padrino-admin 0.17.0 → 0.18.1

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +1 -1
  3. data/Rakefile +0 -21
  4. data/lib/padrino-admin/access_control.rb +3 -2
  5. data/lib/padrino-admin/generators/actions.rb +1 -1
  6. data/lib/padrino-admin/generators/admin_app.rb +1 -2
  7. data/lib/padrino-admin/generators/admin_page.rb +5 -0
  8. data/lib/padrino-admin/generators/orm.rb +15 -26
  9. data/lib/padrino-admin/generators/templates/account/mongoid.rb.tt +1 -1
  10. data/lib/padrino-admin/generators/templates/app/controllers/sessions.rb.tt +0 -8
  11. data/lib/padrino-admin/generators/templates/app.rb.tt +4 -2
  12. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/affix.js +63 -36
  13. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/alert.js +18 -11
  14. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/bootstrap.min.js +4 -4
  15. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/button.js +41 -23
  16. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/carousel.js +90 -49
  17. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/collapse.js +86 -44
  18. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/dropdown.js +66 -48
  19. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/modal.js +167 -52
  20. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/popover.js +33 -20
  21. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/scrollspy.js +58 -39
  22. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tab.js +55 -25
  23. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/tooltip.js +370 -92
  24. data/lib/padrino-admin/generators/templates/assets/javascripts/bootstrap/transition.js +22 -11
  25. data/lib/padrino-admin/generators/templates/assets/stylesheets/application.css +14 -0
  26. data/lib/padrino-admin/generators/templates/assets/stylesheets/bootstrap.css +6 -4
  27. data/lib/padrino-admin/generators/templates/erb/app/base/index.erb.tt +1 -1
  28. data/lib/padrino-admin/generators/templates/erb/app/sessions/new.erb.tt +0 -6
  29. data/lib/padrino-admin/generators/templates/erb/page/index.erb.tt +2 -2
  30. data/lib/padrino-admin/generators/templates/haml/app/base/index.haml.tt +1 -1
  31. data/lib/padrino-admin/generators/templates/haml/app/sessions/new.haml.tt +0 -6
  32. data/lib/padrino-admin/generators/templates/slim/app/base/index.slim.tt +1 -1
  33. data/lib/padrino-admin/generators/templates/slim/app/sessions/new.slim.tt +0 -6
  34. data/lib/padrino-admin/generators/templates/slim/page/index.slim.tt +2 -2
  35. data/lib/padrino-admin/helpers/authentication_helpers.rb +1 -1
  36. data/lib/padrino-admin/helpers/view_helpers.rb +3 -3
  37. data/lib/padrino-admin/locale/orm/pl.yml +0 -11
  38. data/lib/padrino-admin.rb +1 -1
  39. data/padrino-admin.gemspec +0 -2
  40. data/test/generators/test_account_model_generator.rb +0 -24
  41. data/test/generators/test_admin_app_generator.rb +13 -10
  42. data/test/generators/test_admin_page_generator.rb +86 -8
  43. data/test/test_admin_application.rb +22 -0
  44. metadata +8 -120
  45. data/lib/padrino-admin/bootstrap-less/alerts.less +0 -67
  46. data/lib/padrino-admin/bootstrap-less/badges.less +0 -55
  47. data/lib/padrino-admin/bootstrap-less/bootstrap.less +0 -49
  48. data/lib/padrino-admin/bootstrap-less/breadcrumbs.less +0 -26
  49. data/lib/padrino-admin/bootstrap-less/button-groups.less +0 -226
  50. data/lib/padrino-admin/bootstrap-less/buttons.less +0 -155
  51. data/lib/padrino-admin/bootstrap-less/carousel.less +0 -232
  52. data/lib/padrino-admin/bootstrap-less/close.less +0 -33
  53. data/lib/padrino-admin/bootstrap-less/code.less +0 -63
  54. data/lib/padrino-admin/bootstrap-less/component-animations.less +0 -29
  55. data/lib/padrino-admin/bootstrap-less/dropdowns.less +0 -213
  56. data/lib/padrino-admin/bootstrap-less/font-awesome/bordered-pulled.less +0 -16
  57. data/lib/padrino-admin/bootstrap-less/font-awesome/core.less +0 -12
  58. data/lib/padrino-admin/bootstrap-less/font-awesome/fixed-width.less +0 -6
  59. data/lib/padrino-admin/bootstrap-less/font-awesome/font-awesome.less +0 -17
  60. data/lib/padrino-admin/bootstrap-less/font-awesome/icons.less +0 -412
  61. data/lib/padrino-admin/bootstrap-less/font-awesome/larger.less +0 -13
  62. data/lib/padrino-admin/bootstrap-less/font-awesome/list.less +0 -19
  63. data/lib/padrino-admin/bootstrap-less/font-awesome/mixins.less +0 -20
  64. data/lib/padrino-admin/bootstrap-less/font-awesome/path.less +0 -14
  65. data/lib/padrino-admin/bootstrap-less/font-awesome/rotated-flipped.less +0 -9
  66. data/lib/padrino-admin/bootstrap-less/font-awesome/spinning.less +0 -30
  67. data/lib/padrino-admin/bootstrap-less/font-awesome/stacked.less +0 -20
  68. data/lib/padrino-admin/bootstrap-less/font-awesome/variables.less +0 -381
  69. data/lib/padrino-admin/bootstrap-less/forms.less +0 -419
  70. data/lib/padrino-admin/bootstrap-less/glyphicons.less +0 -233
  71. data/lib/padrino-admin/bootstrap-less/grid.less +0 -100
  72. data/lib/padrino-admin/bootstrap-less/input-groups.less +0 -157
  73. data/lib/padrino-admin/bootstrap-less/jumbotron.less +0 -44
  74. data/lib/padrino-admin/bootstrap-less/labels.less +0 -64
  75. data/lib/padrino-admin/bootstrap-less/list-group.less +0 -110
  76. data/lib/padrino-admin/bootstrap-less/media.less +0 -56
  77. data/lib/padrino-admin/bootstrap-less/mixins.less +0 -926
  78. data/lib/padrino-admin/bootstrap-less/modals.less +0 -138
  79. data/lib/padrino-admin/bootstrap-less/navbar.less +0 -616
  80. data/lib/padrino-admin/bootstrap-less/navs.less +0 -242
  81. data/lib/padrino-admin/bootstrap-less/normalize.less +0 -423
  82. data/lib/padrino-admin/bootstrap-less/padrino-admin.less +0 -18
  83. data/lib/padrino-admin/bootstrap-less/pager.less +0 -55
  84. data/lib/padrino-admin/bootstrap-less/pagination.less +0 -88
  85. data/lib/padrino-admin/bootstrap-less/panels.less +0 -230
  86. data/lib/padrino-admin/bootstrap-less/popovers.less +0 -133
  87. data/lib/padrino-admin/bootstrap-less/print.less +0 -101
  88. data/lib/padrino-admin/bootstrap-less/progress-bars.less +0 -80
  89. data/lib/padrino-admin/bootstrap-less/responsive-utilities.less +0 -93
  90. data/lib/padrino-admin/bootstrap-less/scaffolding.less +0 -134
  91. data/lib/padrino-admin/bootstrap-less/tables.less +0 -233
  92. data/lib/padrino-admin/bootstrap-less/theme.less +0 -247
  93. data/lib/padrino-admin/bootstrap-less/thumbnails.less +0 -36
  94. data/lib/padrino-admin/bootstrap-less/tooltip.less +0 -95
  95. data/lib/padrino-admin/bootstrap-less/type.less +0 -296
  96. data/lib/padrino-admin/bootstrap-less/utilities.less +0 -56
  97. data/lib/padrino-admin/bootstrap-less/variables.less +0 -827
  98. data/lib/padrino-admin/bootstrap-less/wells.less +0 -29
  99. data/lib/padrino-admin/generators/templates/account/dynamoid.rb.tt +0 -55
  100. data/lib/padrino-admin/generators/templates/account/minirecord.rb.tt +0 -44
  101. data/lib/padrino-admin/generators/templates/account/ohm.rb.tt +0 -70
  102. data/lib/padrino-admin/locale/orm/cs.yml +0 -12
  103. data/lib/padrino-admin/locale/orm/da.yml +0 -12
  104. data/lib/padrino-admin/locale/orm/de.yml +0 -12
  105. data/lib/padrino-admin/locale/orm/en.yml +0 -12
  106. data/lib/padrino-admin/locale/orm/es.yml +0 -12
  107. data/lib/padrino-admin/locale/orm/fr.yml +0 -12
  108. data/lib/padrino-admin/locale/orm/hu.yml +0 -12
  109. data/lib/padrino-admin/locale/orm/it.yml +0 -12
  110. data/lib/padrino-admin/locale/orm/ja.yml +0 -12
  111. data/lib/padrino-admin/locale/orm/lv.yml +0 -12
  112. data/lib/padrino-admin/locale/orm/nl.yml +0 -12
  113. data/lib/padrino-admin/locale/orm/no.yml +0 -12
  114. data/lib/padrino-admin/locale/orm/pt_br.yml +0 -12
  115. data/lib/padrino-admin/locale/orm/ro.yml +0 -12
  116. data/lib/padrino-admin/locale/orm/ru.yml +0 -12
  117. data/lib/padrino-admin/locale/orm/sv.yml +0 -12
  118. data/lib/padrino-admin/locale/orm/tr.yml +0 -12
  119. data/lib/padrino-admin/locale/orm/uk.yml +0 -12
  120. data/lib/padrino-admin/locale/orm/zh_cn.yml +0 -12
  121. data/lib/padrino-admin/locale/orm/zh_tw.yml +0 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68403b4a1ac0ebf79801d31e20efdf28626df2b7bcdad0a7c4e8de5d797083a4
