liquid_cms 0.2.0.13 → 0.2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGELOG.rdoc +12 -0
  2. data/app/controllers/cms/assets_controller.rb +32 -10
  3. data/app/controllers/cms/components_controller.rb +3 -3
  4. data/app/controllers/cms/main_controller.rb +2 -0
  5. data/app/controllers/cms/pages_controller.rb +2 -2
  6. data/app/helpers/cms/pages_helper.rb +0 -12
  7. data/app/liquid/cms_paperclip_extension.rb +1 -1
  8. data/app/liquid/drops/cms_asset_drop.rb +15 -0
  9. data/app/liquid/filters/cms_filters.rb +1 -1
  10. data/app/liquid/tags/asset_search_tag.rb +26 -0
  11. data/app/liquid/tags/cms/tag_common.rb +29 -0
  12. data/app/liquid/tags/data_tag.rb +59 -0
  13. data/app/models/cms/asset.rb +109 -2
  14. data/app/models/cms/component.rb +21 -17
  15. data/app/models/cms/page.rb +1 -3
  16. data/app/models/cms/tag.rb +21 -0
  17. data/app/models/cms/taggable.rb +78 -0
  18. data/app/models/cms/tagging.rb +6 -0
  19. data/app/views/cms/assets/_asset.html.erb +2 -3
  20. data/app/views/cms/assets/_form.html.erb +53 -3
  21. data/app/views/cms/assets/_list.html.erb +16 -1
  22. data/app/views/cms/assets/_meta_field.html.erb +15 -0
  23. data/app/views/cms/documentation/_cms_drops.html.erb +18 -0
  24. data/app/views/cms/documentation/_cms_tags.html.erb +13 -0
  25. data/app/views/cms/pages/_page.html.erb +1 -3
  26. data/app/views/cms/shared/_sidebar.html.erb +30 -29
  27. data/generators/liquid_cms/lib/insert_commands.rb +14 -0
  28. data/generators/liquid_cms/liquid_cms_generator.rb +5 -1
  29. data/generators/liquid_cms/templates/config/initializers/cms/liquid_cms.rb +8 -0
  30. data/generators/liquid_cms/templates/config/locales/cms/en.yml +5 -0
  31. data/generators/liquid_cms/templates/migration_rev1.rb +38 -0
  32. data/generators/liquid_cms/templates/public/cms/stylesheets/sidebar.css +25 -7
  33. data/generators/liquid_cms/templates/public/cms/stylesheets/simple_form.css +79 -4
  34. data/generators/liquid_cms/templates/public/cms/stylesheets/styles.css +0 -8
  35. data/generators/liquid_cms/templates/public/cms/stylesheets/themes/dark.css +3 -0
  36. data/lib/liquid_cms/configuration.rb +12 -0
  37. data/lib/liquid_cms/version.rb +1 -1
  38. data/rails/init.rb +0 -1
  39. data/test/functional/assets_controller_test.rb +64 -16
  40. data/test/functional/components_controller_test.rb +90 -1
  41. data/test/functional/main_controller_test.rb +21 -0
  42. data/test/integration/pages_test.rb +124 -0
  43. data/test/integration/pages_test_no_context.rb +57 -0
  44. data/test/rails_app/db/migrate/20110329201435_create_liquid_cms_upgrade_rev1.rb +38 -0
  45. data/test/test_helper.rb +2 -0
  46. data/test/test_helpers/asset_helpers.rb +6 -4
  47. data/test/test_helpers/component_helpers.rb +35 -0
  48. data/test/test_helpers/file_helpers.rb +11 -0
  49. data/test/unit/asset_test.rb +114 -8
  50. data/test/unit/component_test.rb +65 -2
  51. data/test/unit/helpers/cms/common_helper_test.rb +4 -0
  52. metadata +35 -7
  53. data/app/views/cms/assets/destroy.js.rjs +0 -2
  54. data/generators/liquid_cms/templates/config/initializers/cms/vestal_versions.rb +0 -9
  55. data/test/rails_app/config/initializers/cms/vestal_versions.rb +0 -9
@@ -1,43 +1,46 @@
1
1
  require 'zip/zip'
2
2
 
3
3
  class Cms::Component
4
-
5
4
  attr_reader :path
6
5
 
7
6
  def initialize(context, path = nil)
