browsercms 3.3.2 → 3.3.3

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 (42) hide show
  1. data/app/controllers/cms/content_block_controller.rb +2 -2
  2. data/app/controllers/cms/content_controller.rb +1 -1
  3. data/app/controllers/cms/section_nodes_controller.rb +6 -1
  4. data/app/controllers/cms/sections_controller.rb +1 -1
  5. data/app/helpers/cms/application_helper.rb +1 -1
  6. data/app/helpers/cms/content_block_helper.rb +27 -0
  7. data/app/helpers/cms/section_nodes_helper.rb +43 -5
  8. data/app/models/abstract_file_block.rb +17 -2
  9. data/app/models/attachment.rb +16 -34
  10. data/app/models/file_block.rb +0 -12
  11. data/app/models/image_block.rb +0 -12
  12. data/app/models/link.rb +4 -21
  13. data/app/models/page.rb +36 -35
  14. data/app/models/section.rb +82 -42
  15. data/app/models/section_node.rb +41 -24
  16. data/app/views/cms/blocks/index.html.erb +4 -4
  17. data/app/views/cms/file_blocks/_form.html.erb +1 -1
  18. data/app/views/cms/image_blocks/_form.html.erb +1 -1
  19. data/app/views/cms/section_nodes/_link.html.erb +6 -3
  20. data/app/views/cms/section_nodes/_node.html.erb +11 -2
  21. data/app/views/cms/section_nodes/_page.html.erb +13 -7
  22. data/app/views/cms/section_nodes/_section.html.erb +24 -8
  23. data/app/views/cms/section_nodes/index.html.erb +18 -6
  24. data/app/views/cms/shared/_pagination.html.erb +4 -4
  25. data/app/views/portlets/reset_password/render.html.erb +0 -2
  26. data/browsercms.gemspec +1 -4
  27. data/db/migrate/20100117144039_browsercms315.rb +94 -0
  28. data/lib/acts_as_list.rb +1 -1
  29. data/lib/browsercms.rb +3 -1
  30. data/lib/cms/addressable.rb +83 -0
  31. data/lib/cms/behaviors/attaching.rb +42 -24
  32. data/lib/cms/behaviors/connecting.rb +2 -1
  33. data/lib/cms/behaviors/publishing.rb +12 -3
  34. data/lib/cms/behaviors/versioning.rb +43 -24
  35. data/lib/cms/content_rendering_support.rb +3 -3
  36. data/lib/cms/error_pages.rb +8 -0
  37. data/lib/cms/version.rb +2 -2
  38. data/lib/generators/browser_cms/cms/cms_generator.rb +1 -0
  39. data/lib/generators/cms/upgrade_module/templates/GPL.txt +1 -1
  40. data/lib/tasks/data.rake +43 -0
  41. metadata +27 -8
  42. data/app/views/cms/section_nodes/_section_node.html.erb +0 -10
@@ -121,8 +121,8 @@ class Cms::ContentBlockController < Cms::BaseController
121
121
  def load_blocks
122
122
  options = {}
123
123
  if params[:section_id] && params[:section_id] != 'all'
124
- options[:include] = { :attachment => { :section_node => :section }}
125
- options[:conditions] = ["sections.id = ?", params[:section_id]]
124
+ options[:include] = { :attachment => :section_node }
125
+ options[:conditions] = ["section_nodes.ancestry = ?", Section.find(params[:section_id]).ancestry_path]
126
126
  end
127
127
  options[:page] = params[:page]
128
128
  options[:order] = model_class.default_order if model_class.respond_to?(:default_order)
@@ -90,7 +90,7 @@ class Cms::ContentController < Cms::ApplicationController
90
90
 
91
91
  def try_to_redirect
92
92
  if redirect = Redirect.find_by_from_path(@path)
93
- redirect_to redirect.to_path
93
+ redirect_to redirect.to_path, :status=>:moved_permanently
94
94
  end
95
95
  end
96
96
 
@@ -3,7 +3,12 @@ class Cms::SectionNodesController < Cms::BaseController
3
3
 
4
4
  def index
5
5
  @toolbar_tab = :sitemap
6
- @section = Section.root.first
6
+ @modifiable_sections = current_user.modifiable_sections
7
+ @public_sections = Group.guest.sections.all # Load once here so that every section doesn't need to.
8
+
9
+ @sitemap = Section.sitemap
10
+ @root_section_node = @sitemap.keys.first
11
+ @section = @root_section_node.node
7
12
  end