4
- data.tar.gz: 2c54d74ec0ab3894b3e17316a5eef9c6fbb0ab1de7a5d53c7142fd3b8024a9e8
3
+ metadata.gz: 281388666c8cb872b46f3ce068940e8718006d27375c7a81b5281e09e8a250de
4
+ data.tar.gz: e3b4d990cc8c9d48954531eeb3234efadc0d46ab2a63fdf34cce3f1e8ce218ac
5
5
  SHA512:
6
- metadata.gz: 2790f246820f9cc250f9f652af4a70ce6485dd2b9622272cfbeb057ad7fda6e3c54959dca39d3e2751fe1f89c1c917089a62e00d2075c5a8fd239df359d9bbe7
7
- data.tar.gz: 5e9fbac977443415c373f2bba7ec3243052974512aadf5c5caa38d32be93399ac5cc65fb8cd586582c2ac6405d10879396e540d37f144d2ac650d8a4fb0f4f47
6
+ metadata.gz: 7c2b5c039a5c8716aaeb1f4e6a1aad7bf61aeee5994cb567e425a3580050d282e473e033037a603ceb85feeef1a84fcb8d0f3d056e5916d97bd2bcec54398e79
7
+ data.tar.gz: e58b0d302e3d6ff10a2ae6866e55640819512d6309e06a595138a91ee61e3ff1789abd898dfe233245d97a49dcf366d6014d5d5b8f5ba9d1723c6aa0ebbebb97
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  Padrino has a beautiful Admin management dashboard with these features:
6
6
 
