merb-admin 0.4.3

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 (129) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +58 -0
  3. data/Rakefile +64 -0
  4. data/app/controllers/application.rb +6 -0
  5. data/app/controllers/main.rb +145 -0
  6. data/app/helpers/application_helper.rb +64 -0
  7. data/app/helpers/main_helper.rb +122 -0
  8. data/app/views/layout/_message.html.erb +10 -0
  9. data/app/views/layout/dashboard.html.erb +34 -0
  10. data/app/views/layout/form.html.erb +48 -0
  11. data/app/views/layout/list.html.erb +42 -0
  12. data/app/views/main/_belongs_to.html.erb +29 -0
  13. data/app/views/main/_big_decimal.html.erb +12 -0
  14. data/app/views/main/_boolean.html.erb +7 -0
  15. data/app/views/main/_date.html.erb +12 -0
  16. data/app/views/main/_datetime.html.erb +12 -0
  17. data/app/views/main/_float.html.erb +12 -0
  18. data/app/views/main/_has_many.html.erb +16 -0
  19. data/app/views/main/_has_one.html.erb +30 -0
  20. data/app/views/main/_integer.html.erb +18 -0
  21. data/app/views/main/_properties.html.erb +18 -0
  22. data/app/views/main/_string.html.erb +12 -0
  23. data/app/views/main/_text.html.erb +11 -0
  24. data/app/views/main/_time.html.erb +12 -0
  25. data/app/views/main/_timestamp.html.erb +12 -0
  26. data/app/views/main/delete.html.erb +12 -0
  27. data/app/views/main/edit.html.erb +25 -0
  28. data/app/views/main/index.html.erb +22 -0
  29. data/app/views/main/list.html.erb +72 -0
  30. data/app/views/main/new.html.erb +22 -0
  31. data/lib/abstract_model.rb +67 -0
  32. data/lib/activerecord_support.rb +169 -0
  33. data/lib/datamapper_support.rb +157 -0
  34. data/lib/generic_support.rb +17 -0
  35. data/lib/merb-admin/merbtasks.rb +103 -0
  36. data/lib/merb-admin/slicetasks.rb +20 -0
  37. data/lib/merb-admin/spectasks.rb +53 -0
  38. data/lib/merb-admin.rb +99 -0
  39. data/public/images/arrow-down.gif +0 -0
  40. data/public/images/arrow-up.gif +0 -0
  41. data/public/images/changelist-bg.gif +0 -0
  42. data/public/images/changelist-bg_rtl.gif +0 -0
  43. data/public/images/chooser-bg.gif +0 -0
  44. data/public/images/chooser_stacked-bg.gif +0 -0
  45. data/public/images/default-bg-reverse.gif +0 -0
  46. data/public/images/default-bg.gif +0 -0
  47. data/public/images/deleted-overlay.gif +0 -0
  48. data/public/images/icon-no.gif +0 -0
  49. data/public/images/icon-unknown.gif +0 -0
  50. data/public/images/icon-yes.gif +0 -0
  51. data/public/images/icon_addlink.gif +0 -0
  52. data/public/images/icon_alert.gif +0 -0
  53. data/public/images/icon_calendar.gif +0 -0
  54. data/public/images/icon_changelink.gif +0 -0
  55. data/public/images/icon_clock.gif +0 -0
  56. data/public/images/icon_deletelink.gif +0 -0
  57. data/public/images/icon_error.gif +0 -0
  58. data/public/images/icon_searchbox.png +0 -0
  59. data/public/images/icon_success.gif +0 -0
  60. data/public/images/inline-delete-8bit.png +0 -0
  61. data/public/images/inline-delete.png +0 -0
  62. data/public/images/inline-restore-8bit.png +0 -0
  63. data/public/images/inline-restore.png +0 -0
  64. data/public/images/inline-splitter-bg.gif +0 -0
  65. data/public/images/nav-bg-grabber.gif +0 -0
  66. data/public/images/nav-bg-reverse.gif +0 -0
  67. data/public/images/nav-bg.gif +0 -0
  68. data/public/images/selector-add.gif +0 -0
  69. data/public/images/selector-addall.gif +0 -0
  70. data/public/images/selector-remove.gif +0 -0
  71. data/public/images/selector-removeall.gif +0 -0
  72. data/public/images/selector-search.gif +0 -0
  73. data/public/images/selector_stacked-add.gif +0 -0
  74. data/public/images/selector_stacked-remove.gif +0 -0
  75. data/public/images/tool-left.gif +0 -0
  76. data/public/images/tool-left_over.gif +0 -0
  77. data/public/images/tool-right.gif +0 -0
  78. data/public/images/tool-right_over.gif +0 -0
  79. data/public/images/tooltag-add.gif +0 -0
  80. data/public/images/tooltag-add_over.gif +0 -0
  81. data/public/images/tooltag-arrowright.gif +0 -0
  82. data/public/images/tooltag-arrowright_over.gif +0 -0
  83. data/public/javascripts/CollapsedFieldsets.js +85 -0
  84. data/public/javascripts/DateTimeShortcuts.js +255 -0
  85. data/public/javascripts/RelatedObjectLookups.js +96 -0
  86. data/public/javascripts/SelectBox.js +111 -0
  87. data/public/javascripts/SelectFilter2.js +113 -0
  88. data/public/javascripts/actions.js +39 -0
  89. data/public/javascripts/calendar.js +143 -0
  90. data/public/javascripts/core.js +176 -0
  91. data/public/javascripts/dateparse.js +233 -0
  92. data/public/javascripts/getElementsBySelector.js +167 -0
  93. data/public/javascripts/i18n.js +33 -0
  94. data/public/javascripts/master.js +0 -0
  95. data/public/javascripts/ordering.js +137 -0
  96. data/public/javascripts/timeparse.js +94 -0
  97. data/public/javascripts/urlify.js +140 -0
  98. data/public/stylesheets/base.css +746 -0
  99. data/public/stylesheets/changelists.css +269 -0
  100. data/public/stylesheets/dashboard.css +24 -0
  101. data/public/stylesheets/forms.css +327 -0
  102. data/public/stylesheets/global.css +142 -0
  103. data/public/stylesheets/ie.css +51 -0
  104. data/public/stylesheets/layout.css +29 -0
  105. data/public/stylesheets/login.css +54 -0
  106. data/public/stylesheets/master.css +2 -0
  107. data/public/stylesheets/null.css +1 -0
  108. data/public/stylesheets/patch-iewin.css +8 -0
  109. data/public/stylesheets/rtl.css +206 -0
  110. data/public/stylesheets/widgets.css +506 -0
  111. data/schema/migrations/001_create_divisions_migration.rb +15 -0
  112. data/schema/migrations/002_create_drafts_migration.rb +21 -0
  113. data/schema/migrations/003_create_leagues_migration.rb +13 -0
  114. data/schema/migrations/004_create_players_migration.rb +23 -0
  115. data/schema/migrations/005_create_teams_migration.rb +18 -0
  116. data/spec/controllers/main_spec.rb +25 -0
  117. data/spec/models/activerecord/division.rb +8 -0
  118. data/spec/models/activerecord/draft.rb +16 -0
  119. data/spec/models/activerecord/league.rb +6 -0
  120. data/spec/models/activerecord/player.rb +10 -0
  121. data/spec/models/activerecord/team.rb +11 -0
  122. data/spec/models/datamapper/division.rb +12 -0
  123. data/spec/models/datamapper/draft.rb +18 -0
  124. data/spec/models/datamapper/league.rb +11 -0
  125. data/spec/models/datamapper/player.rb +21 -0
  126. data/spec/models/datamapper/team.rb +15 -0
  127. data/spec/requests/main_spec.rb +475 -0
  128. data/spec/spec_helper.rb +112 -0
  129. metadata +209 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Erik Michaels-Ober
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.markdown ADDED
@@ -0,0 +1,58 @@
1
+ # MerbAdmin
2
+
3
+ **MerbAdmin is a Merb plugin that provides an easy-to-use interface for managing your data.**
4
+
5
+ It currently offers the features listed [here](http://sferik.tadalist.com/lists/1352791/public).
6
+
7
+ ## Get it
8
+
9
+ At the command prompt, type:
10
+
11
+ sudo gem install sferik-merb-admin -s http://gems.github.com
12
+
13
+ ## Install it
14
+
15
+ In your app, add the following dependency to `config/dependencies.rb`:
16
+
17
+ dependency "sferik-merb-admin", "0.4.3", :require_as => "merb-admin"
18
+
19
+ Add the following route to `config/router.rb`:
20
+
21
+ add_slice(:merb_admin, :name_prefix => nil, :path_prefix => "admin", :default_routes => false)
22
+
23
+ Then, run the following rake task:
24
+
25
+ rake slices:merb-admin:install
26
+
27
+ ## Configure it (optional)
28
+
29
+ If you're feeling crafty, you can set a couple configuration options in `config/init.rb`:
30
+
31
+ Merb::BootLoader.before_app_loads do
32
+ Merb::Slices::config[:merb_admin][:app_name] = "My App"
33
+ Merb::Slices::config[:merb_admin][:per_page] = 100
34
+ end
35
+
36
+ ## Run it
37
+
38
+ Start the server:
39
+
40
+ merb
41
+
42
+ You should now be able to administer your site at [http://localhost:4000/admin](http://localhost:4000/admin).
43
+
44
+ Please report any problems you encounter to <sferik@gmail.com> or [@sferik](http://twitter.com/home/?status=@sferik%20) on Twitter.
45
+
46
+ ## WARNING
47
+
48
+ MerbAdmin does not implement any authorization scheme. Make sure to apply authorization logic before deploying to production!
49
+
50
+ ## Acknowledgements
51
+
52
+ Many thanks to:
53
+
54
+ * [Wilson Miner](http://www.wilsonminer.com) for contributing the stylesheets and javascripts from [Django](http://www.djangoproject.com)
55
+ * [Aaron Wheeler](http://fightinjoe.com/) for contributing libraries from [Merb AutoScaffold](http://github.com/fightinjoe/merb-autoscaffold)
56
+ * [Lori Holden](http://loriholden.com/) for contributing the [merb-pagination](http://github.com/lholden/merb-pagination) helper
57
+
58
+ Also, thanks to [beer](http://www.21st-amendment.com).
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require "rubygems"
2
+ require "rake/gempackagetask"
3
+
4
+ require "merb-core"
5
+ require "merb-core/tasks/merb"
6
+
7
+ GEM_NAME = "merb-admin"
8
+ AUTHOR = "Erik Michaels-Ober"
9
+ EMAIL = "sferik@gmail.com"
10
+ HOMEPAGE = "http://twitter.com/sferik"
11
+ SUMMARY = "MerbAdmin is a Merb plugin that provides an easy-to-use interface for managing your data."
12
+ GEM_VERSION = "0.4.3"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.rubyforge_project = "merb"
16
+ s.name = GEM_NAME
17
+ s.version = GEM_VERSION
18
+ s.platform = Gem::Platform::RUBY
19
+ s.has_rdoc = false
20
+ s.extra_rdoc_files = ["README.markdown", "LICENSE"]
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+ s.add_dependency("merb-slices", ">= 1.0.12")
27
+ s.add_dependency("builder", ">= 2.1.2")
28
+ s.require_path = "lib"
29
+ s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{app,lib,public,schema,spec,stubs}/**/*")
30
+ s.post_install_message = <<-POST_INSTALL_MESSAGE
31
+ #{"*" * 80}
32
+
33
+ WARNING: MerbAdmin does not implement any authorization scheme.
34
+ Make sure to apply authorization logic before deploying to production!
35
+
36
+ #{"*" * 80}
37
+ POST_INSTALL_MESSAGE
38
+ end
39
+
40
+ Rake::GemPackageTask.new(spec) do |pkg|
41
+ pkg.gem_spec = spec
42
+ end
43
+
44
+ desc "Install the gem"
45
+ task :install do
46
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
47
+ end
48
+
49
+ desc "Uninstall the gem"
50
+ task :uninstall do
51
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
52
+ end
53
+
54
+ desc "Create a gemspec file"
55
+ task :gemspec do
56
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
57
+ file.puts spec.to_ruby
58
+ end
59
+ end
60
+
61
+ require "spec/rake/spectask"
62
+ require "merb-core/test/tasks/spectasks"
63
+ desc "Default: run spec examples"
64
+ task :default => "spec"
@@ -0,0 +1,6 @@
1
+ class MerbAdmin::Application < Merb::Controller
2
+ include Merb::MerbAdmin::MainHelper
3
+
4
+ controller_for_slice
5
+
6
+ end
@@ -0,0 +1,145 @@
1
+ require File.join( File.dirname(__FILE__), '..', '..', 'lib', 'abstract_model' )
2
+
3
+ class MerbAdmin::Main < MerbAdmin::Application
4
+ include Merb::MerbAdmin::MainHelper
5
+
6
+ before :find_models, :only => ['index']
7
+ before :find_model, :exclude => ['index']
8
+ before :find_object, :only => ['edit', 'update', 'delete', 'destroy']
9
+
10
+ def index
11
+ render(:layout => 'dashboard')
12
+ end
13
+
14
+ def list
15
+ options = {}
16
+
17
+ if params[:all]
18
+ options = {
19
+ :limit => MerbAdmin[:per_page] * 2,
20
+ }.merge(options)
21
+ @objects = @abstract_model.all(options).reverse
22
+ else
23
+ @current_page = (params[:page] || 1).to_i
24
+ options = {
25
+ :page => @current_page,
26
+ :per_page => MerbAdmin[:per_page],
27
+ }.merge(options)
28
+ @page_count, @objects = @abstract_model.paginated(options)
29
+ options.delete(:page)
30
+ options.delete(:per_page)
31
+ options.delete(:offset)
32
+ options.delete(:limit)
33
+ end
34
+
35
+ @record_count = @abstract_model.count(options)
36
+ render(:layout => 'list')
37
+ end
38
+
39
+ def new
40
+ @object = @abstract_model.new
41
+ render(:layout => 'form')
42
+ end
43
+
44
+ def edit
45
+ render(:layout => 'form')
46
+ end
47
+
48
+ def create
49
+ object = params[@abstract_model.singular_name] || {}
50
+ # Delete fields that are blank
51
+ object.each do |key, value|
52
+ object[key] = nil if value.blank?
53
+ end
54
+ has_one_associations = @abstract_model.has_one_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
55
+ has_many_associations = @abstract_model.has_many_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
56
+ @object = @abstract_model.new(object)
57
+ if @object.save && has_one_associations.each{|association, id| update_has_one_association(association, id)} && has_many_associations.each{|association, ids| update_has_many_association(association, ids)}
58
+ if params[:_continue]
59
+ redirect(url(:admin_edit, :model_name => @abstract_model.singular_name, :id => @object.id), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
60
+ elsif params[:_add_another]
61
+ redirect(url(:admin_new, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
62
+ else
63
+ redirect(url(:admin_list, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully created"})
64
+ end
65
+ else
66
+ message[:error] = "#{@abstract_model.pretty_name} failed to be created"
67
+ render(:new, :layout => 'form')
68
+ end
69
+ end
70
+
71
+ def update
72
+ object = params[@abstract_model.singular_name] || {}
73
+ # Delete fields that are blank
74
+ object.each do |key, value|
75
+ object[key] = nil if value.blank?
76
+ end
77
+ has_one_associations = @abstract_model.has_one_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
78
+ has_many_associations = @abstract_model.has_many_associations.map{|association| [association, (params[:associations] || {}).delete(association[:name])]}
79
+ if @object.update_attributes(object) && has_one_associations.each{|association, id| update_has_one_association(association, id)} && has_many_associations.each{|association, ids| update_has_many_association(association, ids)}
80
+ if params[:_continue]
81
+ redirect(url(:admin_edit, :model_name => @abstract_model.singular_name, :id => @object.id), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
82
+ elsif params[:_add_another]
83
+ redirect(url(:admin_new, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
84
+ else
85
+ redirect(url(:admin_list, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully updated"})
86
+ end
87
+ else
88
+ message[:error] = "#{@abstract_model.pretty_name} failed to be updated"
89
+ render(:edit, :layout => 'form')
90
+ end
91
+ end
92
+
93
+ def delete
94
+ render(:layout => 'form')
95
+ end
96
+
97
+ def destroy
98
+ if @object.destroy
99
+ redirect(url(:admin_list, :model_name => @abstract_model.singular_name), :message => {:notice => "#{@abstract_model.pretty_name} was successfully destroyed"})
100
+ else
101
+ raise BadRequest
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def find_models
108
+ @abstract_models = MerbAdmin::AbstractModel.all
109
+ end
110
+
111
+ def find_model
112
+ model_name = params[:model_name].camel_case
113
+ @abstract_model = MerbAdmin::AbstractModel.new(model_name)
114
+ find_properties
115
+ end
116
+
117
+ def find_properties
118
+ @properties = @abstract_model.properties
119
+ end
120
+
121
+ def find_object
122
+ @object = @abstract_model.get(params[:id])
123
+ raise NotFound unless @object
124
+ end
125
+
126
+ def update_has_one_association(association, id)
127
+ model = MerbAdmin::AbstractModel.new(association[:child_model])
128
+ if object = model.get(id)
129
+ object.update_attributes(association[:child_key].first => @object.id)
130
+ end
131
+ end
132
+
133
+ def update_has_many_association(association, ids)
134
+ # Remove all of the associated items
135
+ relationship = @object.send(association[:name])
136
+ @object.clear_association(relationship)
137
+ # Add all of the objects to the relationship
138
+ model = MerbAdmin::AbstractModel.new(association[:child_model])
139
+ for object in model.all_in(ids)
140
+ relationship << object
141
+ end
142
+ @object.save
143
+ end
144
+
145
+ end
@@ -0,0 +1,64 @@
1
+ module Merb
2
+ module MerbAdmin
3
+ module ApplicationHelper
4
+
5
+ # @param *segments<Array[#to_s]> Path segments to append.
6
+ #
7
+ # @return <String>
8
+ # A path relative to the public directory, with added segments.
9
+ def image_path(*segments)
10
+ public_path_for(:image, *segments)
11
+ end
12
+
13
+ # @param *segments<Array[#to_s]> Path segments to append.
14
+ #
15
+ # @return <String>
16
+ # A path relative to the public directory, with added segments.
17
+ def javascript_path(*segments)
18
+ public_path_for(:javascript, *segments)
19
+ end
20
+
21
+ # @param *segments<Array[#to_s]> Path segments to append.
22
+ #
23
+ # @return <String>
24
+ # A path relative to the public directory, with added segments.
25
+ def stylesheet_path(*segments)
26
+ public_path_for(:stylesheet, *segments)
27
+ end
28
+
29
+ # Construct a path relative to the public directory
30
+ #
31
+ # @param <Symbol> The type of component.
32
+ # @param *segments<Array[#to_s]> Path segments to append.
33
+ #
34
+ # @return <String>
35
+ # A path relative to the public directory, with added segments.
36
+ def public_path_for(type, *segments)
37
+ ::MerbAdmin.public_path_for(type, *segments)
38
+ end
39
+
40
+ # Construct an app-level path.
41
+ #
42
+ # @param <Symbol> The type of component.
43
+ # @param *segments<Array[#to_s]> Path segments to append.
44
+ #
45
+ # @return <String>
46
+ # A path within the host application, with added segments.
47
+ def app_path_for(type, *segments)
48
+ ::MerbAdmin.app_path_for(type, *segments)
49
+ end
50
+
51
+ # Construct a slice-level path.
52
+ #
53
+ # @param <Symbol> The type of component.
54
+ # @param *segments<Array[#to_s]> Path segments to append.
55
+ #
56
+ # @return <String>
57
+ # A path within the slice source (Gem), with added segments.
58
+ def slice_path_for(type, *segments)
59
+ ::MerbAdmin.slice_path_for(type, *segments)
60
+ end
61
+
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,122 @@
1
+ require 'builder'
2
+ module Merb
3
+ module MerbAdmin
4
+ module MainHelper
5
+ def object_title(object)
6
+ if object.respond_to?(:name)
7
+ object.name
8
+ elsif object.respond_to?(:title)
9
+ object.title
10
+ else
11
+ "#{object.class.to_s} ##{object.id}"
12
+ end
13
+ end
14
+
15
+ # Given a page count and the current page, we generate a set of pagination
16
+ # links.
17
+ #
18
+ # * We use an inner and outer window into a list of links. For a set of
19
+ # 20 pages with the current page being 10:
20
+ # outer_window:
21
+ # 1 2 ..... 19 20
22
+ # inner_window
23
+ # 5 6 7 8 9 10 11 12 13 14
24
+ #
25
+ # This is totally adjustable, or can be turned off by giving the
26
+ # :inner_window setting a value of nil.
27
+ #
28
+ # * Options
29
+ # :left_cut_label => <em>text_for_cut</em>::
30
+ # Used when the page numbers need to be cut off to prevent the set of
31
+ # pagination links from being too long.
32
+ # Defaults to '&hellip;'
33
+ # :right_cut_label => <em>text_for_cut</em>::
34
+ # Same as :left_cut_label but for the right side of numbers.
35
+ # Defaults to '&hellip;'
36
+ # :outer_window => <em>number_of_pages</em>::
37
+ # Sets the number of pages to include in the outer 'window'
38
+ # Defaults to 2
39
+ # :inner_window => <em>number_of_pages</em>::
40
+ # Sets the number of pags to include in the inner 'window'
41
+ # Defaults to 7
42
+ # :page_param => <em>name_of_page_paramiter</em>
43
+ # Sets the name of the paramiter the paginator uses to return what
44
+ # page is being requested.
45
+ # Defaults to 'page'
46
+ # :url => <em>url_for_links</em>
47
+ # Provides the base url to use in the page navigation links.
48
+ # Defaults to ''
49
+ def paginate(current_page, page_count, options = {})
50
+ options[:left_cut_label] ||= '&hellip;'
51
+ options[:right_cut_label] ||= '&hellip;'
52
+ options[:outer_window] ||= 2
53
+ options[:inner_window] ||= 7
54
+ options[:page_param] ||= 'page'
55
+ options[:url] ||= ''
56
+
57
+ url = options.delete(:url)
58
+ url << (url.include?('?') ? '&' : '?') << options[:page_param]
59
+
60
+ pages = {
61
+ :all => (1..page_count).to_a,
62
+ :left => [],
63
+ :center => [],
64
+ :right => []
65
+ }
66
+
67
+ # Only worry about using our 'windows' if the page count is less then
68
+ # our windows combined.
69
+ if options[:inner_window].nil? || ((options[:outer_window] * 2) + options[:inner_window] + 2) >= page_count
70
+ pages[:center] = pages[:all]
71
+ else
72
+ pages[:left] = pages[:all][0, options[:outer_window]]
73
+ pages[:right] = pages[:all][page_count - options[:outer_window], options[:outer_window]]
74
+ pages[:center] = case current_page
75
+ # allow the inner 'window' to shift to right when close to the left edge
76
+ # Ex: 1 2 [3] 4 5 6 7 8 9 ... 20
77
+ when -infinity .. (options[:inner_window] / 2) + 3
78
+ pages[:all][options[:outer_window], options[:inner_window]] +
79
+ [options[:right_cut_label]]
80
+ # allow the inner 'window' to shift left when close to the right edge
81
+ # Ex: 1 2 ... 12 13 14 15 16 [17] 18 19 20
82
+ when (page_count - (options[:inner_window] / 2.0).ceil) - 1 .. infinity
83
+ [options[:left_cut_label]] +
84
+ pages[:all][page_count - options[:inner_window] - options[:outer_window], options[:inner_window]]
85
+ # Display the unshifed window
86
+ # ex: 1 2 ... 5 6 7 [8] 9 10 11 ... 19 20
87
+ else
88
+ [options[:left_cut_label]] +
89
+ pages[:all][current_page - (options[:inner_window] / 2) - 1, options[:inner_window]] +
90
+ [options[:right_cut_label]]
91
+ end
92
+ end
93
+
94
+ b = []
95
+
96
+ [pages[:left], pages[:center], pages[:right]].each do |p|
97
+ p.each do |page_number|
98
+ case page_number
99
+ when String
100
+ b << page_number
101
+ when current_page
102
+ b << Builder::XmlMarkup.new.span(page_number, :class => "this-page")
103
+ when page_count
104
+ b << Builder::XmlMarkup.new.a(page_number, :class => "end", :href => "#{url}=#{page_number}")
105
+ else
106
+ b << Builder::XmlMarkup.new.a(page_number, :href => "#{url}=#{page_number}")
107
+ end
108
+ end
109
+ end
110
+
111
+ b.join(" ")
112
+ end
113
+
114
+ private
115
+
116
+ def infinity
117
+ 1.0 / 0
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,10 @@
1
+ <% if message && message[:error] %>
2
+ <p class="errornote">
3
+ <%=h message[:error] %>
4
+ </p>
5
+ <% end %>
6
+ <% if message && message[:notice] %>
7
+ <ul class="messagelist">
8
+ <li><%=h message[:notice] %></li>
9
+ </ul>
10
+ <% end %>
@@ -0,0 +1,34 @@
1
+ <%
2
+ slice_name = "MerbAdmin" + (MerbAdmin[:app_name].blank? ? "" : " for #{MerbAdmin[:app_name]}")
3
+ page_name = "Site administration"
4
+ %>
5
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
7
+ <head>
8
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
9
+ <meta name="robots" content="NONE,NOARCHIVE" />
10
+ <title><%= page_name %> | <%= slice_name %></title>
11
+ <link href="<%= public_path_for :stylesheet, 'base.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
12
+ <link href="<%= public_path_for :stylesheet, 'dashboard.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
13
+ <!--[if lte IE 7]><link href="<%= public_path_for :stylesheet, 'ie.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" /><![endif]-->
14
+ </head>
15
+ <body class="admin-slice dashboard">
16
+ <div id="container">
17
+ <div id="header">
18
+ <div id="branding">
19
+ <h1 id="site-name">
20
+ <%= slice_name %>
21
+ </h1>
22
+ </div>
23
+ </div>
24
+ <%= partial('layout/message', :message => message) unless message.blank? -%>
25
+ <div id="content" class="colMS">
26
+ <h1>
27
+ <%= page_name %>
28
+ </h1>
29
+ <%= catch_content(:for_layout) -%>
30
+ </div>
31
+ <div id="footer"></div>
32
+ </div>
33
+ </body>
34
+ </html>
@@ -0,0 +1,48 @@
1
+ <%
2
+ slice_name = "MerbAdmin" + (MerbAdmin[:app_name].blank? ? "" : " for #{MerbAdmin[:app_name]}")
3
+ page_name = action_name.capitalize + " " + @abstract_model.pretty_name.downcase
4
+ %>
5
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
7
+ <head>
8
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
9
+ <meta name="robots" content="NONE,NOARCHIVE" />
10
+ <title><%= page_name %> | <%= slice_name %></title>
11
+ <link href="<%= public_path_for :stylesheet, 'base.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
12
+ <link href="<%= public_path_for :stylesheet, 'forms.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
13
+ <!--[if lte IE 7]><link href="<%= public_path_for :stylesheet, 'ie.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" /><![endif]-->
14
+ <script src="<%= public_path_for :javascript, 'i18n.js' %>" type="text/javascript" charset="utf-8"></script>
15
+ <script src="<%= public_path_for :javascript, 'core.js' %>" type="text/javascript" charset="utf-8"></script>
16
+ <script src="<%= public_path_for :javascript, 'RelatedObjectLookups.js' %>" type="text/javascript" charset="utf-8"></script>
17
+ <script src="<%= public_path_for :javascript, 'getElementsBySelector.js' %>" type="text/javascript" charset="utf-8"></script>
18
+ <script src="<%= public_path_for :javascript, 'actions.js' %>" type="text/javascript" charset="utf-8"></script>
19
+ <script src="<%= public_path_for :javascript, 'SelectBox.js' %>" type="text/javascript" charset="utf-8"></script>
20
+ <script src="<%= public_path_for :javascript, 'SelectFilter2.js' %>" type="text/javascript" charset="utf-8"></script>
21
+ <script src="<%= public_path_for :javascript, 'calendar.js' %>" type="text/javascript" charset="utf-8"></script>
22
+ <script src="<%= public_path_for :javascript, 'DateTimeShortcuts.js' %>" type="text/javascript" charset="utf-8"></script>
23
+ </head>
24
+ <body class="admin-slice change-form">
25
+ <div id="container">
26
+ <div id="header">
27
+ <div id="branding">
28
+ <h1 id="site-name">
29
+ <%= slice_name %>
30
+ </h1>
31
+ </div>
32
+ </div>
33
+ <div class="breadcrumbs">
34
+ <%= link_to("Home", url(:admin_dashboard)) %> &rsaquo;
35
+ <%= link_to(@abstract_model.plural_name.to_s.capitalize, url(:admin_list, :model_name => @abstract_model.singular_name)) %> &rsaquo;
36
+ <%= page_name %>
37
+ </div>
38
+ <%= partial('layout/message', :message => message) unless message.blank? -%>
39
+ <div id="content" class="colM">
40
+ <h1>
41
+ <%= page_name %>
42
+ </h1>
43
+ <%= catch_content(:for_layout) -%>
44
+ </div>
45
+ <div id="footer"></div>
46
+ </div>
47
+ </body>
48
+ </html>
@@ -0,0 +1,42 @@
1
+ <%
2
+ slice_name = "MerbAdmin" + (MerbAdmin[:app_name].blank? ? "" : " for #{MerbAdmin[:app_name]}")
3
+ page_name = "Select " + @abstract_model.pretty_name.downcase + " to edit"
4
+ %>
5
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
7
+ <head>
8
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
9
+ <meta name="robots" content="NONE,NOARCHIVE" />
10
+ <title><%= page_name %> | <%= slice_name %></title>
11
+ <link href="<%= public_path_for :stylesheet, 'base.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
12
+ <link href="<%= public_path_for :stylesheet, 'changelists.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" />
13
+ <!--[if lte IE 7]><link href="<%= public_path_for :stylesheet, 'ie.css' %>" type="text/css" charset="utf-8" rel="stylesheet" media="all" /><![endif]-->
14
+ <script src="<%= public_path_for :javascript, 'core.js' %>" type="text/javascript" charset="utf-8"></script>
15
+ <script src="<%= public_path_for :javascript, 'RelatedObjectLookups.js' %>" type="text/javascript" charset="utf-8"></script>
16
+ <script src="<%= public_path_for :javascript, 'getElementsBySelector.js' %>" type="text/javascript" charset="utf-8"></script>
17
+ <script src="<%= public_path_for :javascript, 'actions.js' %>" type="text/javascript" charset="utf-8"></script>
18
+ </head>
19
+ <body class="admin-slice change-list">
20
+ <div id="container">
21
+ <div id="header">
22
+ <div id="branding">
23
+ <h1 id="site-name">
24
+ <%= slice_name %>
25
+ </h1>
26
+ </div>
27
+ </div>
28
+ <div class="breadcrumbs">
29
+ <%= link_to("Home", url(:admin_dashboard)) %> &rsaquo;
30
+ <%= @abstract_model.plural_name.to_s.capitalize %>
31
+ </div>
32
+ <%= partial('layout/message', :message => message) unless message.blank? -%>
33
+ <div id="content" class="flex">
34
+ <h1>
35
+ <%= page_name %>
36
+ </h1>
37
+ <%= catch_content(:for_layout) -%>
38
+ </div>
39
+ <div id="footer"></div>
40
+ </div>
41
+ </body>
42
+ </html>
@@ -0,0 +1,29 @@
1
+ <%
2
+ child_key = association[:child_key].first
3
+ collection = MerbAdmin::AbstractModel.new(association[:parent_model]).all.map{|o| [o.id, object_title(o)]}.sort_by{|o| o[1]}
4
+ selected = @object.send(child_key)
5
+ label = association[:pretty_name]
6
+ required = false
7
+ @properties.each do |property|
8
+ next unless property[:name] == child_key
9
+ required = true unless property[:nullable?]
10
+ end
11
+ %>
12
+ <fieldset class="module aligned">
13
+ <h2><%= label %></h2>
14
+ <div class="<%= @object.errors[child_key] ? "form-row errors" : "form-row"%>">
15
+ <% if @object.errors[child_key] %>
16
+ <ul class="errorlist">
17
+ <% @object.errors[child_key].each do |error| %>
18
+ <li><%= error %></li>
19
+ <% end %>
20
+ </ul>
21
+ <% end %>
22
+ <div>
23
+ <%= select(child_key, :collection => collection, :include_blank => true, :selected => selected.to_s, :label => label) %>
24
+ <p class="help">
25
+ <%= required ? "Required." : "Optional." %>
26
+ </p>
27
+ </div>
28
+ </div>
29
+ </fieldset>
@@ -0,0 +1,12 @@
1
+ <%
2
+ name = property[:name]
3
+ length = property[:length]
4
+ label = property[:pretty_name]
5
+ required = !property[:nullable?] || property[:serial?]
6
+ %>
7
+ <div>
8
+ <%= text_field(name, :maxlength => length, :label => label) %>
9
+ <p class="help">
10
+ <%= required ? "Required." : "Optional." %>
11
+ </p>
12
+ </div>