effective_pages 0.8.0

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 (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