jakewendt-simply_pages 2.0.0

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