effective_pages 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +30 -0
  4. data/Rakefile +24 -0
  5. data/app/assets/javascripts/effective_pages.js +0 -0
  6. data/app/assets/stylesheets/effective_pages/dropdown-submenu.css +7 -0
  7. data/app/assets/stylesheets/effective_pages.css.scss +1 -0
  8. data/app/controllers/admin/menus_controller.rb +79 -0
  9. data/app/controllers/admin/pages_controller.rb +95 -0
  10. data/app/controllers/effective/pages_controller.rb +24 -0
  11. data/app/helpers/effective_menus_helper.rb +151 -0
  12. data/app/helpers/effective_pages_helper.rb +14 -0
  13. data/app/models/effective/access_denied.rb +17 -0
  14. data/app/models/effective/datatables/menus.rb +16 -0
  15. data/app/models/effective/datatables/pages.rb +19 -0
  16. data/app/models/effective/menu.rb +152 -0
  17. data/app/models/effective/menu_item.rb +68 -0
  18. data/app/models/effective/page.rb +32 -0
  19. data/app/views/admin/menu_items/_actions.html.haml +4 -0
  20. data/app/views/admin/menu_items/_expand.html.haml +2 -0
  21. data/app/views/admin/menu_items/_item.html.haml +13 -0
  22. data/app/views/admin/menu_items/_new.html.haml +3 -0
  23. data/app/views/admin/menus/_actions.html.haml +4 -0
  24. data/app/views/admin/menus/_form.html.haml +9 -0
  25. data/app/views/admin/menus/edit.html.haml +2 -0
  26. data/app/views/admin/menus/index.html.haml +9 -0
  27. data/app/views/admin/menus/new.html.haml +2 -0
  28. data/app/views/admin/pages/_actions.html.haml +14 -0
  29. data/app/views/admin/pages/_form.html.haml +31 -0
  30. data/app/views/admin/pages/edit.html.haml +2 -0
  31. data/app/views/admin/pages/index.html.haml +9 -0
  32. data/app/views/admin/pages/new.html.haml +2 -0
  33. data/config/routes.rb +28 -0
  34. data/db/migrate/01_create_effective_pages.rb.erb +52 -0
  35. data/lib/effective_pages/engine.rb +19 -0
  36. data/lib/effective_pages/version.rb +3 -0
  37. data/lib/effective_pages.rb +73 -0
  38. data/lib/generators/effective_pages/install_generator.rb +43 -0
  39. data/lib/generators/templates/README +1 -0
  40. data/lib/generators/templates/effective_pages.rb +49 -0
  41. data/lib/generators/templates/example.html.haml +6 -0
  42. data/lib/tasks/effective_pages_tasks.rake +29 -0
  43. data/spec/controllers/effective/pages_controller_spec.rb +66 -0
  44. data/spec/dummy/README.rdoc +261 -0
  45. data/spec/dummy/Rakefile +7 -0
  46. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  47. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  48. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  49. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  50. data/spec/dummy/app/views/effective/pages/example.html.haml +2 -0
  51. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  52. data/spec/dummy/config/application.rb +66 -0
  53. data/spec/dummy/config/boot.rb +10 -0
  54. data/spec/dummy/config/database.yml +25 -0
  55. data/spec/dummy/config/environment.rb +5 -0
  56. data/spec/dummy/config/environments/development.rb +37 -0
  57. data/spec/dummy/config/environments/production.rb +67 -0
  58. data/spec/dummy/config/environments/test.rb +37 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +15 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  65. data/spec/dummy/config/locales/en.yml +5 -0
  66. data/spec/dummy/config/routes.rb +60 -0
  67. data/spec/dummy/config.ru +4 -0
  68. data/spec/dummy/db/migrate/01_create_effective_pages.rb +51 -0
  69. data/spec/dummy/db/schema.rb +52 -0
  70. data/spec/dummy/db/test.sqlite3 +0 -0
  71. data/spec/dummy/public/404.html +26 -0
  72. data/spec/dummy/public/422.html +26 -0
  73. data/spec/dummy/public/500.html +25 -0
  74. data/spec/dummy/public/favicon.ico +0 -0
  75. data/spec/dummy/script/rails +6 -0
  76. data/spec/dummy/spec_link +3 -0
  77. data/spec/effective_pages_spec.rb +7 -0
  78. data/spec/helpers/effective_menus_helper_spec.rb +281 -0
  79. data/spec/models/effective/menu_spec.rb +133 -0
  80. data/spec/spec_helper.rb +43 -0
  81. data/spec/support/factories.rb +15 -0
  82. metadata +261 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f2e8d4e803d0925a598367d67af494db92c5343
