liquid_cms 0.2.0.13 → 0.2.1.0

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