browsercms 3.3.2 → 3.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/app/controllers/cms/content_block_controller.rb +2 -2
- data/app/controllers/cms/content_controller.rb +1 -1
- data/app/controllers/cms/section_nodes_controller.rb +6 -1
- data/app/controllers/cms/sections_controller.rb +1 -1
- data/app/helpers/cms/application_helper.rb +1 -1
- data/app/helpers/cms/content_block_helper.rb +27 -0
- data/app/helpers/cms/section_nodes_helper.rb +43 -5
- data/app/models/abstract_file_block.rb +17 -2
- data/app/models/attachment.rb +16 -34
- data/app/models/file_block.rb +0 -12
- data/app/models/image_block.rb +0 -12
- data/app/models/link.rb +4 -21
- data/app/models/page.rb +36 -35
- data/app/models/section.rb +82 -42
- data/app/models/section_node.rb +41 -24
- data/app/views/cms/blocks/index.html.erb +4 -4
- data/app/views/cms/file_blocks/_form.html.erb +1 -1
- data/app/views/cms/image_blocks/_form.html.erb +1 -1
- data/app/views/cms/section_nodes/_link.html.erb +6 -3
- data/app/views/cms/section_nodes/_node.html.erb +11 -2
- data/app/views/cms/section_nodes/_page.html.erb +13 -7
- data/app/views/cms/section_nodes/_section.html.erb +24 -8
- data/app/views/cms/section_nodes/index.html.erb +18 -6
- data/app/views/cms/shared/_pagination.html.erb +4 -4
- data/app/views/portlets/reset_password/render.html.erb +0 -2
- data/browsercms.gemspec +1 -4
- data/db/migrate/20100117144039_browsercms315.rb +94 -0
- data/lib/acts_as_list.rb +1 -1
- data/lib/browsercms.rb +3 -1
- data/lib/cms/addressable.rb +83 -0
- data/lib/cms/behaviors/attaching.rb +42 -24
- data/lib/cms/behaviors/connecting.rb +2 -1
- data/lib/cms/behaviors/publishing.rb +12 -3
- data/lib/cms/behaviors/versioning.rb +43 -24
- data/lib/cms/content_rendering_support.rb +3 -3
- data/lib/cms/error_pages.rb +8 -0
- data/lib/cms/version.rb +2 -2
- data/lib/generators/browser_cms/cms/cms_generator.rb +1 -0
- data/lib/generators/cms/upgrade_module/templates/GPL.txt +1 -1
- data/lib/tasks/data.rake +43 -0
- metadata +27 -8
- data/app/views/cms/section_nodes/_section_node.html.erb +0 -10
data/app/models/section_node.rb
CHANGED
@@ -1,10 +1,33 @@
|
|
1
|
+
require 'ancestry'
|
2
|
+
|
1
3
|
class SectionNode < ActiveRecord::Base
|
2
|
-
|
3
|
-
|
4
|
+
has_ancestry
|
5
|
+
|
6
|
+
# This is the parent section for this node
|
7
|
+
# For backwards compatiblity
|
8
|
+
def parent_section
|
9
|
+
self.parent ? self.parent.node : nil
|
10
|
+
end
|
11
|
+
|
12
|
+
alias :section :parent_section
|
4
13
|
|
5
|
-
|
14
|
+
# For backwards compatiblity
|
15
|
+
def section=(new_section)
|
16
|
+
self.parent = new_section.node
|
17
|
+
end
|
18
|
+
|
19
|
+
# The item this node links to
|
20
|
+
belongs_to :node, :polymorphic => :true, :inverse_of => :section_node
|
21
|
+
|
22
|
+
acts_as_list
|
23
|
+
# For acts_as_list. Specifies that position should be unique within a section.
|
24
|
+
def scope_condition
|
25
|
+
ancestry ? "ancestry = '#{ancestry}'" : 'ancestry IS NULL'
|
26
|
+
end
|
6
27
|
|
7
28
|
scope :of_type, lambda{|types| {:conditions => ["section_nodes.node_type IN (?)", types]}}
|
29
|
+
scope :in_order, :order => "position asc"
|
30
|
+
scope :fetch_nodes, :include => :node
|
8
31
|
|
9
32
|
def visible?
|
10
33
|
return false unless node
|
@@ -27,27 +50,29 @@ class SectionNode < ActiveRecord::Base
|
|
27
50
|
def page?
|
28
51
|
node_type == 'Page'
|
29
52
|
end
|
30
|
-
|
31
|
-
|
53
|
+
|
54
|
+
# @param [Section] section
|
55
|
+
# @param [Integer] position
|
56
|
+
def move_to(section, position)
|
32
57
|
#logger.info "Moving Section Node ##{id} to Section ##{sec.id} Position #{pos}"
|
33
58
|
transaction do
|
34
|
-
if
|
59
|
+
if self.parent != section.node
|
35
60
|
remove_from_list
|
36
|
-
self.
|
61
|
+
self.parent = section.node
|
37
62
|
save
|
38
63
|
end
|
39
64
|
|
40
|
-
if
|
41
|
-
|
65
|
+
if position < 0
|
66
|
+
position = 0
|
42
67
|
else
|
43
68
|
#This helps prevent the position from getting out of whack
|
44
69
|
#If you pass in a really high number for position,
|
45
70
|
#this just corrects it to the right number
|
46
|
-
node_count = SectionNode.count(:conditions => {:
|
47
|
-
|
71
|
+
node_count = SectionNode.count(:conditions => {:ancestry => ancestry})
|
72
|
+
position = node_count if position > node_count
|
48
73
|
end
|
49
74
|
|
50
|
-
insert_at_position(
|
75
|
+
insert_at_position(position)
|
51
76
|
end
|
52
77
|
end
|
53
78
|
|
@@ -77,17 +102,9 @@ class SectionNode < ActiveRecord::Base
|
|
77
102
|
#1.0/0 == Infinity
|
78
103
|
move_to(sec, 1.0/0)
|
79
104
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
ancestors << sn.section
|
85
|
-
if sn.section && !sn.section.root?
|
86
|
-
fn.call(sn.section.node)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
fn.call(self)
|
90
|
-
ancestors.reverse
|
105
|
+
|
106
|
+
|
107
|
+
def ancestry_path
|
108
|
+
path_ids.join "/"
|
91
109
|
end
|
92
|
-
|
93
110
|
end
|
@@ -50,7 +50,6 @@
|
|
50
50
|
<% page_title "Content Library / List #{content_type.display_name_plural}" %>
|
51
51
|
<% @toolbar_title = "List #{content_type.display_name_plural}" %>
|
52
52
|
<%= render :partial => 'cms/blocks/toolbar' %>
|
53
|
-
|
54
53
|
<div class="roundedcorners">
|
55
54
|
<table id="blocks" class="data">
|
56
55
|
<thead>
|
@@ -90,8 +89,9 @@
|
|
90
89
|
col_ct += 1 if content_type.model_class.publishable? %>
|
91
90
|
<% @blocks.each do |b| %>
|
92
91
|
<% block = b.class.versioned? ? b.as_of_draft_version : b %>
|
93
|
-
|
94
|
-
|
92
|
+
|
93
|
+
<%= block_row_tag(block) %>
|
94
|
+
<td class="first"></td>
|
95
95
|
<% content_type.columns_for_index.each_with_index do |column, i| %>
|
96
96
|
<td class="<%= column[:label].gsub(' ', '').underscore %>">
|
97
97
|
<div<%= ' class="dividers"' if (i + 3 < col_ct) %>>
|
@@ -105,7 +105,7 @@
|
|
105
105
|
</td>
|
106
106
|
<% end %>
|
107
107
|
<% if content_type.model_class.respond_to?(:updated_at) %><td class="updated"><div class="dividers"><%= block.updated_at.to_s(:date) %></div></td><% end %>
|
108
|
-
<% if content_type.model_class.connectable? %><td class="used"><div class="dividers"><%= block.connected_pages.
|
108
|
+
<% if content_type.model_class.connectable? %><td class="used"><div class="dividers"><%= block.connected_pages.size %></div></td><% end %>
|
109
109
|
<% if content_type.model_class.publishable? %><td class="block_status"><%= status_icon(block.status) %> <div><%= block.status %></div></td><% end %>
|
110
110
|
<td class="last"></td>
|
111
111
|
</tr>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
root.full_path = root.name
|
4
4
|
@sections = []
|
5
5
|
@sections << root
|
6
|
-
@sections += root.
|
6
|
+
@sections += root.master_section_list
|
7
7
|
@sections.each {|s| s.full_path = "/" + s.full_path unless s == root }
|
8
8
|
@block.attachment_file_path = @block.attachment.file_path if @block.attachment_file_path.blank? && !@block.new_record?
|
9
9
|
%>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
root.full_path = root.name
|
4
4
|
@sections = []
|
5
5
|
@sections << root
|
6
|
-
@sections += root.
|
6
|
+
@sections += root.master_section_list
|
7
7
|
@sections.each {|s| s.full_path = "/" + s.full_path unless s == root }
|
8
8
|
@block.attachment_file_path = @block.attachment.file_path if @block.attachment_file_path.blank? && !@block.new_record?
|
9
9
|
%>
|
@@ -1,11 +1,14 @@
|
|
1
|
-
|
1
|
+
<% first_level = in_first_level?(node)
|
2
|
+
%>
|
3
|
+
<%= sitemap_ul_tag(node) %>
|
2
4
|
<li>
|
3
5
|
<%= render :partial => "node", :locals => {
|
4
6
|
:node => node,
|
5
7
|
:node_type => "link",
|
6
|
-
:icon => action_icon(
|
8
|
+
:icon => action_icon(first_level ? :root_link : :link),
|
7
9
|
:published_status_icon => status_icon(node.status),
|
8
|
-
:published_status_label => node.published? ? "Published" : "Draft"
|
10
|
+
:published_status_label => node.published? ? "Published" : "Draft",
|
11
|
+
:parent => parent
|
9
12
|
} %>
|
10
13
|
</li>
|
11
14
|
</ul>
|
@@ -4,13 +4,22 @@
|
|
4
4
|
published_status_icon = defined?(published_status_icon) ? published_status_icon : nil
|
5
5
|
published_status_label = defined?(published_status_label) ? published_status_label : nil
|
6
6
|
|
7
|
+
editable_class = ""
|
8
|
+
case node_type
|
9
|
+
when "section"
|
10
|
+
editable_class = "non-editable" unless @modifiable_sections.include?(node)
|
11
|
+
else
|
12
|
+
editable_class = "non-editable" unless defined?(parent) && @modifiable_sections.include?(parent)
|
13
|
+
end
|
14
|
+
|
15
|
+
node_type_class = node_type == "section" && node.root? ? 'root' : ''
|
7
16
|
%>
|
8
17
|
<div class="roundedcorners">
|
9
18
|
<table class="section_node <%= node_type %> <%= "movable" if current_user.able_to?(:publish_content) %>" width="100%" cellspacing="0" cellpadding="0">
|
10
19
|
<tr><td colspan="4" class="drop-before"></td></tr>
|
11
20
|
<tr<%= ' class="doubled"' if access_icon && hidden %>>
|
12
|
-
<td id="<%= node_type %>_<%= node.id %>" class="<%=
|
13
|
-
<%=
|
21
|
+
<td id="<%= node_type %>_<%= node.id %>" class="<%= node_type_class %> <%= node_type %> node <%= editable_class %>">
|
22
|
+
<%= icon.html_safe %>
|
14
23
|
<div><%= h(node.name) %></div>
|
15
24
|
</td>
|
16
25
|
<td class="sitemap_hidden divided">
|
@@ -1,14 +1,20 @@
|
|
1
|
-
<%
|
2
|
-
|
1
|
+
<%
|
2
|
+
page = node
|
3
|
+
status_icon = page.archived? ? :archived : page.status
|
4
|
+
first_level = in_first_level?(node)
|
5
|
+
|
6
|
+
%>
|
7
|
+
<%= sitemap_ul_tag(node) %>
|
3
8
|
<li>
|
4
9
|
<%= render :partial => "node", :locals => {
|
5
10
|
:node => node,
|
6
11
|
:node_type => "page",
|
7
|
-
:icon => action_icon(
|
8
|
-
:hidden =>
|
9
|
-
:access_icon => status_icon(
|
10
|
-
:published_status_icon => status_icon(
|
11
|
-
:published_status_label =>
|
12
|
+
:icon => action_icon(first_level ? :root_page : :page),
|
13
|
+
:hidden => page.hidden?,
|
14
|
+
:access_icon => status_icon(access_icon),
|
15
|
+
:published_status_icon => status_icon(status_icon),
|
16
|
+
:published_status_label => status_icon.to_s.titleize,
|
17
|
+
:parent => parent
|
12
18
|
} %>
|
13
19
|
</li>
|
14
20
|
</ul>
|
@@ -1,12 +1,28 @@
|
|
1
|
-
|
1
|
+
<%
|
2
|
+
children = child_hash[key].keys
|
3
|
+
section_node = key
|
4
|
+
access_status = access_status(node, @public_sections)
|
5
|
+
first_level = in_first_level?(node)
|
6
|
+
%>
|
7
|
+
<%= sitemap_ul_tag(node) %>
|
2
8
|
<li>
|
3
9
|
<%= render :partial => "node", :locals => {
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
:node => node,
|
11
|
+
:node_type => "section",
|
12
|
+
:icon => "#{section_icons(section_node, children)} #{action_icon(first_level ? :root_folder : :folder, :class => "folder")}",
|
13
|
+
:hidden => node.hidden?,
|
14
|
+
:access_icon => status_icon(access_status),
|
15
|
+
:parent => parent
|
16
|
+
} %>
|
17
|
+
<% children.each do |child_section_node| %>
|
18
|
+
<%= render :partial => child_section_node.node.partial_for,
|
19
|
+
:locals => {:access_icon => access_status,
|
20
|
+
:node => child_section_node.node,
|
21
|
+
:parent => node,
|
22
|
+
:child_hash => child_hash[key],
|
23
|
+
:key => child_section_node
|
24
|
+
} %>
|
25
|
+
<% end %>
|
26
|
+
|
11
27
|
</li>
|
12
28
|
</ul>
|
@@ -20,12 +20,24 @@
|
|
20
20
|
<ul id="root_<%= @section.id %>" class="root" style="padding-left: 0">
|
21
21
|
<li>
|
22
22
|
<%= render :partial => "node", :locals => {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
:node => @section,
|
24
|
+
:node_type => "section",
|
25
|
+
:icon => action_icon(:home),
|
26
|
+
:display => true
|
27
|
+
} %>
|
28
28
|
</li>
|
29
29
|
</ul>
|
30
|
-
|
30
|
+
<%
|
31
|
+
access_status = access_status(@section, @public_sections)
|
32
|
+
@sitemap[@root_section_node].keys.each do |child_section_node| %>
|
33
|
+
<%= render :partial => child_section_node.node.partial_for,
|
34
|
+
:locals => {:access_icon => access_status,
|
35
|
+
:node => child_section_node.node,
|
36
|
+
:parent => @section,
|
37
|
+
:child_hash => @sitemap[@root_section_node],
|
38
|
+
:key => child_section_node
|
39
|
+
}
|
40
|
+
%>
|
41
|
+
<% end %>
|
31
42
|
</div>
|
43
|
+
|
@@ -8,8 +8,8 @@
|
|
8
8
|
<%= collection.total_entries %>
|
9
9
|
</div>
|
10
10
|
<div class="links">
|
11
|
-
<%= link_to " ", first_page_path, :id => "first_page_link" %>
|
12
|
-
<%= link_to " ", previous_page_path, :id => "previous_page_link" %>
|
11
|
+
<%= link_to " ".html_safe, first_page_path, :id => "first_page_link" %>
|
12
|
+
<%= link_to " ".html_safe, previous_page_path, :id => "previous_page_link" %>
|
13
13
|
<span>
|
14
14
|
<% url = URI.parse(current_page_path) %>
|
15
15
|
<%= form_tag url.path, :method => :get, :class => "current_page" do %>
|
@@ -24,8 +24,8 @@
|
|
24
24
|
</strong>
|
25
25
|
<% end %>
|
26
26
|
</span>
|
27
|
-
<%= link_to " ", next_page_path, :id => "next_page_link" %>
|
28
|
-
<%= link_to " ", last_page_path, :id => "last_page_link" %>
|
27
|
+
<%= link_to " ".html_safe, next_page_path, :id => "next_page_link" %>
|
28
|
+
<%= link_to " ".html_safe, last_page_path, :id => "last_page_link" %>
|
29
29
|
</div>
|
30
30
|
<br clear="all"/>
|
31
31
|
</div>
|
data/browsercms.gemspec
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# This file is now managed directly, rather than generated by Jeweler.
|
2
|
-
#
|
3
1
|
require File.dirname(__FILE__) + "/lib/cms/version.rb"
|
4
2
|
|
5
3
|
Gem::Specification.new do |s|
|
@@ -7,9 +5,7 @@ Gem::Specification.new do |s|
|
|
7
5
|
s.name = %q{browsercms}
|
8
6
|
s.version = Cms::VERSION
|
9
7
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
8
|
s.authors = ["BrowserMedia"]
|
12
|
-
s.date = %q{2011-03-15}
|
13
9
|
s.summary = %q{BrowserCMS is a a general purpose, open source Web Content Management System (CMS), written using Ruby on Rails.}
|
14
10
|
s.description = %q{Web Content Management in Rails.}
|
15
11
|
s.email = %q{github@browsermedia.com}
|
@@ -42,6 +38,7 @@ Gem::Specification.new do |s|
|
|
42
38
|
s.files -= Dir['test/dummy/*']
|
43
39
|
|
44
40
|
s.add_dependency('rails', "~> 3.0.7")
|
41
|
+
s.add_dependency "ancestry", "~> 1.2.4"
|
45
42
|
|
46
43
|
# Required only for bcms-upgrade
|
47
44
|
s.add_dependency('term-ansicolor')
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Browsercms315 < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
generate_ancestry_from_section_id
|
4
|
+
update_latest_version_cache
|
5
|
+
|
6
|
+
INDEXES.each do |index|
|
7
|
+
add_index *index
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
# This migration is not reversible since it removes the original section_id column.
|
13
|
+
end
|
14
|
+
|
15
|
+
# Add some very commonly used indexes to improve the site performance as the # of pages/content grows (i.e. several thousand pages)
|
16
|
+
INDEXES = [
|
17
|
+
[:pages, :deleted],
|
18
|
+
[:pages, :path],
|
19
|
+
[:pages, :version],
|
20
|
+
[:page_versions, :page_id],
|
21
|
+
[:groups, :code],
|
22
|
+
[:groups, :group_type_id],
|
23
|
+
[:group_types, :cms_access],
|
24
|
+
[:group_sections, :section_id],
|
25
|
+
[:group_sections, :group_id],
|
26
|
+
[:users, :expires_at],
|
27
|
+
[:user_group_memberships, :group_id],
|
28
|
+
[:user_group_memberships, :user_id],
|
29
|
+
[:group_permissions, :group_id],
|
30
|
+
[:group_permissions, :permission_id],
|
31
|
+
[:group_permissions, [:group_id, :permission_id]],
|
32
|
+
[:section_nodes, :node_type],
|
33
|
+
[:section_nodes, :ancestry],
|
34
|
+
[:connectors, :page_id],
|
35
|
+
[:connectors, :page_version],
|
36
|
+
[:html_blocks, :deleted],
|
37
|
+
[:html_block_versions, :html_block_id],
|
38
|
+
[:html_block_versions, :version],
|
39
|
+
[:portlet_attributes, :portlet_id],
|
40
|
+
[:portlets, :name],
|
41
|
+
[:sections, :path],
|
42
|
+
[:redirects, :from_path],
|
43
|
+
[:connectors, :connectable_version],
|
44
|
+
[:connectors, :connectable_type],
|
45
|
+
[:content_types, :content_type_group_id],
|
46
|
+
[:content_types, :name],
|
47
|
+
[:file_block_versions, :file_block_id],
|
48
|
+
[:file_block_versions, :version],
|
49
|
+
[:file_blocks, :deleted],
|
50
|
+
[:file_blocks, :type],
|
51
|
+
[:attachment_versions, :attachment_id],
|
52
|
+
[:tasks, :page_id],
|
53
|
+
[:tasks, :completed_at],
|
54
|
+
[:tasks, :assigned_to_id],
|
55
|
+
]
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# v3.1.5 uses Ancestry to manage the parent child relationship between sections and their children.
|
60
|
+
# This converts the data from the old section_id to use the ancestry column.
|
61
|
+
def self.generate_ancestry_from_section_id
|
62
|
+
add_column :section_nodes, :ancestry, :string
|
63
|
+
add_column :section_nodes, :temp_parent_id, :integer
|
64
|
+
|
65
|
+
SectionNode.reset_column_information
|
66
|
+
root_section = Section.root.first
|
67
|
+
SectionNode.create!(:node => root_section) if root_section
|
68
|
+
|
69
|
+
all_nodes_but_root = SectionNode.find(:all, :conditions=>["section_id IS NOT NULL"])
|
70
|
+
all_nodes_but_root.each do |sn|
|
71
|
+
parent_node = SectionNode.find(:first, :conditions => ["node_id = ? and node_type = 'Section'", sn.section_id])
|
72
|
+
sn.temp_parent_id = parent_node.id
|
73
|
+
sn.save!
|
74
|
+
end
|
75
|
+
rename_column :section_nodes, :temp_parent_id, :parent_id # Ancestry works off the 'parent_id' column.
|
76
|
+
|
77
|
+
SectionNode.build_ancestry_from_parent_ids!
|
78
|
+
remove_column :section_nodes, :section_id
|
79
|
+
remove_column :section_nodes, :parent_id
|
80
|
+
SectionNode.reset_column_information
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds a 'latest_version' pointer to pages and links. Greatly reduces the number of queries the sitemap requires to determine if pages are in draft/published mode
|
84
|
+
def self.update_latest_version_cache
|
85
|
+
add_column :pages, :latest_version, :integer
|
86
|
+
add_column :links, :latest_version, :integer
|
87
|
+
Page.all.each do |p|
|
88
|
+
p.update_latest_version
|
89
|
+
end
|
90
|
+
Link.all.each do |link|
|
91
|
+
link.update_latest_version
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/acts_as_list.rb
CHANGED
@@ -7,7 +7,7 @@ module ActsAsList
|
|
7
7
|
# The class that has this specified needs to have a +position+ column defined as an integer on
|
8
8
|
# the mapped database table.
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# To Do list example:
|
11
11
|
#
|
12
12
|
# class TodoList < ActiveRecord::Base
|
13
13
|
# has_many :todo_items, :order => "position"
|