7
- Orm Agnostic:: Data Adapters for Activerecord, MiniRecord, Sequel, Mongoid, Ohm, Dynamoid
7
+ Orm Agnostic:: Data Adapters for Activerecord, Sequel, Mongoid
8
8
  Template Agnostic:: Erb, Erubis and Haml Renderer
9
9
  Authentication:: Support for Account authentication, Account Permission management
10
10
  Scaffold:: You can simply create a new "admin interface" by providing a Model
data/Rakefile CHANGED
@@ -1,22 +1 @@
1
1
  require_relative '../gem_rake_helper'
2
-
3
- namespace :bootstrap do
4
- desc 'Compile bootstrap assets'
5
- task :compile do
6
- puts 'Implement'
7
- end
8
-
9
- desc 'Compile css'
10
- task :css do
11
- require 'less'
12
- src = File.join(__dir__, 'lib', 'padrino-admin', 'bootstrap-less', 'padrino-admin.less')
13
- out = File.join(__dir__, 'lib', 'padrino-admin', 'generators', 'templates', 'assets', 'stylesheets', 'bootstrap.css')
14
- css = Less::Parser.new(paths: [File.dirname(src)]).parse(File.read(src)).to_css(compress: true)
15
- File.open(out, 'w') { |file| file.write css }
16
- puts "Generated #{out}"
17
- end
18
-
19
- desc 'Compile js'
20
- task :js do
21
- end
22
- end
@@ -104,7 +104,8 @@ module Padrino
104
104
  #