8
7
  @context = context
9
- @path = clean_path(path) if path
8
+ @path = self.class.clean_path(path) if path
10
9
  end
11
10
 
11
+ # base public path for components
12
12
  def self.base_path(context)
13
- File.join('cms', context.object ? File.join('components', context.object.id.to_s) : 'components')
13
+ Pathname.new(File.join('cms', context.object ? File.join('components', context.object.id.to_s) : 'components'))
14
14
  end
15
15
 
16
+ # full component path on the local system
16
17
  def self.full_path(context)
17
18
  Rails.root.join 'public', base_path(context)
18
19
  end
19
20
 
21
+ # the path for just the current component file as it existed in the original zip file
22
+ # returns empty if the path isn't in the main component directory which occurs if the zip contained relative references
23
+ # path: the full path of the component on the file system
20
24
  def self.component_path(context, path)
21
- path.sub(full_path(context).to_s + "/", '')
25
+ path.to_s.include?(full_path(context).to_s) ? path.sub(full_path(context).to_s + "/", '') : ''
22
26
  end
23
27
 
24
28
  def self.files(path)
25
29
  Dir[File.expand_path(path) + "/*"]
26
30
  end
27
31
 
28
- def self.valid_type?(file)
29
- %w(.css .js .png .jpg .jpeg .gif .json .xml .fla .ico).include?(File.extname(file).downcase)
32
+ def self.valid_ext?(file)
33
+ Cms.valid_component_exts.include?(File.extname(file).downcase)
30
34
  end
31
35
 
32
- def expand(file)
36
+ def self.expand(context, file)
33
37
  Zip::ZipFile.open(file) do |zip_file|
34
38
  zip_file.each do |f|
35
- f_path = self.class.full_path(@context).join(f.name)
36
- #if !File.exist?(f_path) && self.class.valid_type?(f_path)
37
- if self.class.valid_type?(f_path)
38
- FileUtils.mkdir_p File.dirname(f_path)
39
- FileUtils.rm_rf(f_path) if File.exist?(f_path)
40
- zip_file.extract(f, f_path)
39
+ f_path = full_path(context).join(f.name)
40
+ if valid_ext?(f_path) && component_path(context, f_path).present?
41
+ FileUtils.mkdir_p f_path.dirname
42
+ FileUtils.rm_rf(f_path.to_s) if f_path.exist?
43
+ zip_file.extract(f, f_path.to_s)
41
44
  end
42
45
  end
43
46
  end
@@ -46,7 +49,7 @@ class Cms::Component
46
49
  def read
47
50
  return '' if @path.blank? || !self.class.editable?(@path)
48
51
 
49
- fname = self.class.full_path(@context).join(@path).to_s
52
+ fname = self.class.full_path(@context).join(@path)
50
53
  if File.exist?(fname)
51
54
  File.open(fname).read
52
55
  else
@@ -57,7 +60,7 @@ class Cms::Component
57
60
  def write(content)
58
61
  return false if content.blank? || @path.blank? || !self.class.editable?(@path)
59
62
 
60
- fname = self.class.full_path(@context).join(@path).to_s
63
+ fname = self.class.full_path(@context).join(@path)
61
64
  File.exist?(fname).tap do |exist|
62
65
  File.open(fname, 'w') do |f|
63
66
  f.puts content
@@ -75,11 +78,12 @@ class Cms::Component
75
78
  end
76
79
 
77
80
  def self.editable?(file)
78
- !(file =~ /\.(js|css|html|xml)$/).blank?
81
+ Cms.editable_component_exts.include?(File.extname(file).downcase)
79
82
  end
80
83
 
81
84
  protected
82
- def clean_path(path)
85
+ # cleans the path to remove relative references, etc. to other areas of the filesystem
86
+ def self.clean_path(path)
83
87
  # don't do anything if the root path is present
84
88
  return nil if path.blank? || path[0] == "/"
85
89
 
@@ -6,8 +6,6 @@ module Cms
6
6
 
7
7
  NAME_REGEX = /^[^\/][a-zA-Z0-9_\-\.]+$/
8
8
 
9
- versioned
10
-
11
9
  belongs_to :layout_page, :class_name => self.to_s
12
10
  has_many :content_pages, :class_name => self.to_s, :foreign_key => 'layout_page_id', :dependent => :nullify, :order => 'name ASC'