8
13
  def move_before
9
14
  move(:before)
@@ -16,7 +16,7 @@ class Cms::SectionsController < Cms::BaseController
16
16
  end
17
17
 
18
18
  def new
19
- @section = @parent.sections.build
19
+ @section = @parent.build_section
20
20
  @section.groups = @parent.groups
21
21
  end
22
22
 
@@ -23,7 +23,7 @@ module Cms
23
23
  def searchable_sections(selected = nil)
24
24
  root = Section.root.first
25
25
  options = [['All sections', 'all'], [root.name, root.id]]
26
- root.all_children_with_name.each { |s| options << [s.full_path, s.id] }
26
+ root.master_section_list.each { |s| options << [s.full_path, s.id] }
27
27
  options_for_select(options, selected.to_i)
28
28
  end
29
29
 
@@ -0,0 +1,27 @@
1
+ module Cms
2
+ module ContentBlockHelper
3
+
4
+
5
+ # Prints the <tr> for each block. Adds classes based on:
6
+ # * Name/id of the block
7
+ # * If a block is published/draft
8
+ # * If the user can edit/publish it
9
+ def block_row_tag(block)
10
+ cname = class_name_for(block)
11
+ can_modify = current_user.able_to_modify?(block)
12
+
13
+ options = {
14
+ :id => "#{cname}_#{block.id}",
15
+ :class => cname
16
+ }
17
+ options[:class] += block.class.publishable? && !block.published? ? ' draft' : ' published'
18
+ options[:class] += ' non-editable' unless can_modify && current_user.able_to?(:edit_content)
19
+ options[:class] += ' non-publishable' unless can_modify && current_user.able_to?(:publish_content)
20
+ tag "tr", options, true
21
+ end
22
+
23
+ def class_name_for(block)
24
+ block.class.name.underscore
25
+ end
26
+ end
27
+ end
@@ -1,13 +1,51 @@
1
1
  module Cms
2
2
  module SectionNodesHelper
3
- def section_icons(node)
4
-
5
- if (node.root? || node.parent.root? || node.parent.parent.root?)
6
- node.child_nodes.empty? ? image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle large") : image_tag("cms/sitemap/gray_expand.png", :class => "folder_toggle large")
3
+
4
+ def access_status(section_node, public_sections)
5
+ access_icon = :unlocked
6
+ unless public_sections.include?(section_node)
7
+ access_icon = :locked
8
+ end
9
+ access_icon
10
+ end
11
+
12
+ def section_icons(section_node, children=[])
13
+ folder_style = ""
14
+ expander_image = "expand.png"
15
+ if top_level_section?(section_node)
16
+ folder_style = " large"
17
+ expander_image = "gray_expand.png"
18
+ end
19
+ if children.empty?
20
+ image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle#{folder_style}")
7
21
  else
8
- node.child_nodes.empty? ? image_tag("cms/sitemap/no_contents.png", :class => "no_folder_toggle") : image_tag("cms/sitemap/expand.png", :class => "folder_toggle")
22
+ image_tag("cms/sitemap/#{expander_image}", :class => "folder_toggle#{folder_style}")
9
23
  end
10
24
  end
11
25
 
26
+ # Renders the ul for a given node (Page/Section/Link/etc)
27
+ # Default look:
28
+ # - First level pages/sections use 'big' icons
29
+ # - All non-first level items should be hidden.
30
+ def sitemap_ul_tag(node)
31
+ opts = {
32
+ :id => "section_node_#{node.section_node.id}",
33
+ :class => "section_node"
34
+ }
35
+ opts[:class] += " rootlet" if in_first_level?(node)
36
+ opts[:style] = "display: none" unless in_first_level?(node)
37
+ tag("ul", opts, true)
38
+ end
39
+
40
+ def in_first_level?(node)
41
+ node.section_node.depth == 1
42
+ end
43
+
44
+ private
45
+
46
+ def top_level_section?(node)
47
+ node.depth <= 2
48
+ end
49
+
12
50
  end
13
51
  end
@@ -4,8 +4,11 @@ class AbstractFileBlock < ActiveRecord::Base
4
4
 
5
5
  validates_presence_of :name
6
6
 
7
- scope :by_section, lambda { |section| { :include => {:attachment => :section_node }, :conditions => ["section_nodes.section_id = ?", section.id] } }
8
-
7
+ scope :by_section, lambda { |section| {
8
+ :include => {:attachment => :section_node },
9
+ :conditions => ["section_nodes.ancestry = ?", section.node.ancestry_path] }
10
+ }
11
+
9
12
  def path
