jakewendt-simply_pages 2.0.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 (28) hide show
  1. data/README.rdoc +65 -0
  2. data/generators/simply_pages/USAGE +0 -0
  3. data/generators/simply_pages/simply_pages_generator.rb +120 -0
  4. data/generators/simply_pages/templates/autotest_simply_pages.rb +2 -0
  5. data/generators/simply_pages/templates/controllers/locales_controller.rb +16 -0
  6. data/generators/simply_pages/templates/controllers/pages_controller.rb +160 -0
  7. data/generators/simply_pages/templates/functional/locales_controller_test.rb +58 -0
  8. data/generators/simply_pages/templates/functional/pages_controller_test.rb +237 -0
  9. data/generators/simply_pages/templates/images/drag.gif +0 -0
  10. data/generators/simply_pages/templates/javascripts/pages.js +48 -0
  11. data/generators/simply_pages/templates/migrations/create_pages.rb +26 -0
  12. data/generators/simply_pages/templates/models/page.rb +107 -0
  13. data/generators/simply_pages/templates/models/page_sweeper.rb +74 -0
  14. data/generators/simply_pages/templates/simply_pages.rake +5 -0
  15. data/generators/simply_pages/templates/stylesheets/page.css +17 -0
  16. data/generators/simply_pages/templates/stylesheets/pages.css +22 -0
  17. data/generators/simply_pages/templates/unit/page_test.rb +149 -0
  18. data/generators/simply_pages/templates/unit/redcloth_extension_test.rb +64 -0
  19. data/generators/simply_pages/templates/views/pages/_child.html.erb +20 -0
  20. data/generators/simply_pages/templates/views/pages/_form.html.erb +44 -0
  21. data/generators/simply_pages/templates/views/pages/_page.html.erb +34 -0
  22. data/generators/simply_pages/templates/views/pages/all.html.erb +39 -0
  23. data/generators/simply_pages/templates/views/pages/edit.html.erb +10 -0
  24. data/generators/simply_pages/templates/views/pages/index.html.erb +29 -0
  25. data/generators/simply_pages/templates/views/pages/new.html.erb +10 -0
  26. data/generators/simply_pages/templates/views/pages/show.html.erb +31 -0
  27. data/generators/simply_pages/templates/views/pages/translate.js.erb +42 -0
  28. metadata +93 -0