13
11
 
@@ -30,7 +28,7 @@ module Cms
30
28
  named_scope :published, :conditions => {:published => true}
31
29
  named_scope :unpublished, :conditions => {:published => false}
32
30
  named_scope :layouts, :conditions => {:is_layout_page => true}
33
- named_scope :ordered, :order => 'name ASC'
31
+ named_scope :ordered, :order => 'is_layout_page DESC, name ASC'
34
32
 
35
33
  def to_s
36
34
  name
@@ -0,0 +1,21 @@
1
+ class Cms::Tag < ActiveRecord::Base
2
+ unloadable
3
+
4
+ set_table_name 'cms_tags'
5
+
6
+ class << self
7
+ def find_or_initialize_with_name_like(name)
8
+ with_name_like(name).first || new(:name => name)
9
+ end
10
+ end
11
+
12
+ has_many :taggings, :dependent => :destroy, :class_name => 'Cms::Tagging'
13
+
14
+ validates_presence_of :name
15
+
16
+ named_scope :with_name_like, lambda { |name| { :conditions => ["name like ?", name] } }
17
+
18
+ def to_s
19
+ name
20
+ end
21
+ end
@@ -0,0 +1,78 @@
1
+ module Cms::Taggable
2
+ class TagList < Array
3
+ def initialize(list)
4
+ list = list.is_a?(Array) ? list : list.split(/[,\W]+/).collect(&:strip).reject(&:blank?).collect(&:downcase)
5
+ super
6
+ end
7
+
8
+ def to_s
9
+ join ', '
10
+ end
11
+ end
12
+
13
+ def self.included(klass)
14
+ klass.extend TaggableMethods::ClassMethods
15
+
16
+ klass.class_eval do
17
+ include TaggableMethods::InstanceMethods
18
+
19
+ has_many :taggings, :as => :taggable, :dependent => :destroy, :class_name => 'Cms::Tagging'
20
+ has_many :tags, :through => :taggings
21
+
22
+ after_save :save_tags
23
+ end
24
+ end
25
+
26
+ module TaggableMethods
27
+ module ClassMethods
28
+ def define_tag_association(assoc)
29
+ source_klass = self.to_s
30
+ Cms::Tag.class_eval do
31
+ has_many assoc, :through => :taggings, :source => :taggable, :source_type => source_klass
32
+ end
33
+
34
+ self.named_scope :tagged_with, lambda{|tag| {:include => :tags, :conditions => ['cms_tags.name like ?', tag.to_s]}}
35
+ self.named_scope :tagged, :joins => "left outer join cms_taggings on cms_taggings.taggable_id = #{table_name}.id", :conditions => 'cms_taggings.id is not null'
36
+ self.named_scope :untagged, :joins => "left outer join cms_taggings on cms_taggings.taggable_id = #{table_name}.id", :conditions => 'cms_taggings.id is null'
37
+ end
38
+ end
39
+
40
+ module InstanceMethods
41
+ def tag_list
42
+ get_tag_list
43
+ end
44
+
45
+ def tag_list=(new_list)
46
+ set_tag_list new_list
47
+ end
48
+
49
+ protected
50
+ def set_tag_list(list)
51
+ @_tag_list = TagList.new(list)
52
+ end
53
+
54
+ def get_tag_list
55
+ set_tag_list(tags.map(&:name)) if @_tag_list.nil?
56
+ @_tag_list
57
+ end
58
+
59
+ def save_tags
60
+ delete_unused_tags
61
+ add_new_tags
62
+
63
+ taggings.each(&:save)
64
+ end
65
+
66
+ def delete_unused_tags
67
+ tags.each { |t| tags.delete(t) unless get_tag_list.include?(t.name) }
68
+ end
69
+
70
+ def add_new_tags
71
+ tag_names = tags.map(&:name)
72
+ get_tag_list.each do |tag_name|
73
+ tags << Cms::Tag.find_or_initialize_with_name_like(tag_name) unless tag_names.include?(tag_name)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,6 @@
1
+ class Cms::Tagging < ActiveRecord::Base
2
+ set_table_name 'cms_taggings'
3
+
4
+ belongs_to :tag, :class_name => 'Cms::Tag'
5
+ belongs_to :taggable, :polymorphic => true
6
+ end
@@ -1,8 +1,7 @@
1
1
  <% content_tag_for :li, asset, :class => cms_row_class do %>
