refinerycms-blog 3.0.2 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +2 -0
- data/.travis.yml +1 -3
- data/Gemfile +8 -8
- data/app/controllers/refinery/blog/admin/categories_controller.rb +2 -2
- data/app/controllers/refinery/blog/admin/posts_controller.rb +15 -12
- data/app/controllers/refinery/blog/blog_controller.rb +1 -1
- data/app/controllers/refinery/blog/posts_controller.rb +15 -13
- data/app/helpers/refinery/blog/posts_helper.rb +4 -4
- data/app/models/refinery/blog/category.rb +3 -0
- data/app/models/refinery/blog/post.rb +43 -16
- data/app/views/refinery/blog/admin/categories/_category.html.erb +4 -10
- data/app/views/refinery/blog/admin/comments/_comment.html.erb +4 -14
- data/app/views/refinery/blog/admin/posts/_form.html.erb +5 -1
- data/app/views/refinery/blog/admin/posts/_post.html.erb +7 -12
- data/app/views/refinery/blog/posts/_comment.html.erb +3 -3
- data/app/views/refinery/blog/posts/_comments.html.erb +6 -6
- data/app/views/refinery/blog/posts/_post.html.erb +7 -7
- data/app/views/refinery/blog/posts/index.rss.builder +8 -2
- data/app/views/refinery/blog/shared/_categories.html.erb +2 -2
- data/app/views/refinery/blog/shared/_post.html.erb +9 -7
- data/app/views/refinery/blog/shared/_posts.html.erb +1 -1
- data/app/views/refinery/blog/shared/_tags.html.erb +1 -1
- data/bin/rails +9 -3
- data/certs/parndt.pem +25 -0
- data/config/locales/ru.yml +1 -1
- data/config/locales/uk.yml +172 -0
- data/db/migrate/20110803223522_create_blog_structure.rb +1 -1
- data/db/migrate/20110803223523_add_user_id_to_blog_posts.rb +1 -1
- data/db/migrate/20110803223524_acts_as_taggable_on_migration.rb +1 -1
- data/db/migrate/20110803223526_add_cached_slugs.rb +1 -1
- data/db/migrate/20110803223527_add_custom_url_field_to_blog_posts.rb +1 -1
- data/db/migrate/20110803223528_add_custom_teaser_field_to_blog_posts.rb +1 -1
- data/db/migrate/20110803223529_add_primary_key_to_categorizations.rb +1 -1
- data/db/migrate/20120103055909_add_source_url_to_blog_posts.rb +2 -2
- data/db/migrate/20120223022021_add_access_count_to_posts.rb +4 -4
- data/db/migrate/20120227022021_add_slug_to_posts_and_categories.rb +2 -2
- data/db/migrate/20120530102901_create_blog_translations.rb +1 -1
- data/db/migrate/20120531113632_delete_cached_slugs.rb +1 -1
- data/db/migrate/20120601151114_create_category_translations.rb +1 -1
- data/db/migrate/20140622132537_add_missing_unique_indices.acts_as_taggable_on_engine.rb +1 -1
- data/db/migrate/20140622132538_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb +1 -1
- data/db/migrate/20160602042848_add_username_to_blog_posts.rb +5 -0
- data/db/migrate/20161223024527_create_multi_user_model.rb +13 -0
- data/db/migrate/20180420132008_remove_translated_columns_to_refinery_blog_categories.rb +5 -0
- data/lib/generators/refinery/blog/templates/config/initializers/refinery/blog.rb.erb +2 -1
- data/lib/refinery/blog.rb +2 -0
- data/lib/refinery/blog/configuration.rb +3 -3
- data/lib/refinery/blog/engine.rb +1 -0
- data/readme.md +2 -2
- data/refinerycms-blog.gemspec +15 -8
- data/spec/controllers/refinery/blog/admin/comments_controller_spec.rb +10 -14
- data/spec/controllers/refinery/blog/admin/posts_controller_spec.rb +5 -5
- data/spec/controllers/refinery/blog/posts_controller_spec.rb +4 -4
- data/spec/factories/blog_categories.rb +1 -1
- data/spec/factories/blog_comments.rb +1 -1
- data/spec/factories/blog_posts.rb +6 -2
- data/spec/factories/blog_test_users.rb +6 -0
- data/spec/features/refinery/blog/admin/categories_spec.rb +3 -3
- data/spec/features/refinery/blog/admin/comments_spec.rb +5 -5
- data/spec/features/refinery/blog/admin/menu_spec.rb +2 -2
- data/spec/features/refinery/blog/admin/posts_spec.rb +34 -20
- data/spec/features/refinery/blog/categories_spec.rb +2 -3
- data/spec/features/refinery/blog/posts_spec.rb +17 -30
- data/spec/models/refinery/blog/category_spec.rb +12 -13
- data/spec/models/refinery/blog/comment_spec.rb +1 -1
- data/spec/models/refinery/blog/post_spec.rb +38 -31
- data/spec/spec_helper.rb +1 -0
- data/spec/support/refinery_blog_test_user.rb +2 -0
- metadata +85 -33
- metadata.gz.sig +0 -0
- data/spec/factories/user.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 597f06b7bd6f17d95315443d3b2d11ff80f426dbfd173b1c3e0b89a133dde153
|
4
|
+
data.tar.gz: 44cbe39a432bef4d113972c3602bf167d844b246da4c2ac420529f54c0a492c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1106d3a7977b42bd9e89261516af147cc6c7f14f06c47c69a60591b3b23ba72146cc1d8ad54252f4c4949a7490dff2b57edadc97ba233642a58a6a5046d8f60
|
7
|
+
data.tar.gz: 87170e08784d993834f348ddd7af0ee7095de88f3eec9539e4fc1468c8649e76fdf0c4609a60eb0aa28cdb0c4012b5b06135ccacddad1e1ea5fc0c9434e31662
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
Binary file
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
@@ -1,22 +1,22 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
|
-
gem "refinerycms-authentication-devise", '~> 1.0.4'
|
4
|
-
|
5
3
|
gemspec
|
6
4
|
|
7
|
-
|
5
|
+
git "https://github.com/refinery/refinerycms", branch: "4-0-stable" do
|
6
|
+
gem 'refinerycms'
|
8
7
|
|
9
|
-
group :
|
10
|
-
|
8
|
+
group :test do
|
9
|
+
gem 'refinerycms-testing'
|
10
|
+
end
|
11
11
|
end
|
12
12
|
|
13
13
|
# Add the default visual editor, for now.
|
14
|
-
gem 'refinerycms-wymeditor', ['~>
|
14
|
+
gem 'refinerycms-wymeditor', ['~> 2.0', '>= 2.0.0']
|
15
15
|
|
16
16
|
group :test do
|
17
|
-
gem 'pry'
|
18
17
|
gem 'launchy'
|
19
18
|
gem 'poltergeist'
|
19
|
+
gem 'listen'
|
20
20
|
end
|
21
21
|
|
22
22
|
# Database Configuration
|
@@ -33,7 +33,7 @@ end
|
|
33
33
|
|
34
34
|
if !ENV['TRAVIS'] || ENV['DB'] == 'postgresql'
|
35
35
|
gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
|
36
|
-
gem 'pg', :platform => :ruby
|
36
|
+
gem 'pg', '~> 0.18', :platform => :ruby
|
37
37
|
end
|
38
38
|
|
39
39
|
# Refinery/rails should pull in the proper versions of these
|
@@ -4,8 +4,8 @@ module Refinery
|
|
4
4
|
class CategoriesController < ::Refinery::AdminController
|
5
5
|
|
6
6
|
crudify :'refinery/blog/category',
|
7
|
-
:
|
8
|
-
:
|
7
|
+
include: [:translations],
|
8
|
+
order: 'refinery_blog_category_translations.title ASC'
|
9
9
|
|
10
10
|
private
|
11
11
|
|
@@ -4,13 +4,16 @@ module Refinery
|
|
4
4
|
class PostsController < ::Refinery::AdminController
|
5
5
|
|
6
6
|
crudify :'refinery/blog/post',
|
7
|
-
:
|
8
|
-
:
|
7
|
+
order: 'published_at DESC',
|
8
|
+
include: [:translations, :author]
|
9
9
|
|
10
|
-
|
11
|
-
:
|
10
|
+
before_action :find_all_categories,
|
11
|
+
only: [:new, :edit, :create, :update]
|
12
12
|
|
13
|
-
|
13
|
+
before_action :find_all_authors,
|
14
|
+
only: [:new, :edit, :create, :update]
|
15
|
+
|
16
|
+
before_action :check_category_ids, only: :update
|
14
17
|
|
15
18
|
def uncategorized
|
16
19
|
@posts = Refinery::Blog::Post.uncategorized.page(params[:page])
|
@@ -31,10 +34,6 @@ module Refinery
|
|
31
34
|
render :json => @tags.flatten
|
32
35
|
end
|
33
36
|
|
34
|
-
def new
|
35
|
-
@post = ::Refinery::Blog::Post.new(:author => current_refinery_user)
|
36
|
-
end
|
37
|
-
|
38
37
|
def create
|
39
38
|
# if the position field exists, set this object as last object, given the conditions of this class.
|
40
39
|
if Refinery::Blog::Post.column_names.include?("position")
|
@@ -87,11 +86,11 @@ module Refinery
|
|
87
86
|
def post_params
|
88
87
|
params.require(:post).permit(permitted_post_params)
|
89
88
|
end
|
90
|
-
|
89
|
+
|
91
90
|
def permitted_post_params
|
92
91
|
[
|
93
92
|
:title, :body, :custom_teaser, :tag_list,
|
94
|
-
:draft, :published_at, :custom_url, :user_id, :browser_title,
|
93
|
+
:draft, :published_at, :custom_url, :user_id, :username, :browser_title,
|
95
94
|
:meta_description, :source_url, :source_url_title, :category_ids => []
|
96
95
|
]
|
97
96
|
end
|
@@ -99,13 +98,17 @@ module Refinery
|
|
99
98
|
protected
|
100
99
|
|
101
100
|
def find_post
|
102
|
-
@post = Refinery::Blog::Post.friendly.find(params[:id])
|
101
|
+
@post = Refinery::Blog::Post.friendly.joins(:translations).find(params[:id])
|
103
102
|
end
|
104
103
|
|
105
104
|
def find_all_categories
|
106
105
|
@categories = Refinery::Blog::Category.all
|
107
106
|
end
|
108
107
|
|
108
|
+
def find_all_authors
|
109
|
+
@authors = Refinery::Blog.user_class.all if (!Refinery::Blog.user_class.nil? && Refinery::Blog.user_class.column_names.include?('username'))
|
110
|
+
end
|
111
|
+
|
109
112
|
def check_category_ids
|
110
113
|
params[:post][:category_ids] ||= []
|
111
114
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require 'responders'
|
2
|
+
|
1
3
|
module Refinery
|
2
4
|
module Blog
|
3
5
|
class PostsController < BlogController
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
before_action :find_all_blog_posts, except: [:archive]
|
8
|
+
before_action :find_blog_post, only: [:show, :comment, :update_nav]
|
9
|
+
before_action :find_tags
|
8
10
|
|
9
11
|
respond_to :html, :js, :rss
|
10
12
|
|
@@ -19,20 +21,20 @@ module Refinery
|
|
19
21
|
end
|
20
22
|
respond_with (@posts) do |format|
|
21
23
|
format.html
|
22
|
-
format.rss { render :
|
24
|
+
format.rss { render layout: false }
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def show
|
27
29
|
@comment = Comment.new
|
28
30
|
|
29
|
-
@canonical = refinery.url_for(:
|
31
|
+
@canonical = refinery.url_for(locale: Refinery::I18n.current_frontend_locale) if canonical?
|
30
32
|
|
31
|
-
|
33
|
+
Post.increment_counter(:access_count, @post.id)
|
32
34
|
|
33
35
|
respond_with (@post) do |format|
|
34
36
|
format.html { present(@post) }
|
35
|
-
format.js { render :
|
37
|
+
format.js { render partial: 'post', layout: false }
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
@@ -48,12 +50,12 @@ module Refinery
|
|
48
50
|
end
|
49
51
|
|
50
52
|
if Comment::Moderation.enabled?
|
51
|
-
flash[:notice] = t('thank_you_moderated', :
|
53
|
+
flash[:notice] = t('thank_you_moderated', scope: 'refinery.blog.posts.comments')
|
52
54
|
redirect_to refinery.blog_post_url(params[:id])
|
53
55
|
else
|
54
|
-
flash[:notice] = t('thank_you', :
|
56
|
+
flash[:notice] = t('thank_you', scope: 'refinery.blog.posts.comments')
|
55
57
|
redirect_to refinery.blog_post_url(params[:id],
|
56
|
-
:
|
58
|
+
anchor: "comment-#{@comment.to_param}")
|
57
59
|
end
|
58
60
|
else
|
59
61
|
render :show
|
@@ -64,12 +66,12 @@ module Refinery
|
|
64
66
|
if params[:month].present?
|
65
67
|
date = "#{params[:month]}/#{params[:year]}"
|
66
68
|
archive_date = Time.parse(date)
|
67
|
-
@date_title = ::I18n.l(archive_date, :
|
69
|
+
@date_title = ::I18n.l(archive_date, format: '%B %Y')
|
68
70
|
@posts = Post.live.by_month(archive_date).page(params[:page])
|
69
71
|
else
|
70
72
|
date = "01/#{params[:year]}"
|
71
73
|
archive_date = Time.parse(date)
|
72
|
-
@date_title = ::I18n.l(archive_date, :
|
74
|
+
@date_title = ::I18n.l(archive_date, format: '%Y')
|
73
75
|
@posts = Post.live.by_year(archive_date).page(params[:page])
|
74
76
|
end
|
75
77
|
respond_with (@posts)
|
@@ -78,7 +80,7 @@ module Refinery
|
|
78
80
|
def tagged
|
79
81
|
@tag = ActsAsTaggableOn::Tag.find(params[:tag_id])
|
80
82
|
@tag_name = @tag.name
|
81
|
-
@posts = Post.live.newest_first.
|
83
|
+
@posts = Post.live.newest_first.distinct.tagged_with(@tag_name).page(params[:page])
|
82
84
|
end
|
83
85
|
|
84
86
|
private
|
@@ -11,11 +11,11 @@ module Refinery
|
|
11
11
|
|
12
12
|
def blog_post_teaser(post)
|
13
13
|
if post.respond_to?(:custom_teaser) && post.custom_teaser.present?
|
14
|
-
|
14
|
+
post.custom_teaser.html_safe
|
15
15
|
else
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
truncate(post.body, {
|
17
|
+
:length => Refinery::Blog.post_teaser_length,
|
18
|
+
:preserve_html_tags => true
|
19
19
|
}).html_safe
|
20
20
|
end
|
21
21
|
end
|
@@ -1,12 +1,30 @@
|
|
1
1
|
require 'acts-as-taggable-on'
|
2
|
-
require 'seo_meta'
|
3
2
|
|
4
3
|
module Refinery
|
5
4
|
module Blog
|
6
5
|
class Post < ActiveRecord::Base
|
7
6
|
extend FriendlyId
|
8
7
|
|
9
|
-
translates :title, :body, :custom_url, :custom_teaser, :slug, :
|
8
|
+
translates :title, :body, :custom_url, :custom_teaser, :slug, include: :seo_meta
|
9
|
+
|
10
|
+
attribute :title
|
11
|
+
attribute :body
|
12
|
+
attribute :custom_url
|
13
|
+
attribute :custom_teaser
|
14
|
+
attribute :slug
|
15
|
+
after_save {translations.collect(&:save)}
|
16
|
+
|
17
|
+
class Translation
|
18
|
+
is_seo_meta
|
19
|
+
|
20
|
+
def self.seo_fields
|
21
|
+
::SeoMeta.attributes.keys.map {|a| [a, :"#{a}="]}.flatten
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def validating_source_urls?
|
26
|
+
Refinery::Blog.validate_source_url
|
27
|
+
end
|
10
28
|
|
11
29
|
friendly_id :friendly_id_source, :use => [:slugged, :globalize]
|
12
30
|
|
@@ -14,38 +32,42 @@ module Refinery
|
|
14
32
|
|
15
33
|
acts_as_taggable
|
16
34
|
|
17
|
-
belongs_to :author, proc { readonly(true) }, :
|
35
|
+
belongs_to :author, proc { readonly(true) }, class_name: Refinery::Blog.user_class.to_s, foreign_key: :user_id, optional: true
|
36
|
+
|
18
37
|
has_many :comments, :dependent => :destroy, :foreign_key => :blog_post_id
|
19
|
-
has_many :categorizations, :dependent => :destroy, :foreign_key => :blog_post_id
|
38
|
+
has_many :categorizations, :dependent => :destroy, :foreign_key => :blog_post_id, inverse_of: :blog_post
|
20
39
|
has_many :categories, :through => :categorizations, :source => :blog_category
|
21
40
|
|
22
41
|
validates :title, :presence => true, :uniqueness => true
|
23
|
-
validates :body,
|
42
|
+
validates :body, :presence => true
|
24
43
|
validates :published_at, :presence => true
|
25
44
|
validates :author, :presence => true, if: :author_required?
|
26
|
-
validates :
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
45
|
+
validates :username, :presence => true, unless: :author_required?
|
46
|
+
validates :source_url, url: {
|
47
|
+
if: :validating_source_urls?,
|
48
|
+
update: true,
|
49
|
+
allow_nil: true,
|
50
|
+
allow_blank: true,
|
51
|
+
verify: [:resolve_redirects]
|
52
|
+
}
|
31
53
|
|
32
54
|
class Translation
|
33
55
|
is_seo_meta
|
34
56
|
end
|
35
|
-
|
57
|
+
|
36
58
|
# Override this to disable required authors
|
37
59
|
def author_required?
|
38
|
-
|
60
|
+
!Refinery::Blog.user_class.nil?
|
39
61
|
end
|
40
62
|
|
41
63
|
# If custom_url or title changes tell friendly_id to regenerate slug when
|
42
64
|
# saving record
|
43
65
|
def should_generate_new_friendly_id?
|
44
|
-
|
66
|
+
saved_change_to_attribute?(:custom_url) || saved_change_to_attribute?(:title)
|
45
67
|
end
|
46
68
|
|
47
69
|
# Delegate SEO Attributes to globalize translation
|
48
|
-
seo_fields = ::SeoMeta.attributes.keys.map{|a| [a, :"#{a}="]}.flatten
|
70
|
+
seo_fields = ::SeoMeta.attributes.keys.map {|a| [a, :"#{a}="]}.flatten
|
49
71
|
delegate(*(seo_fields << {:to => :translation}))
|
50
72
|
|
51
73
|
self.per_page = Refinery::Blog.posts_per_page
|
@@ -66,6 +88,10 @@ module Refinery
|
|
66
88
|
custom_url.presence || title
|
67
89
|
end
|
68
90
|
|
91
|
+
def author_username
|
92
|
+
author.try(:username) || username
|
93
|
+
end
|
94
|
+
|
69
95
|
class << self
|
70
96
|
|
71
97
|
# Wrap up the logic of finding the pages based on the translations table.
|
@@ -79,7 +105,7 @@ module Refinery
|
|
79
105
|
end
|
80
106
|
# A join implies readonly which we don't really want.
|
81
107
|
where(conditions).joins(:translations).where(globalized_conditions)
|
82
|
-
|
108
|
+
.readonly(false)
|
83
109
|
end
|
84
110
|
|
85
111
|
def by_month(date)
|
@@ -116,7 +142,7 @@ module Refinery
|
|
116
142
|
|
117
143
|
def uncategorized
|
118
144
|
newest_first.live.includes(:categories).where(
|
119
|
-
Refinery::Blog::Categorization.table_name => {
|
145
|
+
Refinery::Blog::Categorization.table_name => {:blog_category_id => nil}
|
120
146
|
)
|
121
147
|
end
|
122
148
|
|
@@ -131,6 +157,7 @@ module Refinery
|
|
131
157
|
.where(:draft => false)
|
132
158
|
.with_globalize
|
133
159
|
end
|
160
|
+
|
134
161
|
alias_method :live, :published_before
|
135
162
|
|
136
163
|
def comments_allowed?
|
@@ -21,15 +21,9 @@
|
|
21
21
|
</span>
|
22
22
|
</span>
|
23
23
|
<span class='actions'>
|
24
|
-
<%=
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
:class => "cancel confirm-delete",
|
29
|
-
:title => t('.delete'),
|
30
|
-
:method => :delete,
|
31
|
-
:data => {
|
32
|
-
:confirm => t('message', :scope => 'refinery.admin.delete', :title => category.title)
|
33
|
-
} %>
|
24
|
+
<%= action_icon(:edit, refinery.edit_blog_admin_category_path(category), t('.edit') ) %>
|
25
|
+
<%= action_icon(:delete, refinery.blog_admin_category_path(category), t('.delete'),
|
26
|
+
{ class: "cancel confirm-delete",
|
27
|
+
data: {confirm: t('message', scope: 'refinery.admin.delete', title: category.title)}} ) %>
|
34
28
|
</span>
|
35
29
|
</li>
|
@@ -4,19 +4,9 @@
|
|
4
4
|
<span class="preview"> - <%= truncate(comment.message, :length => 75) %></span>
|
5
5
|
</span>
|
6
6
|
<span class='actions'>
|
7
|
-
<%=
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
<%= link_to refinery_icon_tag('zoom.png'), refinery.blog_admin_comment_path(comment),
|
12
|
-
:title => t('.read') %>
|
13
|
-
<%= link_to refinery_icon_tag("cross.png"),
|
14
|
-
refinery.reject_blog_admin_comment_path(comment),
|
15
|
-
:method => :post,
|
16
|
-
:title => t('.reject') unless comment.rejected? %>
|
17
|
-
<%= link_to refinery_icon_tag("tick.png"),
|
18
|
-
refinery.approve_blog_admin_comment_path(comment),
|
19
|
-
:method => :post,
|
20
|
-
:title => t('.approve') unless comment.approved? %>
|
7
|
+
<%= action_icon(:preview, refinery.blog_post_path(comment.post, :anchor => "comment-#{comment.to_param}"), t('.view_live_html')) unless comment.unmoderated? %>
|
8
|
+
<%= action_icon(:search, refinery.blog_admin_comment_path(comment), t('.read')) %>
|
9
|
+
<%= action_icon(:failure, refinery.reject_blog_admin_comment_path(comment), t('.reject'), method: 'post') unless comment.rejected? %>
|
10
|
+
<%= action_icon(:success, refinery.approve_blog_admin_comment_path(comment), t('.approve'), method: 'post') unless comment.approved? %>
|
21
11
|
</span>
|
22
12
|
</li>
|
@@ -94,7 +94,11 @@
|
|
94
94
|
<%= f.label :user_id, t('.author') %>
|
95
95
|
<%= refinery_help_tag t('.author_help') %>
|
96
96
|
<br/>
|
97
|
-
|
97
|
+
<% if @authors.present? %>
|
98
|
+
<%= f.collection_select :user_id, @authors, :id, :username %>
|
99
|
+
<% else %>
|
100
|
+
<%= f.text_field :username, id: :post_user_id, :class => "widest" %>
|
101
|
+
<% end %>
|
98
102
|
</span>
|
99
103
|
</div>
|
100
104
|
|