105
105
  def allowed?(account = nil, path = nil)
106
106
  path = '/' if path.nil? || path.empty?
107
- path = Rack::Utils.unescape_path(path.b).force_encoding(Encoding::UTF_8) # compare the decoded path
107
+ # Compare the decoded path; scrub invalid UTF-8 ('/%ff') so Regexp rules can match it.
108
+ path = Rack::Utils.unescape_path(path.b).force_encoding(Encoding::UTF_8).scrub
108
109
  role = account.role.to_sym rescue nil
109
110
  authorizations = @authorizations.find_all { |auth| auth.roles.include?(:any) }
110
111
  allowed_paths = authorizations.map(&:allowed).flatten.uniq
@@ -187,7 +188,7 @@ module Padrino
187
188
  # Returns the name of the project module humanize them for you.
188
189
  #
189
190
  def human_name
190
- @name.to_s.humanize
191
+ Padrino::Inflections.humanize(@name)
191
192
  end
192
193
 
193
194
  ##
@@ -27,7 +27,7 @@ module Padrino
27
27
  # Tell us for now which orm we support
28
28
  #
29
29
  def supported_orm
30
- %i[minirecord activerecord mongoid sequel ohm dynamoid]
30
+ %i[activerecord mongoid sequel]
31
31
  end
32
32
 
33
33
  ##
@@ -76,7 +76,7 @@ module Padrino
76
76
  RUBY
77
77
 
78
78
  unless options[:destroy]
79
- insert_middleware 'ConnectionPoolManagement', @admin_path if %i[minirecord activerecord].include?(orm)
79
+ insert_middleware 'ConnectionPoolManagement', @admin_path if orm == :activerecord
80
80
  end
81
81
 