10
13
  attachment_file_path
11
14
  end
@@ -14,4 +17,16 @@ class AbstractFileBlock < ActiveRecord::Base
14
17
  true
15
18
  end
16
19
 
20
+ def set_attachment_path
21
+ if @attachment_file_path && @attachment_file_path != attachment.file_path
22
+ attachment.file_path = @attachment_file_path
23
+ end
24
+ end
25
+
26
+ def set_attachment_section
27
+ if @attachment_section_id && @attachment_section_id != attachment.section
28
+ attachment.section_id = @attachment_section_id
29
+ end
30
+ end
31
+
17
32
  end
@@ -28,7 +28,6 @@ class Attachment < ActiveRecord::Base
28
28
  before_validation :extract_file_type_from_temp_file
29
29
  before_validation :extract_file_size_from_temp_file
30
30
  before_validation :set_file_location
31
- before_save :process_section
32
31
 
33
32
  after_save :write_temp_file_to_storage_location
34
33
  after_save :clear_ivars
@@ -36,41 +35,21 @@ class Attachment < ActiveRecord::Base
36
35
 
37
36
  #----- Associations ----------------------------------------------------------
38
37
 
38
+ include Addressable
39
+ include Addressable::DeprecatedPageAccessors
39
40
  has_one :section_node, :as => :node
41
+ alias :node :section_node
40
42
 
41
43
  #----- Validations -----------------------------------------------------------
42
44
 
43
45
  validates_presence_of :temp_file, :message => "You must upload a file", :on => :create
44
46
  validates_presence_of :file_path
45
47
  validates_uniqueness_of :file_path
46
- validates_presence_of :section_id
47
-
48
- #----- Virtual Attributes ----------------------------------------------------
49
-
50
- def section_id
51
- @section_id ||= section_node ? section_node.section_id : nil
52
- end
53
-
54
- def section_id=(section_id)
55
- if @section_id != section_id
56
- dirty!
57
- @section_id = section_id
58
- end
59
- end
60
-
61
- def section
62
- @section ||= section_node ? section_node.section : nil
63
- end
64
48
 
65
49
  def section=(section)
66
- logger.debug {"Attachment#section=(#{section})"}
67
- if @section != section
68
- dirty!
69
- @section_id = section ? section.id : nil
70
- @section = section
71
- end
50
+ dirty! if self.section != section
51
+ super(section)
72
52
  end
73
-
74
53
  #----- Callbacks Methods -----------------------------------------------------
75
54
 
76
55
  def make_dirty_if_temp_file
@@ -117,14 +96,17 @@ class Attachment < ActiveRecord::Base
117
96
  end
118
97
  end
119
98
 
120
- def process_section
121
- #logger.info "processing section, section_id => #{section_id}, section_node => #{section_node.inspect}"
122
- if section_node && !section_node.new_record? && section_node.section_id != section_id
123
- section_node.move_to_end(Section.find(section_id))
124
- else
125
- build_section_node(:node => self, :section_id => section_id)
126
- end
127
- end
99
+ #def process_section
100
+ # if section_node
101
+ # section_node.move_to_end(parent)
102
+ # #end
103
+ # #logger.info "processing section, section_id => #{section_id}, section_node => #{section_node.inspect}"
104
+ # #if section_node && !section_node.new_record? && section_node.section_id != section_id
105
+ # # section_node.move_to_end(Section.find(section_id))
106
+ # else
107
+ # build_section_node(:node => self, :parent => parent)
108
+ # end
109
+ #end
128
110
 
129
111
  def write_temp_file_to_storage_location
130
112
  unless temp_file.blank?
@@ -1,18 +1,6 @@
1
1
  class FileBlock < AbstractFileBlock
2
2
 
3
3
  acts_as_content_block :belongs_to_attachment => true, :taggable => true
4
-
5
- def set_attachment_file_path
6
- if @attachment_file_path && @attachment_file_path != attachment.file_path
7
- attachment.file_path = @attachment_file_path
8
- end
9
- end
10
-
11
- def set_attachment_section
12
- if @attachment_section_id && @attachment_section_id != attachment.section_id
13
- attachment.section_id = @attachment_section_id
14
- end
15
- end
16
4
 
17
5
  def self.display_name
18
6
  "File"