4
+ data.tar.gz: e9a1d930b926dbba2f6edf03ada5a3ea9a4de2d8
5
+ SHA512:
6
+ metadata.gz: 4a0ed01da349862e8fdf438f7b5f766cc3424db0c62b24694c6672ff9f47dce03bc5ce0663dcacf2f44dd11e9381f298093aee7199e9d8f28a154e23fb67ef50
7
+ data.tar.gz: 0c2324550662189e4aa3cdaf286befc6e76e895888e63b523726d3fa66b8a9718bd69ec3e7b7a97ca74b0cbf96b22fcb599212afb598c9eea01c6af26bc4ba06
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Code and Effect Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Effective Pages
2
+
3
+ Rise of the effective page!!
4
+
5
+ This is a work in progress gem that's ALMOST ready for release
6
+
7
+ TODO: Make a README!
8
+
9
+ effective_pages.page_url
10
+ effective_pages.page_path
11
+
12
+
13
+ No javascript to add for Pages
14
+
15
+ Put
16
+
17
+ = effective_page_header_tags
18
+
19
+ in your header, so the page title and meta-description can be saved
20
+
21
+
22
+ If you want to use regular maxDepth == 2 bootstrap3 menus, no CSS to add
23
+
24
+ if you want deep menus, you can add
25
+
26
+ @import 'effective_pages'; for unlimitted depth bootstrap3 menus addon
27
+
28
+ then call = render_menu('main menu', :maxdepth => 3)
29
+
30
+
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ # Our tasks
9
+ load 'lib/tasks/effective_pages_tasks.rake'
10
+
11
+ # Testing tasks
12
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
13
+ load 'rails/tasks/engine.rake'
14
+
15
+ require "bundler/vendored_thor"
16
+ Bundler::GemHelper.install_tasks
17
+
18
+ require 'rspec/core'
19
+ require 'rspec/core/rake_task'
20
+
21
+ desc "Run all specs in spec directory (excluding plugin specs)"
22
+ RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
23
+
24
+ task :default => :spec
File without changes
@@ -0,0 +1,7 @@
1
+ /* http://www.bootply.com/71520 */
2
+ li.dropdown > ul.dropdown-menu > li.dropdown{position:relative;}
3
+ li.dropdown > ul.dropdown-menu > li.dropdown>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}
4
+ li.dropdown > ul.dropdown-menu > li.dropdown:hover>.dropdown-menu{display:block;}
5
+ li.dropdown > ul.dropdown-menu > li.dropdown>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}
6
+ li.dropdown > ul.dropdown-menu > li.dropdown:hover>a:after{border-left-color:#ffffff;}
7
+ li.dropdown > ul.dropdown-menu > li.dropdown.pull-left{float:none;}li.dropdown > ul.dropdown-menu > li.dropdown.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}
@@ -0,0 +1 @@
1
+ @import 'effective_pages/dropdown-submenu';
@@ -0,0 +1,79 @@
1
+ module Admin
2
+ class MenusController < ApplicationController
3
+ before_filter :authenticate_user! # This is devise, ensure we're logged in.
4
+
5
+ layout (EffectivePages.layout.kind_of?(Hash) ? EffectivePages.layout[:admin] : EffectivePages.layout)
6
+
7
+ def index
8
+ @datatable = Effective::Datatables::Menus.new() if defined?(EffectiveDatatables)
9
+ @page_title = 'Menus'
10
+
11
+ EffectivePages.authorized?(self, :index, Effective::Menu)
12
+ end
13
+
14
+ def new
15
+ @menu = Effective::Menu.new()
16
+ @page_title = 'New Menu'
17
+
18
+ EffectivePages.authorized?(self, :new, @menu)
19
+ end
20
+
21
+ def create
22
+ @menu = Effective::Menu.new(menu_params)
23
+ @page_title = 'New Menu'
24
+
25
+ EffectivePages.authorized?(self, :create, @menu)
26
+
27
+ if @menu.save
28
+ flash[:success] = 'Successfully created menu'
29
+ redirect_to effective_pages.edit_admin_menu_path(@menu)
30
+ else
31
+ flash.now[:danger] = 'Unable to create menu'
32
+ render :action => :new
33
+ end
34
+ end
35
+
36
+ def edit
37
+ @menu = Effective::Menu.find(params[:id])
38
+ @page_title = 'Edit Menu'
39
+
40
+ EffectivePages.authorized?(self, :edit, @menu)
41
+ end
42
+
43
+ def update
44
+ @menu = Effective::Menu.find(params[:id])
45
+ @page_title = 'Edit Menu'
46
+
47
+ EffectivePages.authorized?(self, :update, @menu)
48
+
49
+ if @menu.update_attributes(menu_params)
50
+ flash[:success] = 'Successfully updated menu'
51
+ redirect_to effective_pages.edit_admin_menu_path(@menu)
52
+ else
53
+ flash.now[:danger] = 'Unable to update menu'
54
+ render :action => :edit
55
+ end
56
+ end
57
+
58
+ def destroy
59
+ @menu = Effective::Menu.find(params[:id])
60
+
61
+ EffectivePages.authorized?(self, :destroy, @menu)
62
+
63
+ if @menu.destroy
64
+ flash[:success] = 'Successfully deleted menu'
65
+ else
66
+ flash[:danger] = 'Unable to delete menu'
67
+ end
68
+
69
+ redirect_to effective_pages.admin_menus_path
70
+ end
71
+
72
+ private
73
+
74
+ def menu_params
75
+ params.require(:effective_menu).permit(:title)
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,95 @@
1
+ module Admin
2
+ class PagesController < ApplicationController
3
+ before_filter :authenticate_user! # This is devise, ensure we're logged in.
4
+
5
+ layout (EffectivePages.layout.kind_of?(Hash) ? EffectivePages.layout[:admin] : EffectivePages.layout)
6
+
7
+ def index
8
+ @page_title = 'Pages'
9
+ EffectivePages.authorized?(self, :index, Effective::Page)
10
+
11
+ if request.format.json?
12
+ # This is actually the effective_menus dialog asking for all @pages
13
+ render :json => ([['', '']] + Effective::Page.order(:title).map { |page| [page.title, page.id] }).to_json
14
+ return
15
+ else
16
+ @datatable = Effective::Datatables::Pages.new() if defined?(EffectiveDatatables)
17
+ end
18
+ end
19
+
20
+ def new
21
+ @page = Effective::Page.new()
22
+ @page_title = 'New Page'
23
+
24
+ EffectivePages.authorized?(self, :new, @page)
25
+ end
26
+
27
+ def create
28
+ @page = Effective::Page.new(page_params)
29
+ @page_title = 'New Page'
30
+
31
+ EffectivePages.authorized?(self, :create, @page)
32
+
33
+ if @page.save
34
+ if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
35
+ redirect_to effective_regions.edit_path(effective_pages.page_path(@page))
36
+ else
37
+ flash[:success] = 'Successfully created page'
38
+ redirect_to effective_pages.edit_admin_page_path(@page)
39
+ end
40
+ else
41
+ flash.now[:danger] = 'Unable to create page'
42
+ render :action => :new
43
+ end
44
+ end
45
+
46
+ def edit
47
+ @page = Effective::Page.find(params[:id])
48
+ @page_title = 'Edit Page'
49
+
50
+ EffectivePages.authorized?(self, :edit, @page)
51
+ end
52
+
53
+ def update
54
+ @page = Effective::Page.find(params[:id])
55
+ @page_title = 'Edit Page'
56
+
57
+ EffectivePages.authorized?(self, :update, @page)
58
+
59
+ if @page.update_attributes(page_params)
60
+ if params[:commit] == 'Save and Edit Content' && defined?(EffectiveRegions)
61
+ redirect_to effective_regions.edit_path(effective_pages.page_path(@page))
62
+ else
63
+ flash[:success] = 'Successfully updated page'
64
+ redirect_to effective_pages.edit_admin_page_path(@page)
65
+ end
66
+ else
67
+ flash.now[:danger] = 'Unable to update page'
68
+ render :action => :edit
69
+ end
70
+ end
71
+
72
+ def destroy
73
+ @page = Effective::Page.find(params[:id])
74
+
75
+ EffectivePages.authorized?(self, :destroy, @page)
76
+
77
+ if @page.destroy
78
+ flash[:success] = 'Successfully deleted page'
79
+ else
80
+ flash[:danger] = 'Unable to delete page'
81
+ end
82
+
83
+ redirect_to effective_pages.admin_pages_path
84
+ end
85
+
86
+ private
87
+
88
+ def page_params
89
+ params.require(:effective_page).permit(
90
+ :title, :meta_description, :draft, :layout, :template, :slug, :roles => []
91
+ )
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,24 @@
1
+ module Effective
2
+ class PagesController < ApplicationController
3
+ def show
4
+ @pages = (Rails::VERSION::MAJOR > 3 ? Effective::Page.all : Effective::Page.scoped)
5
+
6
+ if defined?(EffectiveRoles) && (current_user.respond_to?(:roles) rescue false)
7
+ @pages = @pages.for_role(current_user.roles)
8
+ end
9
+
10
+ if params[:edit].to_s != 'true'
11
+ @pages = @pages.published
12
+ end
13
+
14
+ @page = @pages.find(params[:id])
15
+ raise ActiveRecord::RecordNotFound unless @page
16
+
17
+ EffectivePages.authorized?(self, :show, @page)
18
+
19
+ @page_title = @page.title
20
+
21
+ render @page.template, :layout => @page.layout, :locals => {:page => @page}
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,151 @@
1
+ module EffectiveMenusHelper
2
+ def render_menu(menu, options = {}, &block)
3
+ menu = Effective::Menu.find_by_title(menu) if menu.kind_of?(String)
4
+ return "<ul class='nav navbar-nav'><li>Menu '#{menu}' does not exist</li></ul>".html_safe if !menu.present?
5
+
6
+ if (effectively_editting? rescue false)
7
+ options[:menu_id] = menu.id
8
+ form_for(menu, :url => '/') { |form| options[:form] = form }
9
+ end
10
+
11
+ if block_given? && options[:form].blank?
12
+ render_menu_items(menu.menu_items, options) { yield }
13
+ else
14
+ render_menu_items(menu.menu_items, options)
15
+ end
16
+
17
+ # if options[:for_editor]
18
+ #else
19
+ # Rails.cache.fetch(menu) { render_menu_items(menu.menu_items, options) }
20
+ #end
21
+ end
22
+
23
+ def render_menu_items(items, options = {}, &block)
24
+ if options[:form].present? && options[:form].kind_of?(ActionView::Helpers::FormBuilder) == false
25
+ raise 'Expecting ActionView::Helpers::FormBuilder object for :form => option'
26
+ end
27
+
28
+ html = ''
29
+
30
+ if options[:form]
31
+ html << "<ul class='nav navbar-nav effective-menu #{options[:class]}'"
32
+ html << " data-effective-menu-id='#{options[:menu_id] || 0}'"
33
+ html << " data-effective-menu-expand-html=\"#{render(:partial => 'admin/menu_items/expand').gsub('"', "'").gsub("\n", '').gsub(' ', '')}\""
34
+ html << " data-effective-menu-new-html=\"#{render(:partial => 'admin/menu_items/new', :locals => { :item => Effective::MenuItem.new(), :form => options[:form] }).gsub('"', "'").gsub("\n", '').gsub(' ', '').gsub('[0]', '[:new]').gsub('_0_', '_:new_')}\""
35
+
36
+ maxdepth = ((options[:maxdepth].presence || EffectivePages.menu[:maxdepth].presence).to_i rescue 0)
37
+ html << " data-effective-menu-maxdepth='#{maxdepth}'" if maxdepth > 0
38
+
39
+ html << ">"
40
+ else
41
+ html << "<ul class='nav navbar-nav#{' ' + options[:class].to_s if options[:class].present?}'>"
42
+ end
43
+
44
+ stack = [items.to_a.first] # A stack to keep track of rgt values.
45
+ skip_to_lft = 0 # This lets us skip over nodes we don't have visible_for? permission to see
46
+
47
+ items.each_with_index do |item, index|
48
+ next if index == 0 # We always skip the first Root node
49
+
50
+ # This allows us to skip over nodes we don't have permission to view
51
+ next if item.lft < skip_to_lft
52
+ if options[:form].blank? && !item.visible_for?(defined?(current_user) ? current_user : nil)
53
+ skip_to_lft = item.rgt + 1
54
+ next
55
+ end
56
+
57
+ if stack.size > 1
58
+ html << "<ul class='dropdown-menu'>" if (item.rgt < stack.last.rgt) # Level down?
59
+
60
+ while item.rgt > stack.last.rgt # Level up?
61
+ stack.pop
62
+ html << "</ul></li>" if (item.rgt > stack.last.rgt)
63
+ end
64
+ end
65
+
66
+ # Render the <li>...</li> with carets only on top level dropdowns, not sub dropdowns
67
+ html << render_menu_item(item, stack.size == 1, options)
68
+
69
+ stack.push(item)
70
+ end
71
+
72
+ while stack.size > 0
73
+ item = stack.pop
74
+
75
+ if stack.size == 0 # Very last one
76
+ html << render(:partial => 'admin/menu_items/actions') if options[:form]
77
+ html << (capture(&block) || '') if block_given? && !options[:form]
78
+ html << '</ul>'
79
+ elsif item.leaf? == false
80
+ html << '</ul></li>'
81
+ end
82
+ end
83
+
84
+ html.html_safe
85
+ end
86
+
87
+ private
88
+
89
+ # This is where we actually build out an li item
90
+ def render_menu_item(item, caret, options)
91
+ html = ""
92
+
93
+ url = (
94
+ if item.menuable.kind_of?(Effective::Page)
95
+ effective_pages.page_path(item.menuable)
96
+ elsif item.divider?
97
+ nil
98
+ elsif (item.special || '').end_with?('_path')
99
+ self.send(item.special) rescue nil
100
+ elsif item.url.present?
101
+ item.url
102
+ end
103
+ ).presence || '#'
104
+
105
+ classes = (item.classes || '').split(' ')
106
+ classes << 'active' if EffectivePages.menu[:apply_active_class] && request.try(:fullpath) == url
107
+ classes << 'divider' if item.divider?
108
+ classes << 'dropdown' if item.dropdown?
109
+ classes = classes.join(' ')
110
+
111
+ if item.leaf?
112
+ html << (classes.present? ? "<li class='#{classes}'>" : "<li>")
113
+
114
+ if !item.divider? || options[:form] # Show the URL in edit mode, but not normally
115
+ html << render_menu_item_anchor_tag(item, caret, url)
116
+ end
117
+
118
+ if options[:form]
119
+ html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] })
120
+ end
121
+
122
+ html << "</li>"
123
+ else
124
+ html << (classes.present? ? "<li class='#{classes}'>" : "<li>")
125
+ html << render_menu_item_anchor_tag(item, caret, url)
126
+
127
+ if options[:form]
128
+ html << render(:partial => 'admin/menu_items/item', :locals => { :item => item, :form => options[:form] })
129
+ end
130
+ end
131
+
132
+ html
133
+ end
134
+
135
+ def render_menu_item_anchor_tag(item, caret, url)
136
+ new_window_html = (item.new_window? ? " target='_blank'" : "")
137
+
138
+ if item.special == 'destroy_user_session_path'
139
+ "<a href='#{url}' data-method='delete' data-no-turbolink='true'>#{item.title}</a>"
140
+ elsif item.dropdown?
141
+ ''.tap do |html|
142
+ html << "<a href='#{url}' data-toggle='dropdown'#{new_window_html}>#{item.title}"
143
+ html << "<span class='caret'></span>" if caret
144
+ html << "</a>"
145
+ end
146
+ else
147
+ "<a href='#{url}'#{new_window_html}>#{item.title}</a>"
148
+ end
149
+ end
150
+
151
+ end