82
82
  params = [
@@ -150,7 +150,6 @@ module Padrino
150
150
  instructions << "Run 'bundle exec rake db:create' if you have not created a database yet"
151
151
  instructions << "Run 'bundle exec rake db:migrate'"
152
152
  end
153
- instructions << "Now repeat after me... 'ohm mani padme hum', 'ohm mani padme hum'... :)" if orm == :ohm
154
153
  instructions << "Run 'bundle exec rake db:seed'"
155
154
  instructions << "Visit the admin panel in the browser at '/#{@admin_path}'"
156
155
  instructions.map! { |i| " #{instructions.index(i) + 1}) #{i}" }
@@ -41,6 +41,11 @@ module Padrino
41
41
  def create_controller
42
42
  self.destination_root = options[:root]
43
43
  if in_app_root?
44
+ unless supported_orm.include?(orm)
45
+ say "<= At the moment, Padrino only supports #{supported_orm.join(' or ')}. Sorry!", :yellow
46
+ exit 1
47
+ end
48
+
44
49
  @app_name = fetch_app_name
45
50
  @admin_name = options[:admin_name].classify
46
51
  @admin_path = options[:admin_name].underscore
@@ -4,19 +4,17 @@ module Padrino
4
4
  # Contains all admin related generator functionality.
5
5
  #
6
6
  module Generators
7
- # Defines a generic exception for the admin ORM handler.
8
- class OrmError < StandardError; end
7
+ # Defines a generic exception for the admin ORM handler. A Thor::Error, so the
8
+ # generators print its message without a backtrace and exit with status 1.
9
+ class OrmError < Thor::Error; end
9
10
 
10
11
  ##
11
12
  # Defines the generic ORM management functions used to manipulate data for admin.
12
13
  class Orm
13
14
  MODEL_BASES = {
14
15
  activerecord: 'ActiveRecord::Base',
15
- minirecord: 'ActiveRecord::Base',
16
16
  mongoid: 'Mongoid::Document',
17
- sequel: 'Sequel::Model',
18
- ohm: 'Ohm::Model',
19
- dynamoid: 'Dynamoid::Document'
17
+ sequel: 'Sequel::Model'
20
18
  }.freeze
21
19
 
22
20
  attr_reader :klass_name, :klass, :name_plural, :name_singular, :orm, :name_param
@@ -31,13 +29,13 @@ module Padrino
31
29
  @orm = orm.to_sym
32
30
  @columns = columns
33
31
  @column_fields = column_fields
34
- raise OrmError, "Model '#{klass_name}' could not be found!\nPerhaps you would like to run 'bundle exec padrino g model #{klass_name}' to create it first?" if @columns.nil? && @klass.nil?
35
32
  end
36
33
 
37
- # Raises OrmError when the model does not belong to the project's orm. Only needed when
38
- # reading the model's columns to generate a page, so destroying a page skips it.
34
+ # Raises OrmError when the model is missing or does not belong to the project's orm. Only
35
+ # needed when reading the model's columns to generate a page, so destroying a page skips it.
39
36
  def check_model_orm
40
37
  return unless @columns.nil?
38
+ raise OrmError, "Model '#{klass_name}' could not be found!\nPerhaps you would like to run 'bundle exec padrino g model #{klass_name}' to create it first?" if @klass.nil?
41
39
 
42
40
  base = MODEL_BASES[orm]
43
41
  return if base.nil? || @klass.ancestors.any? { |mod| mod.name == base }
@@ -46,10 +44,7 @@ module Padrino
46
44
  end
47
45
 
48
46
  def activerecord?
49
- case orm
50
- when :activerecord, :minirecord then true
51
- else false
52
- end
47
+ orm == :activerecord
53
48
  end
54
49
 
55
50
  def field_type(type)
@@ -71,11 +66,8 @@ module Padrino
71
66
  @columns ||=
72
67
  case orm
73
68
  when :activerecord then @klass.columns
74
- when :minirecord then @klass.columns
75
69
  when :mongoid then @klass.fields.values.reject { |col| %w[_id _type].include?(col.name) }
76
70
  when :sequel then @klass.db_schema.map { |k, v| v[:type] = :text if v[:db_type] =~ /^text/i; Column.new(k, v[:type]) }
77
- when :ohm then @klass.attributes.map { |a| Column.new(a.to_s, :string) } # ohm has strings
78
- when :dynamoid then @klass.attributes.map { |k, v| Column.new(k.to_s, v[:type]) }
79
71
  else raise OrmError, "Adapter #{orm} is not yet supported!"
80
72
  end
81
73
  end
@@ -95,8 +87,8 @@ module Padrino
95
87
 
96
88
  def find(params = nil)
97
89
  case orm
98
- when :activerecord, :minirecord, :mongoid, :dynamoid then "#{klass_name}.find(#{params})"
99
- when :sequel, :ohm then "#{klass_name}[#{params}]"
90
+ when :activerecord, :mongoid then "#{klass_name}.find(#{params})"
91
+ when :sequel then "#{klass_name}[#{params}]"
100
92
  else raise OrmError, "Adapter #{orm} is not yet supported!"
101
93
  end
102
94
  end
@@ -115,39 +107,36 @@ module Padrino
115
107
 
116
108
  def update_attributes(params = nil)
117
109
  case orm
118
- when :mongoid, :dynamoid then "@#{name_singular}.update_attributes(#{params})"
119
- when :activerecord, :minirecord, :ohm then "@#{name_singular}.update(#{params})"
110
+ when :mongoid then "@#{name_singular}.update_attributes(#{params})"
111
+ when :activerecord then "@#{name_singular}.update(#{params})"
120
112
  when :sequel then "@#{name_singular}.modified! && @#{name_singular}.update(#{params})"
121
113
  else raise OrmError, "Adapter #{orm} is not yet supported!"
122
114
  end
123
115
  end
124
116
 
125
117
  def destroy
126
- orm == :ohm ? "#{name_singular}.delete" : "#{name_singular}.destroy"
118
+ "#{name_singular}.destroy"
127
119
  end
128
120
 
129
121
  def find_by_ids(params = nil)
130
122
  case orm
131
- when :ohm then "#{klass_name}.fetch(#{params})"
132
123
  when :sequel then "#{klass_name}.where(id: #{params})"
133
124
  when :mongoid then "#{klass_name}.find(#{params})"
134
- when :dynamoid then "#{klass_name}.find(#{params})"
135
125
  else find(params)
136
126
  end
137
127
  end
138
128
 
139
129
  def multiple_destroy(params = nil)
140
130
  case orm
141
- when :ohm then "#{params}.each(&:delete)"
142
131
  when :sequel then "#{params}.destroy"
143
- when :mongoid, :dynamoid then "#{params}.each(&:destroy)"
132
+ when :mongoid then "#{params}.each(&:destroy)"
144
133
  else "#{klass_name}.destroy #{params}"
145
134
  end
146
135
  end
147
136
 
148
137
  def has_error(field)
149
138
  case orm
150
- when :ohm, :sequel then "@#{name_singular}.errors.key?(:#{field}) && @#{name_singular}.errors[:#{field}].count > 0"
139
+ when :sequel then "@#{name_singular}.errors.key?(:#{field}) && @#{name_singular}.errors[:#{field}].count > 0"
151
140
  else "@#{name_singular}.errors.include?(:#{field})"
152
141
  end
153
142
  end
@@ -27,7 +27,7 @@ class <%= @model_name %>
27
27
  # This method is for authentication purpose.
28
28
  #
29
29
  def self.authenticate(email, password)
30
- account = where(email: /#{Object::Regexp.escape(email)}/i).first if email.present?
30
+ account = where(email: /\A#{Object::Regexp.escape(email)}\z/i).first if email.present?
31
31
  account if account&.has_password?(password)
32
32
  end
33
33
 
@@ -7,14 +7,6 @@
7
7
  if account = <%= @model_name %>.authenticate(params[:email], params[:password])
8
8
  set_current_account(account)
9
9
  redirect url(:base, :index)
10
- elsif Padrino.env == :development && params[:bypass]
11
- <%- if @orm == :ohm -%>
12
- account = <%= @model_name %>.all.first
13
- <%- else -%>
14
- account = <%= @model_name %>.first
15
- <%- end -%>
16
- set_current_account(account)
17
- redirect url(:base, :index)
18
10
  else
19
11
  params[:email] = h(params[:email])
20
12
  flash.now[:error] = pat('login.error')
@@ -26,8 +26,10 @@ module <%= @app_name %>
26
26
  set :admin_model, '<%= @model_name %>'
27
27
  set :login_page, '/sessions/new'
28
28
 
29
- set :sessions, same_site: :lax
30
- # set :sessions, same_site: :lax, secure: true # Send the session cookie over HTTPS only
29
+ # The session cookie is Secure (sent over HTTPS only) in production. Over plain HTTP
30
+ # the app then sends no session cookie, so logins and CSRF-protected forms fail. Behind
31
+ # a proxy that terminates TLS, have it send X-Forwarded-Proto: https, or set secure: false.
32
+ set :sessions, same_site: :lax, secure: Padrino.env == :production
31
33
  disable :store_location
32
34
 
33
35
  access_control.roles_for :any do |role|
@@ -1,8 +1,8 @@
1
1
  /* ========================================================================
2
- * Bootstrap: affix.js v3.1.0
3
- * http://getbootstrap.com/javascript/#affix
2
+ * Bootstrap: affix.js v3.4.1
3
+ * https://getbootstrap.com/docs/3.4/javascript/#affix
4
4
  * ========================================================================
5
- * Copyright 2011-2014 Twitter, Inc.
5
+ * Copyright 2011-2019 Twitter, Inc.
6
6
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
7
  * ======================================================================== */
8
8
 
@@ -15,28 +15,56 @@
15
15
 
16
16
  var Affix = function (element, options) {
17
17
  this.options = $.extend({}, Affix.DEFAULTS, options)
18
- this.$window = $(window)
18
+
19
+ var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
20
+
21
+ this.$target = target
19
22
  .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
20
23
  .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
21
24
 
22
25
  this.$element = $(element)
23
- this.affixed =
24
- this.unpin =
26
+ this.affixed = null
27
+ this.unpin = null
25
28
  this.pinnedOffset = null
26
29
 
27
30
  this.checkPosition()
28
31
  }
29
32
 
30
- Affix.RESET = 'affix affix-top affix-bottom'
33
+ Affix.VERSION = '3.4.1'
34
+
35
+ Affix.RESET = 'affix affix-top affix-bottom'
31
36
 
32
37
  Affix.DEFAULTS = {
33
- offset: 0
38
+ offset: 0,
39
+ target: window
40
+ }
41
+
42
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
43
+ var scrollTop = this.$target.scrollTop()
44
+ var position = this.$element.offset()
45
+ var targetHeight = this.$target.height()
46
+
47
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
48
+
49
+ if (this.affixed == 'bottom') {
50
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
51
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
52
+ }
53
+
54
+ var initializing = this.affixed == null
55
+ var colliderTop = initializing ? scrollTop : position.top
56
+ var colliderHeight = initializing ? targetHeight : height
57
+
58
+ if (offsetTop != null && scrollTop <= offsetTop) return 'top'
59
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
60
+
61
+ return false
34
62
  }
35
63
 
36
64
  Affix.prototype.getPinnedOffset = function () {
37
65
  if (this.pinnedOffset) return this.pinnedOffset
38
66
  this.$element.removeClass(Affix.RESET).addClass('affix')
39
- var scrollTop = this.$window.scrollTop()
67
+ var scrollTop = this.$target.scrollTop()
40
68
  var position = this.$element.offset()
41
69
  return (this.pinnedOffset = position.top - scrollTop)
42
70
  }
@@ -48,43 +76,41 @@
48
76
  Affix.prototype.checkPosition = function () {
49
77
  if (!this.$element.is(':visible')) return
50
78
 
51
- var scrollHeight = $(document).height()
52
- var scrollTop = this.$window.scrollTop()
53
- var position = this.$element.offset()
79
+ var height = this.$element.height()
54
80
  var offset = this.options.offset
55
81
  var offsetTop = offset.top
56
82
  var offsetBottom = offset.bottom
57
-
58
- if (this.affixed == 'top') position.top += scrollTop
83
+ var scrollHeight = Math.max($(document).height(), $(document.body).height())
59
84
 
60
85
  if (typeof offset != 'object') offsetBottom = offsetTop = offset
61
86
  if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
62
87
  if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
63
88
 
64
- var affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false :
65
- offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
66
- offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false
89
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
67
90
 
68
- if (this.affixed === affix) return
69
- if (this.unpin) this.$element.css('top', '')
91
+ if (this.affixed != affix) {
92
+ if (this.unpin != null) this.$element.css('top', '')
70
93
 
71
- var affixType = 'affix' + (affix ? '-' + affix : '')
72
- var e = $.Event(affixType + '.bs.affix')
94
+ var affixType = 'affix' + (affix ? '-' + affix : '')
95
+ var e = $.Event(affixType + '.bs.affix')
73
96
 
74
- this.$element.trigger(e)
97
+ this.$element.trigger(e)
75
98
 
76
- if (e.isDefaultPrevented()) return
99
+ if (e.isDefaultPrevented()) return
77
100
 
78
- this.affixed = affix
79
- this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
101
+ this.affixed = affix
102
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
80
103
 
81
- this.$element
82
- .removeClass(Affix.RESET)
83
- .addClass(affixType)
84
- .trigger($.Event(affixType.replace('affix', 'affixed')))
104
+ this.$element
105
+ .removeClass(Affix.RESET)
106
+ .addClass(affixType)
107
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
108
+ }
85
109
 
86
110
  if (affix == 'bottom') {
87
- this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
111
+ this.$element.offset({
112
+ top: scrollHeight - height - offsetBottom
113
+ })
88
114
  }
89
115
  }
90
116
 
@@ -92,9 +118,7 @@
92
118
  // AFFIX PLUGIN DEFINITION
93
119
  // =======================
94
120
 
95
- var old = $.fn.affix
96
-
97
- $.fn.affix = function (option) {
121
+ function Plugin(option) {
98
122
  return this.each(function () {
99
123
  var $this = $(this)
100
124
  var data = $this.data('bs.affix')
@@ -105,6 +129,9 @@
105
129
  })
106
130
  }
107
131
 
132
+ var old = $.fn.affix
133
+
134
+ $.fn.affix = Plugin
108
135
  $.fn.affix.Constructor = Affix
109
136
 
110
137
 
@@ -127,10 +154,10 @@
127
154
 
128
155
  data.offset = data.offset || {}
129
156
 
130
- if (data.offsetBottom) data.offset.bottom = data.offsetBottom
131
- if (data.offsetTop) data.offset.top = data.offsetTop
157
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
158
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
132
159
 
133
- $spy.affix(data)
160
+ Plugin.call($spy, data)
134
161
  })
135
162
  })