@@ -3,18 +3,6 @@ class ImageBlock < AbstractFileBlock
3
3
  acts_as_content_block :versioned => { :version_foreign_key => :file_block_id },
4
4
  :belongs_to_attachment => true, :taggable => true
5
5
 
6
- def set_attachment_file_path
7
- if @attachment_file_path && @attachment_file_path != attachment.file_path
8
- attachment.file_path = @attachment_file_path
9
- end
10
- end
11
-
12
- def set_attachment_section
13
- if @attachment_section_id && @attachment_section_id != attachment.section_id
14
- attachment.section_id = @attachment_section_id
15
- end
16
- end
17
-
18
6
  def self.display_name
19
7
  "Image"
20
8
  end
data/app/models/link.rb CHANGED
@@ -3,29 +3,12 @@ class Link < ActiveRecord::Base
3
3
 
4
4
  scope :named, lambda{|name| {:conditions => ['links.name = ?', name]}}
5
5
 
6
- has_one :section_node, :as => :node, :dependent => :destroy
7
-
6
+ has_one :section_node, :as => :node, :dependent => :destroy, :inverse_of => :node
7
+
8
8
  validates_presence_of :name
9
9
 
10
- def section_id
11
- section ? section.id : nil
12
- end
13
-
14
- def section
15
- section_node ? section_node.section : nil
16
- end
17
-
18
- def section_id=(sec_id)
19
- self.section = Section.find(sec_id)
20
- end
21
-
22
- def section=(sec)
23
- if section_node
24
- section_node.move_to_end(sec)
25
- else
26
- build_section_node(:node => self, :section => sec)
27
- end
28
- end
10
+ include Addressable
11
+ include Addressable::DeprecatedPageAccessors
29
12
 
30
13
  #needed by menu_helper
31
14
  def path
data/app/models/page.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  class Page < ActiveRecord::Base
2
-
2
+
3
+ def actual_path
4
+ path
5
+ end
6
+
3
7
  is_archivable
4
8
  flush_cache_on_change
5
9
  is_hideable
@@ -57,8 +61,12 @@ class Page < ActiveRecord::Base
57
61
  end
58
62
  }
59
63
 
60
- has_one :section_node, :as => :node, :dependent => :destroy
61
-
64
+ has_one :section_node, :as => :node, :dependent => :destroy, :inverse_of => :node
65
+
66
+
67
+ include Addressable
68
+ include Addressable::DeprecatedPageAccessors
69
+
62
70
  has_many :tasks
63
71
 
64
72
  before_validation :append_leading_slash_to_path, :remove_trailing_slash_from_path
@@ -123,7 +131,7 @@ class Page < ActiveRecord::Base
123
131
  :page_version => options[:to_version_number],
124
132
  :connectable => connectable,
125
133
  :connectable_version => version,
126
- :container => c.container,
134
+ :container => c.container,
127
135
  :position => c.position
128
136
  )
129
137
  logger.debug {"Built new connector #{new_connector}."}
@@ -200,26 +208,6 @@ class Page < ActiveRecord::Base
200
208
  "?"
201
209
  end
202
210
 
203
- def section_id
204
- section ? section.id : nil
205
- end
206
-
207
- def section
208
- section_node ? section_node.section : nil
209
- end
210
-
211
- def section_id=(sec_id)
212
- self.section = Section.find(sec_id)
213
- end
214
-
215
- def section=(sec)
216
- if section_node
217
- section_node.move_to_end(sec)
218
- else
219
- build_section_node(:node => self, :section => sec)
220
- end
221
- end
222
-
223
211
  def public?
224
212
  section ? section.public? : false
225
213
  end
@@ -261,16 +249,25 @@ class Page < ActiveRecord::Base
261
249
  template_file_name && PageTemplate.display_name(template_file_name)
262
250
  end
263
251
 
264
- def ancestors
265
- section_node.ancestors
266
- end
267
-
252
+ # Determines if a page is a descendant of a given Section.
253
+ #
254
+ # @param [String | Section] section_or_section_name
268
255
  def in_section?(section_or_section_name)
269
- sec = section_or_section_name.is_a?(String) ?
270
- Section.first(:conditions => {:name => section_or_section_name}) :
271
- section_or_section_name
272
- fn = lambda{|s| s ? (s == sec || fn.call(s.parent)) : false}
273
- fn.call(section)
256
+ found = false
257
+ ancestors.each do |a|
258
+ if section_or_section_name.is_a?(String)
259
+ if a.name == section_or_section_name
260
+ found = true
261
+ break
262
+ end
263
+ else
264
+ if a == section_or_section_name
265
+ found = true
266
+ break
267
+ end
268
+ end
269
+ end
270
+ found
274
271
  end
