page_engine 0.0.1
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.
- data/MIT-LICENSE +20 -0
- data/README.markdown +74 -0
- data/Rakefile +39 -0
- data/app/assets/images/page_engine/add.png +0 -0
- data/app/assets/images/page_engine/bullet_add.png +0 -0
- data/app/assets/images/page_engine/bullet_go.png +0 -0
- data/app/assets/images/page_engine/delete.png +0 -0
- data/app/assets/images/page_engine/page_add.png +0 -0
- data/app/assets/images/page_engine/page_copy.png +0 -0
- data/app/assets/images/page_engine/page_delete.png +0 -0
- data/app/assets/images/page_engine/page_edit.png +0 -0
- data/app/assets/images/page_engine/page_gear.png +0 -0
- data/app/assets/images/page_engine/page_green.png +0 -0
- data/app/assets/images/page_engine/page_hidden.png +0 -0
- data/app/assets/images/page_engine/page_lightning.png +0 -0
- data/app/assets/images/page_engine/page_line.jpg +0 -0
- data/app/assets/images/page_engine/page_red.png +0 -0
- data/app/assets/images/page_engine/pencil.png +0 -0
- data/app/assets/images/page_engine/waiting.gif +0 -0
- data/app/assets/images/page_engine/zoom.png +0 -0
- data/app/assets/javascripts/markitup/sets/css/set.js +52 -0
- data/app/assets/javascripts/markitup/sets/html/set.js +64 -0
- data/app/assets/javascripts/markitup/sets/javascript/set.js +6 -0
- data/app/assets/javascripts/markitup/sets/markdown/set.js +53 -0
- data/app/assets/javascripts/markitup/sets/textile/set.js +57 -0
- data/app/assets/javascripts/page_engine.js +189 -0
- data/app/assets/stylesheets/jquery-ui/smoothness/jquery-ui-1.8.15.custom.css +307 -0
- data/app/assets/stylesheets/markitup/sets/css/style.css +69 -0
- data/app/assets/stylesheets/markitup/sets/html/style.css +58 -0
- data/app/assets/stylesheets/markitup/sets/javascript/style.css +0 -0
- data/app/assets/stylesheets/markitup/sets/markdown/style.css +49 -0
- data/app/assets/stylesheets/markitup/sets/textile/style.css +58 -0
- data/app/assets/stylesheets/markitup/skins/markitup/style.css +147 -0
- data/app/assets/stylesheets/markitup/skins/simple/style.css +118 -0
- data/app/assets/stylesheets/page_engine.css +231 -0
- data/app/controllers/admin/page_snippets_controller.rb +64 -0
- data/app/controllers/admin/pages_controller.rb +167 -0
- data/app/controllers/pages_controller.rb +20 -0
- data/app/helpers/pages_helper.rb +234 -0
- data/app/models/page.rb +233 -0
- data/app/models/page_part.rb +35 -0
- data/app/models/page_role.rb +15 -0
- data/app/models/page_snippet.rb +30 -0
- data/app/views/admin/page_snippets/_form.html.haml +10 -0
- data/app/views/admin/page_snippets/destroy.js.erb +3 -0
- data/app/views/admin/page_snippets/edit.html.haml +6 -0
- data/app/views/admin/page_snippets/index.html.haml +20 -0
- data/app/views/admin/page_snippets/new.html.haml +6 -0
- data/app/views/admin/page_snippets/show.html.erb +20 -0
- data/app/views/admin/pages/_form.html.haml +56 -0
- data/app/views/admin/pages/_page.html.haml +19 -0
- data/app/views/admin/pages/_page_list.html.haml +2 -0
- data/app/views/admin/pages/_page_part_fields.html.haml +9 -0
- data/app/views/admin/pages/destroy.js.erb +1 -0
- data/app/views/admin/pages/duplicate.js.erb +5 -0
- data/app/views/admin/pages/edit.html.haml +9 -0
- data/app/views/admin/pages/index.html.haml +10 -0
- data/app/views/admin/pages/new.html.haml +10 -0
- data/app/views/admin/pages/show.html.erb +100 -0
- data/app/views/admin/pages/sort.js.erb +3 -0
- data/app/views/layouts/admin.html.haml +20 -0
- data/app/views/pages/_nav_item.html.haml +10 -0
- data/app/views/pages/_navigation.html.haml +11 -0
- data/app/views/pages/index.html.erb +2 -0
- data/app/views/pages/show.html.erb +2 -0
- data/config/routes.rb +23 -0
- data/db/migrate/20110814185929_create_page_engine.rb +77 -0
- data/db/seed.rb +8 -0
- data/lib/generators/page_engine/page_engine_generator.rb +59 -0
- data/lib/page_engine/class_methods.rb +4 -0
- data/lib/page_engine/defaults.rb +5 -0
- data/lib/page_engine/engine.rb +4 -0
- data/lib/page_engine/exceptions.rb +4 -0
- data/lib/page_engine/extensions.rb +24 -0
- data/lib/page_engine/helpers.rb +10 -0
- data/lib/page_engine/instance_methods.rb +82 -0
- data/lib/page_engine/routes_finder.rb +23 -0
- data/lib/page_engine.rb +41 -0
- data/lib/tasks/page_engine_tasks.rake +4 -0
- metadata +192 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
class PagesController < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
# Find the first published root page
|
5
|
+
@pages = Page.published.shown_in_sitemap.all.group_by(&:parent_id)
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
if @page
|
10
|
+
respond_to do |format|
|
11
|
+
format.html # show.html.erb
|
12
|
+
format.xml { render :xml => @page }
|
13
|
+
end
|
14
|
+
else
|
15
|
+
raise ActiveRecord::RecordNotFound
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module PagesHelper
|
2
|
+
|
3
|
+
# Set the page title
|
4
|
+
def page_title(default_text)
|
5
|
+
if @page
|
6
|
+
replace_title_for(@page)
|
7
|
+
else
|
8
|
+
default_text
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def page_js(options={})
|
13
|
+
default_options = {
|
14
|
+
'with_tags' => true
|
15
|
+
}.merge(options.stringify_keys)
|
16
|
+
|
17
|
+
if default_options['with_tags']
|
18
|
+
if @page && !@page.js.blank?
|
19
|
+
javascript_tag do
|
20
|
+
@page.js
|
21
|
+
end
|
22
|
+
end
|
23
|
+
else
|
24
|
+
@page.js
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def page_css(options={})
|
29
|
+
default_options = {
|
30
|
+
'with_tags' => true
|
31
|
+
}.merge(options.stringify_keys)
|
32
|
+
|
33
|
+
if default_options['with_tags']
|
34
|
+
if @page && !@page.css.blank?
|
35
|
+
content_tag :style do
|
36
|
+
@page.css
|
37
|
+
end
|
38
|
+
end
|
39
|
+
else
|
40
|
+
@page.css
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def page_meta_keywords
|
45
|
+
if @page && !@page.meta_keywords.blank?
|
46
|
+
content_tag :meta, :name => 'keywords' do
|
47
|
+
@page.meta_keywords
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def page_meta_description
|
53
|
+
if @page && !@page.meta_description.blank?
|
54
|
+
content_tag :meta, :name => 'description' do
|
55
|
+
@page.meta_description
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Usage:
|
61
|
+
# You can use the attributes of any instance variables and insert them in the title
|
62
|
+
# For example:
|
63
|
+
# This is a page for {{my_object:my_object_attribute}}
|
64
|
+
# Requires that any object that will be used have a public whitelist method which returns an array
|
65
|
+
# of legal attributes (as this can be set by a user certain attributes should not be exposed)
|
66
|
+
def replace_title_for(page)
|
67
|
+
return nil unless page
|
68
|
+
page.title.scan(/\{\{(\w+):(\w+)\}\}/).uniq.flatten.in_groups_of(2).each do |klass, attribute|
|
69
|
+
if self.instance_variable_defined? "@#{klass}"
|
70
|
+
obj = self.instance_variable_get "@#{klass}"
|
71
|
+
if obj.class.public_methods.include?(:whitelist) && obj.class.whitelist.is_a?(Array)
|
72
|
+
if obj.class.whitelist.include?(attribute)
|
73
|
+
page.title.gsub!("{{#{klass}:#{attribute}}}", obj.send(attribute).to_s)
|
74
|
+
else
|
75
|
+
page.title.gsub!("{{#{klass}:#{attribute}}}", "'#{attribute}' not in whitelist for #{obj.class}")
|
76
|
+
end
|
77
|
+
else
|
78
|
+
page.title.gsub!("{{#{klass}:#{attribute}}}", "Whitelist not defined for #{obj.class}")
|
79
|
+
end
|
80
|
+
else
|
81
|
+
page.title.gsub!("{{#{klass}:#{attribute}}}", "Not found")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
page.title
|
86
|
+
end
|
87
|
+
|
88
|
+
# Add extra fields for an object in a form, in this case page parts
|
89
|
+
def link_to_add_fields(name, f, association)
|
90
|
+
new_object = f.object.class.reflect_on_association(association).klass.new
|
91
|
+
fields = simple_fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
|
92
|
+
safe_concat(render(association.to_s.singularize + "_fields", :f => builder))
|
93
|
+
end
|
94
|
+
|
95
|
+
link_to('Add', '#', :onclick => "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")", :class => 'icon add')
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return the specified page part content
|
99
|
+
def page_content(options={})
|
100
|
+
default_options = {
|
101
|
+
'page' => @page,
|
102
|
+
'part' => 'body'
|
103
|
+
}.merge!(options.stringify_keys)
|
104
|
+
|
105
|
+
default_options['page'].page_parts.detect { |p| p.title == default_options['part'].to_s } if default_options['page']
|
106
|
+
end
|
107
|
+
|
108
|
+
def page_snippet(name, options={})
|
109
|
+
default_options = {
|
110
|
+
'default_text' => 'Page snippet not found',
|
111
|
+
'tag' => nil,
|
112
|
+
'class' => ['page_snippet'],
|
113
|
+
'id' => nil
|
114
|
+
}.merge(options.stringify_keys)
|
115
|
+
|
116
|
+
page_snippet = PageSnippet.find_by_name(name.to_s)
|
117
|
+
|
118
|
+
if default_options['tag']
|
119
|
+
content_tag default_options['tag'], :class => default_options['class'], :id => default_options['id'] do
|
120
|
+
page_snippet ? page_snippet : default_options['default_text']
|
121
|
+
end
|
122
|
+
else
|
123
|
+
page_snippet ? page_snippet : default_options['default_text']
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def link_to_page(page, options={})
|
128
|
+
# Arbitrarily chosen url to take precedence over controller and action
|
129
|
+
if page.url.blank?
|
130
|
+
if page.controller.blank? && page.action.blank?
|
131
|
+
link_to replace_title_for(page), "/#{page.permalink}", options
|
132
|
+
else
|
133
|
+
link_to replace_title_for(page), url_for(:controller => '/' + page.controller, :action => page.action), options
|
134
|
+
end
|
135
|
+
else
|
136
|
+
link_to replace_title_for(page), page.url, options
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Takes an array of pages which constitute the ancestors of the current page (page) and displays them in the requested format
|
141
|
+
# Options:
|
142
|
+
# * seperator: The text or character that will seperate the breadcrumbs. Defaults to " » "
|
143
|
+
# * format: choices are "ul" or "inline". "ul" displays the breadcrumb links in an unordered list whilst "inline" displays them inline in a containing div. Defaults to "ul"
|
144
|
+
def breadcrumbs(options={})
|
145
|
+
default_options = {
|
146
|
+
'breadcrumbs' => @breadcrumbs,
|
147
|
+
'page' => @page,
|
148
|
+
'seperator' => ' » ',
|
149
|
+
'format' => 'ul'
|
150
|
+
}.merge!(options.stringify_keys)
|
151
|
+
|
152
|
+
case default_options['format'].to_s
|
153
|
+
when 'inline'
|
154
|
+
content_tag :div, :class => 'breadcrumbs' do
|
155
|
+
links = default_options['breadcrumbs'].collect.with_index { |breadcrumb, i| link_to_page(breadcrumb, :class => "crumb_#{i}") + default_options['seperator'].html_safe }.join().html_safe
|
156
|
+
links += content_tag(:span, replace_title_for(default_options['page']), :class => 'current_page') if default_options['page']
|
157
|
+
end
|
158
|
+
|
159
|
+
when 'ul'
|
160
|
+
content_tag :ul, :class => 'breadcrumbs' do
|
161
|
+
links = default_options['breadcrumbs'].collect.with_index { |breadcrumb, i| content_tag(:li, link_to_page(breadcrumb, :class => "crumb_#{i}")) }.join().html_safe
|
162
|
+
links += content_tag(:li, replace_title_for(default_options['page']), :class => 'current_page') if default_options['page']
|
163
|
+
end
|
164
|
+
|
165
|
+
else
|
166
|
+
'Please choose one of \'inline\' or \'ul\' as a format'
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Options:
|
171
|
+
# * current: The current_page if not @page
|
172
|
+
# * depth: The number of levels in the tree to traverse. Defaults to 2
|
173
|
+
# * class: The class of the containing ul. Defaults to ""
|
174
|
+
# * id: The id of the containing id. Defaults to ""
|
175
|
+
# * link_current: Set to true if the current page should have a link. Defaults to false
|
176
|
+
def navigation(permalink, options={})
|
177
|
+
default_options = {
|
178
|
+
'current' => @page,
|
179
|
+
'class' => 'nav',
|
180
|
+
'id' => '',
|
181
|
+
'include_root' => false,
|
182
|
+
'link_current' => false,
|
183
|
+
'depth' => 2
|
184
|
+
}.merge!(options.stringify_keys)
|
185
|
+
|
186
|
+
current_user = nil unless defined?(current_user)
|
187
|
+
|
188
|
+
root_page = Page.published_or_hidden.viewable_by(current_user)
|
189
|
+
|
190
|
+
if permalink
|
191
|
+
root_page = root_page.find_by_permalink(permalink.to_s)
|
192
|
+
else
|
193
|
+
root_page = root_page.first
|
194
|
+
end
|
195
|
+
|
196
|
+
return "<p><em>Error:</em> Root page not found</p>".html_safe unless root_page
|
197
|
+
|
198
|
+
grouped_pages = root_page.self_and_descendants.viewable_by(current_user).shown_in_menu.published.group_by(&:parent_id)
|
199
|
+
|
200
|
+
render 'pages/navigation', :options => default_options, :root_page => root_page, :grouped_pages => grouped_pages, :level => 1
|
201
|
+
end
|
202
|
+
|
203
|
+
def filter_select(target, options={})
|
204
|
+
default_options = {
|
205
|
+
'builder' => nil,
|
206
|
+
'object' => nil,
|
207
|
+
'attribute' => nil
|
208
|
+
}.merge!(options.stringify_keys)
|
209
|
+
|
210
|
+
if default_options['builder']
|
211
|
+
default_options['builder'].select(default_options['attribute'], Page.filters, {}, { :class => 'filter', :rel => target })
|
212
|
+
else
|
213
|
+
select_tag(default_options['object'], default_options['attribute'], Page.filters, {}, { :class => 'filter', :rel => target })
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
private
|
218
|
+
|
219
|
+
# To add a class to the root of the tree that the current page appears in
|
220
|
+
def mark_as_root_of_current? page
|
221
|
+
if page.root?
|
222
|
+
page == @page
|
223
|
+
else
|
224
|
+
return true if @breadcrumbs.include?(page) || page == @page
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def page_menu_class page
|
229
|
+
css_classes = []
|
230
|
+
css_classes << page.menu_css_class unless page.menu_css_class.blank?
|
231
|
+
css_classes << "selected" if mark_as_root_of_current?(page)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
data/app/models/page.rb
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
class Page < ActiveRecord::Base
|
2
|
+
acts_as_nested_set
|
3
|
+
|
4
|
+
# Relationships
|
5
|
+
# has_many :descendants, :class_name => "Page", :conditions => proc { "pages.lft between #{self.send(:lft)} and #{self.send(:rgt)}" }
|
6
|
+
# has_many :ancestors, :class_name => "Page", :conditions => proc { "(pages.lft <= #{self.send(:lft)} AND pages.rgt >= #{self.send(:rgt)}) AND (pages.id != #{self.send(:id)})" }, :foreign_key => false
|
7
|
+
has_many :pages, :foreign_key => :parent_id
|
8
|
+
has_many :page_parts, :dependent => :destroy
|
9
|
+
|
10
|
+
if PageEngine.class_exists?('Role')
|
11
|
+
has_many :page_roles
|
12
|
+
has_many :required_roles, :through => :page_roles, :source => :required_role
|
13
|
+
has_many :excluded_roles, :through => :page_roles, :source => :excluded_role
|
14
|
+
end
|
15
|
+
|
16
|
+
if PageEngine.class_exists?('Asset')
|
17
|
+
has_assets
|
18
|
+
end
|
19
|
+
|
20
|
+
if PageEngine.class_exists?('User')
|
21
|
+
belongs_to :user
|
22
|
+
end
|
23
|
+
|
24
|
+
accepts_nested_attributes_for :page_parts, :allow_destroy => true
|
25
|
+
|
26
|
+
# Filters
|
27
|
+
before_validation :set_permalink
|
28
|
+
before_save :check_publish_window
|
29
|
+
before_save :set_controller_and_action
|
30
|
+
|
31
|
+
# Validations
|
32
|
+
validates :title, :presence => true
|
33
|
+
validates :permalink, :presence => true, :uniqueness => true, :format => { :with => /^[a-z0-9-]+$/, :message => "Must only contain lower case letters, numbers or hyphens" }
|
34
|
+
validates :url, :uniqueness => true, :allow_nil => true, :allow_blank => true
|
35
|
+
validates_associated :page_parts
|
36
|
+
|
37
|
+
# Scopes
|
38
|
+
scope :by_permalink, lambda { |permalink| where(:permalink => permalink) }
|
39
|
+
scope :published, lambda { where(["(status = 'Published' and ? between publish_from and publish_to) or (status = 'Published' and publish_from is null and publish_to is null)", DateTime.now]) }
|
40
|
+
scope :published_or_hidden, lambda { where(["(status = 'Published' and ? between publish_from and publish_to) or (status = 'Published' and publish_from is null and publish_to is null) or status = 'Hidden'", DateTime.now]) }
|
41
|
+
scope :root_only, where(:parent_id => nil)
|
42
|
+
scope :shown_in_sitemap, where({ :display_in_sitemap => true })
|
43
|
+
scope :shown_in_menu, where({ :display_in_menu => true })
|
44
|
+
scope :just_controller_and_actions, select("controller || '|' || action as taken").group('taken')
|
45
|
+
|
46
|
+
attr_accessor :no_publish_window, :controller_action
|
47
|
+
|
48
|
+
def no_publish_window
|
49
|
+
no_publish_window_set?
|
50
|
+
end
|
51
|
+
|
52
|
+
def controller_action
|
53
|
+
if controller && action
|
54
|
+
"#{controller}|#{action}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def no_publish_window_set?
|
59
|
+
self.publish_from.nil? && self.publish_to.nil?
|
60
|
+
end
|
61
|
+
|
62
|
+
def published?
|
63
|
+
if self.no_publish_window_set?
|
64
|
+
self.status == "Published"
|
65
|
+
else
|
66
|
+
self.publish_from < DateTime.now && self.publish_to > DateTime.now && self.status == "Published"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_param
|
71
|
+
permalink
|
72
|
+
end
|
73
|
+
|
74
|
+
def is_child_of? page
|
75
|
+
self.parent_id == page.id ? true : false
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_parent_of? page
|
79
|
+
self.id == page.parent_id ? true : false
|
80
|
+
end
|
81
|
+
|
82
|
+
def number_of_children
|
83
|
+
(self.rgt - self.lft - 1) / 2
|
84
|
+
end
|
85
|
+
|
86
|
+
def duplicate
|
87
|
+
page = Page.new(self.attributes)
|
88
|
+
page.title += " (copy) #{Time.now.strftime('%Y%m%d_%H%M%S')}"
|
89
|
+
page.permalink = page.permalink + "-copy-#{Time.now.strftime('%Y%m%d-%H%M%S')}"
|
90
|
+
page.save
|
91
|
+
page.move_to_right_of self
|
92
|
+
|
93
|
+
# Duplicate each of the objects associated with the original
|
94
|
+
# Page parts
|
95
|
+
self.page_parts.each do |page_part|
|
96
|
+
page.page_parts << page_part.duplicate
|
97
|
+
end
|
98
|
+
|
99
|
+
# Roles
|
100
|
+
if PageEngine.class_exists?('Role')
|
101
|
+
page.required_roles = self.required_roles
|
102
|
+
page.excluded_roles = self.excluded_roles
|
103
|
+
end
|
104
|
+
|
105
|
+
# Assets
|
106
|
+
if PageEngine.class_exists?('Asset')
|
107
|
+
self.attachables.each do |attachable|
|
108
|
+
page.attachables << attachable.duplicate
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
page
|
113
|
+
end
|
114
|
+
|
115
|
+
def is_viewable_by? user
|
116
|
+
if PageEngine.class_exists?('Role')
|
117
|
+
if PageEngine.class_exists?('User') && user
|
118
|
+
return true if self.roles.length == 0
|
119
|
+
self.role_ids.length != (self.role_ids - user.role_ids.uniq).length
|
120
|
+
else
|
121
|
+
self.roles.length == 0
|
122
|
+
end
|
123
|
+
else
|
124
|
+
true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def move_children_to_parent
|
129
|
+
self.children.each do |child|
|
130
|
+
if self.parent
|
131
|
+
child.move_to_child_of self.parent
|
132
|
+
else
|
133
|
+
child.move_to_root
|
134
|
+
end
|
135
|
+
end
|
136
|
+
self.reload
|
137
|
+
end
|
138
|
+
|
139
|
+
def css_status
|
140
|
+
return "live" if self.published?
|
141
|
+
status.downcase
|
142
|
+
end
|
143
|
+
|
144
|
+
# Override the protected methods of awesome_nested_set so lft and rgt can be set
|
145
|
+
def lft=(x)
|
146
|
+
self[:lft] = x
|
147
|
+
end
|
148
|
+
|
149
|
+
def rgt=(x)
|
150
|
+
self[:rgt] = x
|
151
|
+
end
|
152
|
+
|
153
|
+
class << self
|
154
|
+
attr_accessor :layouts
|
155
|
+
|
156
|
+
def breadcrumbs_for user, url
|
157
|
+
root = Page.published.viewable_by(user).find_by_url(url)
|
158
|
+
root.nil? ? [] : root.self_and_ancestors
|
159
|
+
end
|
160
|
+
|
161
|
+
def status_values
|
162
|
+
["Draft", "Published", "Review", "Hidden"]
|
163
|
+
end
|
164
|
+
|
165
|
+
def default_layout
|
166
|
+
Page.layouts.first
|
167
|
+
end
|
168
|
+
|
169
|
+
def filters
|
170
|
+
%w{ none html textile markdown erb erb+textile }
|
171
|
+
end
|
172
|
+
|
173
|
+
def page_parts
|
174
|
+
%w{ body left right header footer }
|
175
|
+
end
|
176
|
+
|
177
|
+
# Scopes
|
178
|
+
|
179
|
+
def viewable_by(user)
|
180
|
+
if PageEngine.class_exists?('Role') && PageEngine.class_exists?('User')
|
181
|
+
if user
|
182
|
+
# This is a bit of a kludge until I can figure out how to get it to work properly in a single sql query
|
183
|
+
includes(:page_roles).where("pages.id in (?) or (page_roles.required_role_id is null and page_roles.excluded_role_id is null)", PageRole.viewable_page_ids_for(user))
|
184
|
+
else
|
185
|
+
includes(:page_roles).where({ 'page_roles.required_role_id' => nil })
|
186
|
+
end
|
187
|
+
else
|
188
|
+
scoped
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def with_roles roles
|
193
|
+
if Extras.class_exists?('Role')
|
194
|
+
includes(:roles).where([ "roles.id IN (?)", roles.join(',') ])
|
195
|
+
else
|
196
|
+
scoped
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def with_url request, params
|
201
|
+
url = request.fullpath
|
202
|
+
url.gsub!(/\?.*/, '') # Strip away anything after the ? as it's not needed
|
203
|
+
|
204
|
+
where(["pages.permalink = ? or url = ? or (controller = ? and action = ?)", params[:permalink], url, params[:controller], params[:action]])
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
private
|
210
|
+
|
211
|
+
def set_permalink
|
212
|
+
self.permalink = self[:permalink].blank? ? self.title.parameterize : self[:permalink].parameterize
|
213
|
+
self.menu_css_class = self.permalink if self[:menu_css_class].blank?
|
214
|
+
end
|
215
|
+
|
216
|
+
def set_controller_and_action
|
217
|
+
if @controller_action
|
218
|
+
controller_and_action = @controller_action.split('|')
|
219
|
+
self.controller = controller_and_action.first
|
220
|
+
self.action = controller_and_action.last
|
221
|
+
else
|
222
|
+
self.controller = nil
|
223
|
+
self.action = nil
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def check_publish_window
|
228
|
+
if @no_publish_window == "1"
|
229
|
+
self.publish_to = self.publish_from = nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class PagePart < ActiveRecord::Base
|
2
|
+
# Relationships
|
3
|
+
belongs_to :page
|
4
|
+
|
5
|
+
# Validations
|
6
|
+
validates :title, :uniqueness => {:scope => "page_id"}, :presence => true
|
7
|
+
|
8
|
+
def duplicate
|
9
|
+
page_part = PagePart.new(self.attributes)
|
10
|
+
page_part.save
|
11
|
+
page_part
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
if content
|
16
|
+
case filter
|
17
|
+
when "none"
|
18
|
+
content.html_safe
|
19
|
+
when "textile"
|
20
|
+
RedCloth.new(content).to_html.html_safe
|
21
|
+
when "markdown"
|
22
|
+
BlueCloth.new(content).to_html.html_safe
|
23
|
+
when "erb"
|
24
|
+
require "erb"
|
25
|
+
eval(ERB.new(content).src).html_safe
|
26
|
+
when "erb+textile"
|
27
|
+
require "erb"
|
28
|
+
textilize eval(ERB.new(content).src).html_safe
|
29
|
+
when "html"
|
30
|
+
content.html_safe
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class PageRole < ActiveRecord::Base
|
2
|
+
# Relationships
|
3
|
+
belongs_to :required_role, :class_name => 'Role'
|
4
|
+
belongs_to :excluded_role, :class_name => 'Role'
|
5
|
+
|
6
|
+
# Scopes
|
7
|
+
scope :viewable_by, lambda { |user| where(:required_role_id => user.role_ids) }
|
8
|
+
scope :not_viewable_by, lambda { |user| where(:excluded_role_id => user.role_ids) }
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def viewable_page_ids_for(user)
|
12
|
+
PageRole.viewable_by(user).map(&:page_id) - PageRole.not_viewable_by(user).map(&:page_id)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class PageSnippet < ActiveRecord::Base
|
2
|
+
# Validations
|
3
|
+
validates :name, :presence => true, :uniqueness => true
|
4
|
+
|
5
|
+
# Relationships
|
6
|
+
if PageEngine.class_exists?('Asset')
|
7
|
+
has_assets
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
if content
|
12
|
+
case filter
|
13
|
+
when "none"
|
14
|
+
content.html_safe
|
15
|
+
when "textile"
|
16
|
+
RedCloth.new(content).to_html.html_safe
|
17
|
+
when "markdown"
|
18
|
+
BlueCloth.new(content).to_html.html_safe
|
19
|
+
when "erb"
|
20
|
+
require "erb"
|
21
|
+
eval(ERB.new(content).src).html_safe
|
22
|
+
when "erb+textile"
|
23
|
+
require "erb"
|
24
|
+
textilize eval(ERB.new(content).src).html_safe
|
25
|
+
when "html"
|
26
|
+
content.html_safe
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= simple_form_for [:admin, @page_snippet] do |f|
|
2
|
+
= f.error_notification
|
3
|
+
|
4
|
+
.inputs
|
5
|
+
= f.input :name
|
6
|
+
= f.input :filter, :collection => Page.filters, :include_blank => false, :class => 'filter', :input_html => { :class => 'filter', :rel => 'page_snippet_content' }
|
7
|
+
= f.input :content, :input_html => { :class => 'editor', 'data-filter' => @page_snippet.filter }
|
8
|
+
|
9
|
+
.action
|
10
|
+
= f.submit
|
@@ -0,0 +1,20 @@
|
|
1
|
+
%h2 Page Snippets
|
2
|
+
|
3
|
+
%p
|
4
|
+
= link_to('New page snippet', new_admin_page_snippet_path, :class => 'icon_left add')
|
5
|
+
|
6
|
+
%table#page_snippets
|
7
|
+
%thead
|
8
|
+
%tr
|
9
|
+
%th Name
|
10
|
+
%th
|
11
|
+
%th
|
12
|
+
%tbody
|
13
|
+
- @page_snippets.each do |page_snippet|
|
14
|
+
%tr{ :id => "page_snippet_#{page_snippet.id}", :class => cycle('odd', 'even')}
|
15
|
+
%td.odd
|
16
|
+
= page_snippet.name
|
17
|
+
%td.even.has_icon
|
18
|
+
= link_to('Edit', edit_admin_page_snippet_path(page_snippet), :class => 'icon edit')
|
19
|
+
%td.odd.has_icon
|
20
|
+
= link_to('Destroy', [:admin, page_snippet], :confirm => 'Are you sure?', :method => :delete, :class => 'icon delete')
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<p id="notice"><%= notice %></p>
|
2
|
+
|
3
|
+
<p>
|
4
|
+
<b>Title:</b>
|
5
|
+
<%= @page_snippet.title %>
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<p>
|
9
|
+
<b>Filter:</b>
|
10
|
+
<%= @page_snippet.filter %>
|
11
|
+
</p>
|
12
|
+
|
13
|
+
<p>
|
14
|
+
<b>Content:</b>
|
15
|
+
<%= @page_snippet.content %>
|
16
|
+
</p>
|
17
|
+
|
18
|
+
|
19
|
+
<%= link_to 'Edit', edit_admin_page_snippet_path(@page_snippet) %> |
|
20
|
+
<%= link_to 'Back', admin_page_snippets_path %>
|