2
2
  <%= file_type_icon asset.asset_file_name %>
3
- <%= link_to_remote cms_icon('delete.png', :title => 'Delete'), :url => cms_asset_path(asset), :indicator => dom_id(asset, 'progress'), :method => :delete, :confirm => "Are you sure you want to delete the \"#{asset}\" asset?" %>
4
- <%= link_to truncate(asset.asset_file_name, :length => 22), cms_asset_path(asset), :title => asset.asset_file_name %>
5
- <%= indicator dom_id(asset, 'progress') %>
3
+ <%= link_to cms_icon('delete.png', :title => 'Delete'), cms_asset_path(asset), :method => :delete, :confirm => "Are you sure you want to delete the \"#{asset}\" asset?" %>
4
+ <%= link_to truncate(asset.asset_file_name, :length => 22), edit_cms_asset_path(asset), :title => asset.asset_file_name %>
6
5
 
7
6
  <span class="asset_size"><%= number_to_human_size asset.asset_file_size %></span>
8
7
 
@@ -1,4 +1,19 @@
1
1
  <% simple_form_for @asset, :html => {:multipart => true} do |f| %>
2
+ <% unless f.object.new_record? %>
3
+ <div class="details">
4
+ <p><span class="label">Original</span> <%= link_to @asset.asset_file_name, @asset.asset.url %></p>
5
+ <p><span class="label">Filesize</span> <%= number_to_human_size(@asset.asset_file_size) %></p>
6
+ <p><span class="label">Last Updated</span> <%= @asset.asset_updated_at.to_formatted_s(:long) %></p>
7
+ </div>
8
+ <% end %>
9
+
10
+ <% if f.object.image? %>
11
+ <div class="preview">
12
+ <span class="label">Preview</span>
13
+ <%= image_tag @asset.asset.url(:large) %>
14
+ </div>
15
+ <% end %>
16
+
2
17
  <%= f.input :asset, :as => :file %>
3
18
 
4
19
  <% if f.object.editable? %>
@@ -7,12 +22,47 @@
7
22
  </p>
8
23
 
9
24
  <div class="text required">
10
- <%= label_tag :file_content, 'Content', :class => 'text required' %> <%= text_area_tag :file_content, f.object.read, :rows => 40, :class => 'text required' %>
11
- <span class="hint"><%= t('simple_form.hints.cms_asset.file_content') %></span>
25
+ <%= f.input :file_content, :as => :text, :input_html => {:rows => 40, :cols => nil} %>
12
26
  </div>
13
27
 
14
- <%= codemirror_edit Cms::Editable::content_type(@asset.asset_file_name), 'form.simple_form', 'file_content' %>
28
+ <%= codemirror_edit Cms::Editable::content_type(@asset.asset_file_name), 'form.simple_form', 'cms_asset_file_content' %>
29
+ <% end %>
30
+
31
+ <div class="dimensions">
32
+ <%= f.label :custom_size, :required => false %>
33
+ <%= f.input :custom_width, :label => false, :required => false, :input_html => {:size => 4} %> x
34
+ <%= f.input :custom_height, :label => false, :required => false, :input_html => {:size => 4} %>
35
+ <span class="hint"><%= t('simple_form.hints.cms_asset.dimensions') %></span>
36
+ </div>
37
+
38
+ <%= f.input :tag_list, :as => :string, :required => false %>
39
+
40
+ <% field_set_tag 'Meta Data' do %>
41
+ <ul id="meta_fields">
42
+ <% f.object.meta.each_with_index do |meta,idx| %>
43
+ <%= render 'meta_field', :f => f, :obj => meta, :idx => idx %>
44
+ <% end %>
45
+ </ul>
46
+ <%= cms_icon 'table_add.png' %> <%= link_to 'Add meta data', nil, :id => 'add_meta', :title => 'Add new meta data' %>
15
47
  <% end %>
16
48
 
17
49
  <%= f.commit_button_or_cancel %>