275
272
 
276
273
  #Returns true if the block attached to each connector in the given container are published
@@ -294,12 +291,16 @@ class Page < ActiveRecord::Base
294
291
  (a[1..a.size].map{|a| a.name} + [name]).join(" / ")
295
292
  end
296
293
 
297
- # This will return the "top level section" for a page, which is the section directly
294
+ # This will return the "top level section" for this page, which is the section directly
298
295
  # below the root (a.k.a My Site) that this page is in. If this page is in root,
299
296
  # then this will return root.
297
+ #
298
+ # @return [Section] The first non-root ancestor if available, root otherwise.
300
299
  def top_level_section
300
+ # Cache the results of this since many projects will call it repeatly on current_page in menus.
301
+ return @top_level_section if @top_level_section
301
302
  a = ancestors
302
- (a.size > 0 && ancestors[1]) ? ancestors[1] : Section.root.first
303
+ @top_level_section = (a.size > 0 && a[1]) ? a[1] : Section.root.first
303
304
  end
304
305
 
305
306
  def current_task
@@ -3,14 +3,15 @@ class Section < ActiveRecord::Base
3
3
  flush_cache_on_change
4
4
 
5
5
  #The node that links this section to its parent
6
- has_one :node, :class_name => "SectionNode", :as => :node, :dependent => :destroy
6
+ has_one :section_node, :class_name => "SectionNode", :as => :node, :inverse_of => :node
7
7
 
8
- #The nodes that link this section to its children
9
- has_many :child_nodes, :class_name => "SectionNode"
10
- has_many :child_sections, :class_name => "SectionNode", :conditions => ["node_type = ?", "Section"], :order => 'section_nodes.position'
8
+ include Addressable
9
+ include Addressable::NodeAccessors
11
10
 
12
- has_many :pages, :through => :child_nodes, :source => :node, :source_type => 'Page', :order => 'section_nodes.position'
13
- has_many :sections, :through => :child_nodes, :source => :node, :source_type => 'Section', :order => 'section_nodes.position'
11
+ # Cannot use dependent => :destroy to do this. Ancestry's callbacks trigger before the before_destroy callback.
12
+ # So sections would always get deleted since deletable? would return true
13
+ after_destroy :destroy_node
14
+ before_destroy :deletable?
14
15
 
15
16
  has_many :group_sections
16
17
  has_many :groups, :through => :group_sections
@@ -25,55 +26,81 @@ class Section < ActiveRecord::Base
25
26
  scope :with_path, lambda{|path| {:conditions => ['sections.path = ?', path]}}
26
27
 
27
28
  validates_presence_of :name, :path
28
- #validates_presence_of :parent_id, :if => Proc.new {root.count > 0}, :message => "section is required"
29
29
 
30
30
  # Disabling '/' in section name for interoperability with FCKEditor file browser
31
31
  validates_format_of :name, :with => /\A[^\/]*\Z/, :message => "cannot contain '/'"
32
32
 
33
33
  validate :path_not_reserved
34
34
 
35
- before_destroy :deletable?
36
-
37
35
  attr_accessor :full_path
38
36
 
39
- def visible_child_nodes(options={})
40
- children = child_nodes.of_type(["Section", "Page", "Link"]).all(:order => 'section_nodes.position')
41
- visible_children = children.select{|sn| sn.visible?}
42
- options[:limit] ? visible_children[0...options[:limit]] : visible_children
37
+ delegate :ancestry_path, :to => :node
38
+
39
+ def ancestry
40
+ self.node.ancestry
43
41
  end
44
42
 
45
- def all_children_with_name
46
- child_sections.map do |s|
47
- if s.node
48
- s.node.full_path = root? ? s.node.name : "#{name} / #{s.node.name}"
49
- [s.node] << s.node.all_children_with_name
50
- end
51
- end.flatten.compact
43
+ before_validation :ensure_section_node_exists
44
+
45
+ def ensure_section_node_exists
46
+ unless node
47
+ self.node = build_section_node
48
+ end
52
49
  end
53
50
 
