page_engine 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 %>
|