50
+
51
+ <% javascript_tag do %>
52
+ function remove_element(evt) {
53
+ this.up('li').remove();
54
+ evt.stop();
55
+ }
56
+
57
+ $('add_meta').observe('click', function(evt) {
58
+ var new_field_id = "new_" + new Date().getTime();
59
+ $('meta_fields').insert({
60
+ bottom:
61
+ "<%= escape_javascript(render('meta_field', :f => f, :obj => nil)) %>".replace(/new_\d+/g, new_field_id)
62
+ }).select('.remove_meta').last().observe('click', remove_element);
63
+ evt.stop();
64
+ });
65
+
66
+ $$('.remove_meta').invoke('observe', 'click', remove_element);
67
+ <% end %>
18
68
  <% end %>
@@ -11,7 +11,22 @@
11
11
  <% end %>
12
12
 
13
13
  <ul>
14
- <%= render :partial => 'cms/assets/asset', :collection => @cms_assets %>
14
+ <% @context_asset_tags.each do |tag| %>
15
+ <li class="group tagged">
16
+ <h4><%= tag.to_s %> <%= link_to cms_icon('picture_add.png', :title => 'Add a new asset with this tag'), new_cms_asset_path(:tag => tag.to_s) %></h4>
17
+ <ul>
18
+ <%= render :partial => 'cms/assets/asset', :collection => @context.assets.tagged_with(tag).ordered %>
19
+ </ul>
20
+ </li>
21
+ <% end %>
22
+ <li class="group untagged">
23
+ <% unless @context_asset_tags.blank? %>
24
+ <h4>Untagged</h4>
25
+ <% end %>
26
+ <ul>
27
+ <%= render :partial => 'cms/assets/asset', :collection => @context.assets.untagged.ordered %>
28
+ </ul>
29
+ </li>
15
30
  </ul>
16
31
  <% end %>
17
32
  </div>
@@ -0,0 +1,15 @@
1
+ <% f.simple_fields_for :meta, obj ? obj : nil, :index => obj ? idx : 'new_0' do |m| %>
2
+ <li>
3
+ <div class="field">
4
+ <%= m.input :name, :placeholder => 'field name', :size => 40 %>
5
+ <span class="hint"><%= t('simple_form.hints.cms_asset.meta.name') %></span>
6
+ </div>
7
+ <div class="field">
8
+ <%= m.input :value, :as => :text, :required => false, :input_html => {:rows => 2, :cols => 60, :placeholder => 'field value'} %>
9
+ </div>
10
+
11
+ <span class="delete">
12
+ <%= link_to cms_icon('table_delete.png'), nil, :class => 'remove_meta', :title => 'Delete this meta data' %>
13
+ </span>
14
+ </li>
15
+ <% end %>
@@ -11,3 +11,21 @@
11
11
  {{ image.large.width }}
12
12
  {{ image.large.height }}
13
13
  </pre>
14
+
15
+ <a name="asset_drop"></a>
16
+ <h3>Asset</h3>
17
+ <ul>
18
+ <li><span class="attribute">meta</span> - Meta fields can be accessed from the meta attribute. Meta data is associated with an asset when creating or editing them.</li>
19
+ <li>
20
+ <span class="attribute">image</span> - Gives you access to the image fields if the asset an image. See the <a href="#image_drop">paperclip objects</a> drop for available fields.</a><br/>
21
+ The image attribute only contains the <em>'original'</em> size in addition to a <em>'custom'</em> size if custom dimensions were specified for the image.
22
+ </li>
23
+ </ul>
24
+
25
+ <pre>
26
+ {{ asset.meta.field_name }}
27
+ {{ asset.meta.location }}
28
+
29
+ {{ asset.image.custom.url }}
30
+ {{ asset.image.original.url }}
31
+ </pre>
@@ -7,3 +7,16 @@
7
7
  {% include 'test' %}
8
8
  &lt;/div&gt;
9
9
  </pre>
10
+
11
+ <h3><span class="function">asset_data</span> - Retrieves assets as a collection of asset drops.</h3>
12
+ <ul>
13
+ <li><span class="param required">tag</span> - The tag string used to search for the assets. Tags are associated with the asset when creating or editing them.</li>
14
+ <li><span class="param">random</span> - Return assets in a random order or most recent first. (true/false). false by default.</li>
15
+ <li><span class="param">limit</span> - The maximum number of records to return. Returns all by default.</li>
16
+ <li><span class="param">as</span> - Specify the name of the variable that the asset data will be saved in. The name is 'assets' by default.</li>
17
+ </ul>
18
+
19
+ <pre>
20
+ {% asset_data tag:'gallery' %}
21
+ {% asset_data tag:'customer' random:true %}
22
+ </pre>
@@ -3,15 +3,13 @@
3
3
  <% if page.published? %>