136
163
 
@@ -1,8 +1,8 @@
1
1
  /* ========================================================================
2
- * Bootstrap: alert.js v3.1.0
3
- * http://getbootstrap.com/javascript/#alerts
2
+ * Bootstrap: alert.js v3.4.1
3
+ * https://getbootstrap.com/docs/3.4/javascript/#alerts
4
4
  * ========================================================================
5
- * Copyright 2011-2014 Twitter, Inc.
5
+ * Copyright 2011-2019 Twitter, Inc.
6
6
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
7
7
  * ======================================================================== */
8
8
 
@@ -18,6 +18,10 @@
18
18
  $(el).on('click', dismiss, this.close)
19
19
  }
20
20
 
21
+ Alert.VERSION = '3.4.1'
22
+
23
+ Alert.TRANSITION_DURATION = 150
24
+
21
25
  Alert.prototype.close = function (e) {
22
26
  var $this = $(this)
23
27
  var selector = $this.attr('data-target')
@@ -27,12 +31,13 @@
27
31
  selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
28
32
  }
29
33
 
30
- var $parent = $(selector)
34
+ selector = selector === '#' ? [] : selector
35
+ var $parent = $(document).find(selector)
31
36
 
32
37
  if (e) e.preventDefault()
33
38
 
34
39
  if (!$parent.length) {
35
- $parent = $this.hasClass('alert') ? $this : $this.parent()
40
+ $parent = $this.closest('.alert')
36
41
  }