@@ -0,0 +1,48 @@
1
+ var initial_page_order;
2
+ jQuery(function(){
3
+ jQuery('#pages').sortable({
4
+ axis:'y',
5
+ dropOnEmpty:false,
6
+ handle:'img.handle',
7
+ update:function(event,ui){compare_page_order()},
8
+ items:'tr.page.row'
9
+ });
10
+
11
+ jQuery('#save_order').disable();
12
+
13
+ initial_page_order = page_order();
14
+
15
+ jQuery('form#order_pages').submit(function(){
16
+ if( initial_page_order == page_order() ) {
17
+ /*
18
+ Shouldn't get here as button should
19
+ be disabled if not different!
20
+ */
21
+ alert("Page order hasn't changed. Nothing to save.");
22
+ return false
23
+ } else {
24
+ new_action = jQuery(this).attr('action');
25
+ if( (/\?/).test(new_action) ){
26
+ new_action += '&';
27
+ } else {
28
+ new_action += '?';
29
+ }
30
+ new_action += page_order();
31
+ jQuery(this).attr('action',new_action);
32
+ }
33
+ })
34
+
35
+ });
36
+
37
+ function page_order() {
38
+ return jQuery('#pages').sortable('serialize',{key:'pages[]'});
39
+ }
40
+
41
+ function compare_page_order(){
42
+ if( initial_page_order == page_order() ) {
43
+ jQuery('#save_order').disable();
44
+ } else {
45
+ jQuery('#save_order').highlight(4000);
46
+ jQuery('#save_order').enable();
47
+ }
48
+ }
@@ -0,0 +1,26 @@
1
+ class CreatePages < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :pages do |t|
4
+ t.integer :position
5
+ t.integer :parent_id
6
+ t.boolean :hide_menu, :default => false
7
+ t.string :path
8
+ t.string :title_en
9
+ t.string :title_es
10
+ t.string :menu_en
11
+ t.string :menu_es
12
+ t.text :body_en
13
+ t.text :body_es
14
+ t.timestamps
15
+ end
16
+ add_index :pages, :path, :unique => true
17
+ add_index :pages, :parent_id
18
+ # acts_as_list doesn't like the uniqueness
19
+ # when it reorders, positions are temporarily not unique
20
+ # add_index :pages, :position, :unique => true, :name => 'by_position'
21
+ end
22
+
23
+ def self.down
24
+ drop_table :pages
25
+ end
26
+ end
@@ -0,0 +1,107 @@
1
+ # == requires
2
+ # * path ( unique, > 1 char and starts with a / )
3
+ # * menu ( unique and > 3 chars )
4
+ # * title ( > 3 chars )
5
+ # * body ( > 3 chars )
6
+ #
7
+ # == named_scope(s)
8
+ # * not_home (returns those pages where path is not just '/')
9
+ # * roots
10
+ #
11
+ # uses acts_as_list for parent / child relationship. As this
12
+ # is only a parent and child and no deeper, its ok. If it
13
+ # were to get any deeper, the list should probably be changed
14
+ # to something like a nested set.
15
+ class Page < ActiveRecord::Base
16
+ default_scope :order => :position
17
+
18
+ acts_as_list :scope => :parent_id
19
+ # acts_as_list :scope => "parent_id \#{(parent_id.nil?)?'IS NULL':'= parent_id'} AND locale = '\#{locale}'"
20
+
21
+ validates_presence_of :path
22
+ validates_length_of :path, :minimum => 1
23
+ validates_format_of :path, :with => /^\//
24
+ # validates_presence_of :menu_en
25
+ validates_length_of :menu_en, :minimum => 4
26
+ # validates_presence_of :title_en
27
+ validates_length_of :title_en, :minimum => 4
28
+ # validates_presence_of :body_en
29
+ validates_length_of :body_en, :minimum => 4
30
+ validates_uniqueness_of :menu_en
31
+ validates_uniqueness_of :path
32
+
33
+ belongs_to :parent, :class_name => 'Page'
34
+ has_many :children, :class_name => 'Page', :foreign_key => 'parent_id',
35
+ :dependent => :nullify
36
+
37
+ named_scope :roots, :conditions => {
38
+ :parent_id => nil, :hide_menu => false }
39
+
40
+ named_scope :hidden, :conditions => {
41
+ :hide_menu => true }
42
+
43
+ named_scope :not_home, :conditions => [ "path != '/'" ]
44
+
45
+ attr_accessible :path, :parent_id, :hide_menu,
46
+ :menu, :menu_en, :menu_es,
47
+ :title, :title_en, :title_es,
48
+ :body, :body_en, :body_es
49
+
50
+ before_validation :adjust_path
51
+
52
+ def to_s
53
+ title
54
+ end
55
+
56
+ def adjust_path
57
+ unless self.path.nil?
58
+ # remove any duplicate /'s
59
+ # self.path = path.gsub(/\/+/,'/')
60
+ self.path.gsub!(/\/+/,'/')
61
+
62
+ # add leading / if none
63
+ # self.path = path.downcase
64
+ self.path.downcase!
65
+ end
66
+ end
67
+
68
+ # named_scopes ALWAYS return an "Array"
69
+ # so if ONLY want one, MUST use a method.
70
+ # by_path returns the one(max) page that
71
+ # matches the given path.
72
+ def self.by_path(path)
73
+ page = find(:first,
74
+ :conditions => {
75
+ :path => path.downcase
76
+ }
77
+ )
78
+ end
79
+
80
+ def root
81
+ page = self
82
+ until page.parent == nil
83
+ page = page.parent
84
+ end
85
+ page
86
+ end
87
+
88
+ def is_home?
89
+ self.path == "/"
90
+ end
91
+
92
+ # Virtual attributes
93
+ %w( menu title body ).each do |attr|
94
+ define_method "#{attr}" do |*args|
95
+ r = send("#{attr}_#{args[0]||'en'}")
96
+ (r.blank?) ? send("#{attr}_en") : r
97
+ end
98
+ define_method "#{attr}=" do |new_val|
99
+ self.send("#{attr}_en=",new_val)
100
+ end
101
+ # attr_accessible attr.to_sym
102
+ # %w( en es ).each do |lang|
103
+ # attr_accessible "#{attr}_#{lang}".to_sym
104
+ # end
105
+ end
106
+
107
+ end
@@ -0,0 +1,74 @@
1
+ # While sweepers are model observers, they only seem
2
+ # to be so within the scope of a given controller.
3
+ # If the 'cache_sweeper' line is not given in the
4
+ # controller, these observers don't see it.
5
+ # In addition, saving or destroying a page outside
6
+ # of the scope of the controller (ie. from console)
7
+ # will also go unnoticed.
8
+ #
9
+ # Interestingly, in unit/model testing, this fails
10
+ # as request is nil. This means that I don't quite
11
+ # understand how this works. Perhaps because the cache
12
+ # is in memory and not a file, the server and console
13
+ # are completely separate. Destroying in the console
14
+ # doesn't effect the server's cache. That makes sense.
15
+ # So then. How to get the host_with_port without a
16
+ # request then?
17
+ class PageSweeper < ActionController::Caching::Sweeper
18
+ observe Page
19
+
20
+ # After saving (creating or updating) a page,
21
+ # expire any associated caches.
22
+ def after_save(page)
23
+ expire_cache(page)
24
+ end
25
+
26
+ # After destroying a page, expire any associated
27
+ # caches.
28
+ def after_destroy(page)
29
+ expire_cache(page)
30
+ end
31
+
32
+ # Always expire the menu cache. This may not
33
+ # be necessary as it only relies on the menu,
34
+ # path and position attributes which may have
35
+ # remained unchanged. Also expire the "show"
36
+ # action cache. As the pages are rarely accessed
37
+ # via /pages/:id, we need to expire the special
38
+ # routes used by the catch-all route. In the
39
+ # real world, this works just fine, but in testing
40
+ # the app tries to expire cache when in unit tests
41
+ # as well as functional tests. There is no
42
+ # "request" in a unit test causing failure and
43
+ # my usage of ".try"
44
+ def expire_cache(page)
45
+ # Please note that the "views/" prefix is
46
+ # internal to rails. Don't meddle with it.
47
+
48
+ # Expired fragment: views/page_menu (0.0ms)
49
+ expire_fragment 'page_menu'
50
+
51
+ # We don't really access the pages via :id
52
+ # but they can be so we need to deal with the cache.
53
+ # Expired fragment: views/dev.sph.berkeley.edu:3000/pages/1 (0.0ms)
54
+ # Expired fragment: views/dev.sph.berkeley.edu:3000/pages/5 (0.0ms)
55
+ expire_action
56
+
57
+ # Expired fragment: views/dev.sph.berkeley.edu:3000/alpha (0.0ms)
58
+ # Expired fragment: views/dev.sph.berkeley.edu:3000/ (0.0ms)
59
+ # This fails for the home page as "/" is
60
+ # called "index" by the server
61
+ # NEEDS to change page.path to /index for home page
62
+ # be views/dev.sph.berkeley.edu:3000/index !
63
+ page_path = ( page.path == "/" ) ? "/index" : page.path
64
+ # expire_fragment "#{request.host_with_port}#{page_path}"
65
+ expire_fragment "#{request.try(:host_with_port)}#{page_path}"
66
+
67
+ # In production, the page caches weren't expiring
68
+ # Adding the relative_url_root should fix it.
69
+ page_path = ActionController::Base.relative_url_root.to_s + page_path
70
+ expire_fragment "#{request.try(:host_with_port)}#{page_path}"
71
+
72
+ end
73
+
74
+ end
@@ -0,0 +1,5 @@
1
+ # From `script/generate simply_pages` ...
2
+ unless Gem.source_index.find_name('jakewendt-simply_pages').empty?
3
+ gem 'jakewendt-simply_pages'
4
+ require 'simply_pages/test_tasks'
5
+ end
@@ -0,0 +1,17 @@
1
+ input[type='text'],
2
+ textarea {
3
+ width: 99%;
4
+ }
5
+
6
+ div.parent {
7
+ float:left;
8
+ }
9
+ div.locale {
10
+ float:left;
11
+ }
12
+ div.hide_menu {
13
+ float:right;
14
+ }
15
+ div.fields {
16
+ clear:left;
17
+ }
@@ -0,0 +1,22 @@
1
+ .page img.handle {
2
+ }
3
+ .page .position {
4
+ font-weight:bold;
5
+ text-align:center;
6
+ }
7
+ .page .path {
8
+ width: 140px;
9
+ }
10
+ .page .menu {
11
+ width: 140px;
12
+ }
13
+ .page .title {
14
+ width: 140px;
15
+ }
16
+ .page .manage {
17
+ text-align:right;
18
+ }
19
+
20
+ .page.row.ui-sortable-helper {
21
+ border: 1px dashed #E7C254;
22
+ }
@@ -0,0 +1,149 @@
1
+ require 'test_helper'
2
+
3
+ class PageTest < ActiveSupport::TestCase
4
+
5
+ assert_should_require(:path,:menu_en,:title_en,:body_en)
6
+ assert_should_require_unique(:path,:menu_en)
7
+ assert_should_require_attribute_length(:path,:minimum => 1)
8
+ assert_should_require_attribute_length(:menu_en,:title_en,:body_en,
9
+ :minimum => 4)
10
+
11
+ test "should create page" do
12
+ assert_difference 'Page.count' do
13
+ page = create_page
14
+ assert !page.new_record?,
15
+ "#{page.errors.full_messages.to_sentence}"
16
+ end
17
+ end
18
+
19
+ test "should require path begin with slash" do
20
+ assert_no_difference 'Page.count' do
21
+ page = create_page(:path => 'Hey')
22
+ assert page.errors.on(:path)
23
+ end
24
+ end
25
+
26
+ test "should filter out multiple continguous slashes" do
27
+ page = create_page(:path => "///a//b///c" )
28
+ assert_equal "/a/b/c", page.path
29
+ end
30
+
31
+ test "should downcase path" do
32
+ page = create_page(:path => "/A/B/C")
33
+ assert_equal "/a/b/c", page.path
34
+ end
35
+
36
+ test "can have a parent" do
37
+ parent = create_page
38
+ page = create_page( :parent_id => parent.id )
39
+ assert_equal page.reload.parent, parent
40
+ end
41
+
42
+ test "should return self as root with no parent" do
43
+ page = create_page
44
+ assert_equal page, page.root
45
+ end
46
+
47
+ test "should return parent as root with parent" do
48
+ parent = create_page
49
+ page = create_page( :parent_id => parent.id )
50
+ assert_equal parent, page.reload.root
51
+ end
52
+
53
+ test "should nullify parent_id of children when parent destroyed" do
54
+ parent = create_page
55
+ child = create_page( :parent_id => parent.id )
56
+ assert_equal child.reload.parent_id, parent.id
57
+ parent.destroy
58
+ assert_nil child.reload.parent_id
59
+ end
60
+
61
+ test "should return false if page is not home" do
62
+ page = create_page
63
+ assert !page.is_home?
64
+ end
65
+
66
+ test "should return true if page is home" do
67
+ page = create_page(:path => '/')
68
+ assert page.is_home?
69
+ end
70
+
71
+ test "should create page with hide_menu true" do
72
+ assert_difference('Page.count',1){
73
+ assert_difference('Page.roots.count',0){
74
+ page = create_page(:hide_menu => true)
75
+ # assert_equal 1, Page.count
76
+ # assert_equal 0, Page.roots.count
77
+ assert_not_nil Page.find(page)
78
+ assert_not_nil Page.find(page.id)
79
+ assert_not_nil Page.find_by_path(page.path)
80
+ } }
81
+ end
82
+
83
+ test "should find page by path" do
84
+ p = create_page
85
+ page = Page.by_path(p.path)
86
+ assert_equal p, page
87
+ end
88
+
89
+ test "should return english menu without locale" do
90
+ p = create_page
91
+ assert_equal p.menu, p.menu_en
92
+ end
93
+
94
+ test "should return english title without locale" do
95
+ p = create_page
96
+ assert_equal p.title, p.title_en
97
+ end
98
+
99
+ test "should return english body without locale" do
100
+ p = create_page
101
+ assert_equal p.body, p.body_en
102
+ end
103
+
104
+ test "should return english menu with locale" do
105
+ p = create_page
106
+ assert_equal p.menu('en'), p.menu_en
107
+ end
108
+
109
+ test "should return english title with locale" do
110
+ p = create_page
111
+ assert_equal p.title('en'), p.title_en
112
+ end
113
+
114
+ test "should return english body with locale" do
115
+ p = create_page
116
+ assert_equal p.body('en'), p.body_en
117
+ end
118
+
119
+ test "should return spanish menu with locale" do
120
+ p = create_page(:menu_es => 'spanish menu')
121
+ assert_equal p.menu('es'), p.menu_es
122
+ end
123
+
124
+ test "should return spanish title with locale" do
125
+ p = create_page(:title_es => 'spanish title')
126
+ assert_equal p.title('es'), p.title_es
127
+ end
128
+
129
+ test "should return spanish body with locale" do
130
+ p = create_page(:body_es => 'spanish body')
131
+ assert_equal p.body('es'), p.body_es
132
+ end
133
+
134
+ test "should return english menu with missing spanish locale" do
135
+ p = create_page(:menu_es => '')
136
+ assert_equal p.menu('es'), p.menu_en
137
+ end
138
+
139
+ test "should return english title with missing spanish locale" do
140
+ p = create_page(:title_es => '')
141
+ assert_equal p.title('es'), p.title_en
142
+ end
143
+
144
+ test "should return english body with missing spanish locale" do
145
+ p = create_page(:body_es => '')
146
+ assert_equal p.body('es'), p.body_en
147
+ end
148
+
149
+ end