54
- def parent_id
55
- parent ? parent.id : nil
51
+ # Returns a list of all children which are sections.
52
+ # @return [Array<Section>]
53
+ def sections
54
+ child_nodes.of_type("Section").fetch_nodes.in_order.collect do |section_node|
55
+ section_node.node
56
+ end
56
57
  end
57
58
 
58
- def parent
59
- node ? node.section : nil
59
+ alias :child_sections :sections
60
+
61
+ # Since #sections isn't an association anymore, callers can use this rather than #sections.build
62
+ def build_section
63
+ Section.new(:parent=>self)
60
64
  end
61
65
 
62
- def parent_id=(sec_id)
63
- self.parent = Section.find(sec_id)
66
+ # Used by the sitemap to find children to iterate over.
67
+ def child_nodes
68
+ self.node.children
64
69
  end
65
70
 
66
- def parent=(sec)
67
- if node
68
- node.move_to_end(sec)
69
- else
70
- build_node(:node => self, :section => sec)
71
+ def pages
72
+ child_pages = self.node.children.collect do |section_node|
73
+ section_node.node if section_node.page?
71
74
  end
75
+ child_pages.compact
72
76
  end
73
77
 
74
- def ancestors(options={})
75
- ancs = node ? node.ancestors : []
76
- options[:include_self] ? ancs + [self] : ancs
78
+ def self.sitemap
79
+ SectionNode.of_type(["Page", "Link", "Section"]).fetch_nodes.arrange(:order=>:position)
80
+ end
81
+
82
+ def visible_child_nodes(options={})
83
+ children = child_nodes.of_type(["Section", "Page", "Link"]).fetch_nodes.in_order.all
84
+ visible_children = children.select { |sn| sn.visible? }
85
+ options[:limit] ? visible_children[0...options[:limit]] : visible_children
86
+ end
87
+
88
+
89
+ # Returns a complete list of all sections that are desecendants of this sections, in order, as a single flat list.
90
+ # Used by Section selectors where users have to pick a single section from a complete list of all sections.
91
+ def master_section_list
92
+ sections.map do |section|
93
+ section.full_path = root? ? section.name : "#{name} / #{section.name}"
94
+ [section] << section.master_section_list
95
+ end.flatten.compact
96
+ end
97
+
98
+ def parent_id
99
+ parent ? parent.id : nil
100
+ end
101
+
102
+ def parent_id=(sec_id)
103
+ self.parent = Section.find(sec_id)
77
104
  end
78
105
 
79
106
  def with_ancestors(options = {})
@@ -94,33 +121,46 @@ class Section < ActiveRecord::Base
94
121
  end
95
122
 
96
123
  def empty?
97
- child_nodes.reject{|n| n.orphaned?}.empty?
124
+ child_nodes.empty?
98
125
  end
99
126
 
127
+ # Callback to determine if this section can be deleted.
100
128
  def deletable?
101
129
  !root? && empty?
102
130
  end
103
131
 
132
+ # Callback to clean up related nodes
133
+ def destroy_node
134
+ node.destroy
135
+ end
136
+
104
137
  def editable_by_group?(group)
105
138
  group.editable_by_section(self)
106
139
  end
107
140
 
108
141
  def status
109
- public? ? :unlocked : :locked
142
+ @status ||= public? ? :unlocked : :locked
110
143
  end
111
144
 
145
+ # Used by the file browser to look up a section by the combined names as a path.
146
+ # i.e. /A/B/
147
+ # @return [Section] nil if not found
112
148
  def self.find_by_name_path(name_path)
113
- section = Section.root.first
114
- children = name_path.split("/")[1..-1] || []
115
- children.each do |name|
116
- section = section.sections.first(:conditions => {:name => name})
149
+ current_section = Section.root.first
150
+ path_names = name_path.split("/")[1..-1] || []
151
+
152
+ # This implementation is very slow as it has to loop over the entire tree in memory to match each name element.
153
+ path_names.each do |name|
154
+ current_section.sections.each do |s|
155
+ current_section = s if s.name == name
156
+ end
117
157
  end
118
- section
158
+ current_section
119
159
  end
120
160
 
121
161
  #The first page that is a decendent of this section
122
162
  def first_page_or_link
123
- section_node = child_nodes.of_type(['Link', 'Page']).first(:order => "section_nodes.position")
163
+ section_node = child_nodes.of_type(['Link', 'Page']).fetch_nodes.in_order.first
124
164
  return section_node.node if section_node
125
165
  sections.each do |s|
126
166
  node = s.first_page_or_link