4
4
  <%= cms_icon 'accept.png' %>
5
5
  <% else %>
6
- <%= delete_page_link page %>
6
+ <%= link_to cms_icon('delete.png', :title => 'Delete'), cms_page_path(page), :method => :delete, :confirm => "Are you sure you want to delete the \"#{page}\" page?" %>
7
7
  <% end %>
8
8
  <%= link_to truncate(page.to_s, :length => 24), edit_cms_page_path(page), :title => "Edit '#{page}'" %>
9
9
 
10
10
  <%= cms_icon 'house.png', :title => 'Root/Home Page' if page.root? %>
11
11
  <%= link_to cms_icon('magnifier.png', :title => 'View'), page.url, :class => 'external' if page.published? %>
12
12
 
13
- <%= indicator dom_id(page, 'progress') %>
14
-
15
13
  <% unless page.content_pages.empty? %>
16
14
  <ul>
17
15
  <%= render :partial => 'cms/pages/page', :collection => page.content_pages %>
@@ -1,35 +1,36 @@
1
- <ul id="cms_menus" class="tabs clearfix">
2
- <li><%= link_to t('pages.actions.index.title'), '#cms_pages' %></li>
3
- <li><%= link_to t('assets.actions.index.title'), '#cms_assets' %></li>
4
- <li><%= link_to t('components.actions.index.title'), '#cms_components' %></li>
5
- </ul>
1
+ <div id="sidebar_container">
2
+ <ul id="cms_menus" class="tabs clearfix">
3
+ <li><%= link_to t('pages.actions.index.title'), '#cms_pages' %></li>
4
+ <li><%= link_to t('assets.actions.index.title'), '#cms_assets' %></li>
5
+ <li><%= link_to t('components.actions.index.title'), '#cms_components' %></li>
6
+ </ul>
6
7
 
7
- <div id="tab_container">
8
- <div id="cms_pages">
9
- <h2><%= t 'pages.actions.index.title' %></h2>
10
- <%= render 'cms/pages/list' %>
11
- </div>
8
+ <div id="tab_container">
9
+ <div id="cms_pages">
10
+ <h2><%= t 'pages.actions.index.title' %></h2>
11
+ <%= render 'cms/pages/list' %>
12
+ </div>
12
13
 
13
- <div id="cms_assets">
14
- <h2><%= t 'assets.actions.index.title' %></h2>
15
- <%= render 'cms/assets/list' %>
16
- </div>
14
+ <div id="cms_assets">
15
+ <h2><%= t 'assets.actions.index.title' %></h2>
16
+ <%= render 'cms/assets/list' %>
17
+ </div>
17
18
 
18
- <div id="cms_components">
19
- <h2><%= t 'components.actions.index.title' %></h2>
20
- <%= render 'cms/components/list' %>
19
+ <div id="cms_components">
20
+ <h2><%= t 'components.actions.index.title' %></h2>
21
+ <%= render 'cms/components/list' %>
22
+ </div>
21
23
  </div>
22
- </div>
23
24
 
24
- <% javascript_tag do %>
25
- new Control.Tabs('cms_menus', {
26
- defaultTab: jar.get('active_tab') || 'first',
27
- afterChange: function(new_container) {
28
- // save the active tab
29
- jar.put('active_tab', new_container.getAttribute('id'));
30
- }
31
- });
32
- <% end %>
33
-
34
- <p class="documentation"><%= cms_icon 'page.png' %> <%= link_to 'Documentation', cms_documentation_path %></p>
25
+ <% javascript_tag do %>
26
+ new Control.Tabs('cms_menus', {
27
+ defaultTab: jar.get('active_tab') || 'first',
28
+ afterChange: function(new_container) {
29
+ // save the active tab
30
+ jar.put('active_tab', new_container.getAttribute('id'));
31
+ }
32
+ });
33
+ <% end %>
35
34
 
35
+ <p class="documentation"><%= cms_icon 'page.png' %> <%= link_to 'Documentation', cms_documentation_path %></p>
36
+ </div>