37
42
 
38
43
  $parent.trigger(e = $.Event('close.bs.alert'))
@@ -42,13 +47,14 @@
42
47
  $parent.removeClass('in')
43
48
 
44
49
  function removeElement() {
45
- $parent.trigger('closed.bs.alert').remove()
50
+ // detach from parent, fire event then clean up data
51
+ $parent.detach().trigger('closed.bs.alert').remove()
46
52
  }
47
53
 
48
54
  $.support.transition && $parent.hasClass('fade') ?
49
55
  $parent
50
- .one($.support.transition.end, removeElement)
51
- .emulateTransitionEnd(150) :
56
+ .one('bsTransitionEnd', removeElement)
57
+ .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
52
58
  removeElement()
53
59
  }
54
60
 
@@ -56,9 +62,7 @@
56
62
  // ALERT PLUGIN DEFINITION
57
63
  // =======================
58
64
 
59
- var old = $.fn.alert
60
-
61
- $.fn.alert = function (option) {
65
+ function Plugin(option) {
62
66
  return this.each(function () {
63
67
  var $this = $(this)
64
68
  var data = $this.data('bs.alert')
@@ -68,6 +72,9 @@
68
72
  })
69
73
  }
70
74
 
75
+ var old = $.fn.alert
76
+
77
+ $.fn.alert = Plugin
71
78
  $.fn.alert.Constructor = Alert
72
79
 
73
80