502 lines
21 KiB
Ruby
502 lines
21 KiB
Ruby
module AnnouncementsHelper
|
|
def self.complementaryColor(my_hex)
|
|
if my_hex[0] == '#'
|
|
my_hex = my_hex[1..-1]
|
|
end
|
|
rgb = my_hex.split(//).each_slice(my_hex.length/3).map{|v| v.join}
|
|
comp = rgb.map{|a| (255 - a.to_i(16)).to_s(16).rjust(2,'0')}
|
|
'#'+comp.join
|
|
end
|
|
def self.lighten_color(my_hex,percent)
|
|
if my_hex[0] == '#'
|
|
my_hex = my_hex[1..-1]
|
|
end
|
|
rgb = my_hex.split(//).each_slice(my_hex.length/3).map{|v| v.join}
|
|
comp = rgb.collect do |a|
|
|
tmp = a.to_i(16)*(1+percent/100.0)
|
|
tmp = 255 if tmp>255
|
|
tmp = 0 if tmp < 0
|
|
tmp.to_i.to_s(16).rjust(2,'0')
|
|
end
|
|
'#'+comp.join
|
|
end
|
|
def data_to_human_type(a,set_tag_ids=nil)
|
|
statuses = a.statuses_with_classname.collect do |status|
|
|
{
|
|
"status" => status["name"],
|
|
"status-class" => "status-#{status['classname']}"
|
|
}
|
|
end
|
|
files = a.bulletin_files.map{|file| { "file_url" => file.file.url, "file_title" => (file.title.blank? ? File.basename(file.file.path) : file.title rescue '') } if file.enabled_for?(locale) } rescue []
|
|
files.delete(nil)
|
|
links = a.bulletin_links.map{|link| { "link_url" => link.url, "link_title" => (link.title.blank? ? link.url : link.title) } } rescue []
|
|
author = User.find(a.create_user_id).member_profile.name rescue ""
|
|
desc = a.image_description
|
|
desc = (desc.nil? || desc == "" ? "announcement image" : desc)
|
|
link_to_show = (a.is_external_link? ? a.external_link : OrbitHelper.widget_item_url(a.to_param)) rescue ""
|
|
target = a.is_external_link ? "_blank" : "_self"
|
|
if @image_version == 'thumb'
|
|
image_url = a.image.thumb.url
|
|
elsif @image_version == 'mobile'
|
|
image_url = a.image.mobile.url
|
|
else
|
|
image_url = a.image.url
|
|
end
|
|
doc = Nokogiri::HTML(a.title)
|
|
title = doc.text.empty? ? 'no content' : doc.text
|
|
{
|
|
"is_top" => a.is_top,
|
|
"bulletin_links" => links,
|
|
"bulletin_files" => files,
|
|
"title" => a.title,
|
|
"source-site" => "",
|
|
"source-site-title" => "",
|
|
"source-site-link" => "",
|
|
"subtitle" => a.subtitle,
|
|
"statuses" => statuses,
|
|
"category" => (a.category.title rescue ""),
|
|
"tag_ids" => (set_tag_ids.nil? ? (a.tag_ids.map{|id| id.to_s}.to_s.gsub('"',"'") rescue '[]') : set_tag_ids),
|
|
"postdate" => a.postdate,
|
|
"author" => author,
|
|
"link_to_show" => link_to_show+"\" #{(link_to_show[0] == '/' rescue true) ? '' : 'target="_blank"'} title=\"#{title}",
|
|
"target" => target,
|
|
"img_src" => image_url || "/assets/announcement-default.jpg",
|
|
"img_description" => desc
|
|
}
|
|
end
|
|
def get_feed_annc(type,site_source,locale,categories=nil,max_len=nil)
|
|
ma_key = 'announcement'
|
|
if categories.nil?
|
|
if type == "index"
|
|
categories = Array(OrbitHelper.page_categories)
|
|
elsif type == "widget"
|
|
categories = Array(OrbitHelper.widget_categories)
|
|
else
|
|
categories = []
|
|
end
|
|
end
|
|
categories = ["all"] if categories.length==0
|
|
data = SiteFeedAnnc.get_feed_cache(ma_key,categories,site_source,locale,type=='widget',max_len)
|
|
data
|
|
end
|
|
def get_feed_announcements(type,site_source=nil,categories=nil,max_len=nil)
|
|
locale = OrbitHelper.get_site_locale.to_s
|
|
if !(defined? SiteFeedAnnc).nil?
|
|
fans = get_feed_annc(type,site_source,locale,categories,max_len)
|
|
else
|
|
feed_anns = OrbitHelper.get_feed_for_module(type)
|
|
fans = []
|
|
feed_anns.each do |fa|
|
|
next if !site_source.nil? && site_source != fa["source-site-title"]
|
|
status = {
|
|
"status" => "<a href='#{fa["source-site"]}' target='_blank' class='feed-source'>#{fa["source-site-title"]}</a>",
|
|
"status-class" => "status-source"
|
|
}
|
|
|
|
files = fa["bulletin_files"].collect{|bf| { "file_url" => bf["url"], "file_title" => (fa["title_translations"][locale].blank? ? File.basename(fa["url"]) : fa["title_translations"][locale] rescue '') }} rescue []
|
|
links = fa["bulletin_links"].map{|link| { "link_url" => link["url"], "link_title" => (link["title_translations"][locale].blank? ? link["url"] : link["title_translations"][locale]) } } rescue []
|
|
|
|
x = {
|
|
"bulletin_links" => links,
|
|
"bulletin_files" => files,
|
|
"bulletin_carousel_images" => fa["bulletin_carousel_images"].to_a,
|
|
"title" => fa["title_translations"][locale],
|
|
"subtitle" => fa["subtitle_translations"][locale],
|
|
"statuses" => [status],
|
|
"category" => fa["category"],
|
|
"postdate" => fa["postdate"],
|
|
"author" => fa["author"],
|
|
"source-site" => "<a href='#{fa["source-site"]}' target='_blank' class='feed-source'>#{fa["source-site-title"]}</a>",
|
|
"source-site-title" => fa["source-site-title"],
|
|
"source-site-link" => fa["source-site"],
|
|
"link_to_show" => OrbitHelper.url_to_show(fa["params"]),
|
|
"target" => "_self",
|
|
"img_src" => fa["image"]["thumb"] || "/assets/announcement-default.jpg",
|
|
"img_description" => fa["image_description_translations"][locale],
|
|
"more" => t(:more_plus),
|
|
"view_count" => ""
|
|
}
|
|
if (!x["title"].empty? rescue false)
|
|
fans << x
|
|
end
|
|
end
|
|
end
|
|
fans
|
|
end
|
|
def filter_by_keywords(sorted,keywords,stime,etime)
|
|
kflag = keywords.blank?
|
|
sflag = stime.blank?
|
|
eflag = etime.blank?
|
|
stime = stime.to_s.split('/')
|
|
stime = Time.zone.local(*stime) rescue nil
|
|
etime = etime.to_s.split('/')
|
|
etime = Time.zone.local(*etime) rescue nil
|
|
if !kflag || !sflag || !eflag
|
|
sorted.select{|anns|
|
|
if kflag
|
|
flag = true
|
|
else
|
|
if anns["source-site"].present?
|
|
title = Nokogiri::HTML(anns["title"].to_s).text
|
|
else
|
|
title = Nokogiri::HTML(anns.title.to_s).text
|
|
end
|
|
flag = title.include?(keywords.to_s)
|
|
end
|
|
if sflag && !eflag
|
|
flag = flag && (anns.postdate<=etime)
|
|
elsif !sflag && eflag
|
|
flag = flag && (anns.postdate>=stime)
|
|
elsif !sflag && !eflag
|
|
flag = flag && (anns.postdate>=stime) && (anns.postdate<=etime)
|
|
end
|
|
flag
|
|
}
|
|
else
|
|
sorted
|
|
end
|
|
end
|
|
def get_sorted_annc(data_count=nil)
|
|
params = OrbitHelper.params
|
|
locale = OrbitHelper.get_site_locale.to_s
|
|
page_number = OrbitHelper.page_number.to_i
|
|
page_number = 1 if page_number == 0
|
|
page_data_count = data_count || OrbitHelper.page_data_count.to_i
|
|
feeds_anns = []
|
|
page = OrbitHelper.page rescue nil
|
|
page = Page.where(url:params['url']).first if page.nil?
|
|
if @type == "show_widget"
|
|
tags = @tags
|
|
categories = @categories
|
|
else
|
|
tags = page.tags
|
|
tags = params[:tags] if params[:tags].present?
|
|
categories = params['category']=='all' ? (page.categories || []) : (params['category'].nil? ? (page.categories || []) : Array(params['category']))
|
|
if params['category'].present? && tags.blank?
|
|
tags = ["all"]
|
|
end
|
|
end
|
|
if !params["source"].present?
|
|
if @type == "show_widget"
|
|
if params[:uids].blank?
|
|
announcements = Bulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil])
|
|
.can_display_and_sorted.is_approved
|
|
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
|
|
else
|
|
member_prfile = MemberProfile.any_in(:uid=>params[:uids])
|
|
user_ids = member_prfile.map{|m| m.user.id rescue nil}.select{|id| !id.nil?}
|
|
announcements = Bulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil],:create_user_id.in=>user_ids)
|
|
.can_display_and_sorted.is_approved
|
|
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
|
|
end
|
|
else
|
|
announcements = Bulletin.where(:title.nin => ["",nil],:is_preview.in=>[false,nil])
|
|
.can_display_and_sorted.is_approved
|
|
.filter_by_categories(categories,false).filter_by_tags(tags).to_a
|
|
end
|
|
if !(defined? SiteFeed).nil?
|
|
if @type != "show_widget"
|
|
feeds_anns = get_feed_announcements("index",nil,categories,page_number*page_data_count)
|
|
else
|
|
feeds_anns = []
|
|
end
|
|
end
|
|
else
|
|
announcements = []
|
|
if @type != "show_widget"
|
|
feeds_anns = get_feed_announcements("index",params["source"],categories,page_number*page_data_count)
|
|
else
|
|
feeds_anns = []
|
|
end
|
|
end
|
|
if !feeds_anns.blank?
|
|
if announcements.count != 0
|
|
top_anns = announcements.select{|v| v.is_top} + feeds_anns.select{|v| v['is_top']}
|
|
rest_all_anns = feeds_anns.select{|v| v['is_top'] != true} + announcements.select{|v| !v.is_top}
|
|
rest_anns = rest_all_anns.sort_by { |a| tmp=a["postdate"].blank?;[tmp ? 0 : 1, tmp ? nil : a["postdate"].to_time] }.reverse
|
|
all_sorted = top_anns.sort_by { |a| tmp=a["postdate"].blank?;[tmp ? 0 : 1, tmp ? nil : a["postdate"].to_time] }.reverse + rest_anns
|
|
else
|
|
all_sorted = feeds_anns.select{|v| v['is_top']}.sort_by { |a| tmp=a["postdate"].blank?;[tmp ? 0 : 1, tmp ? nil : a["postdate"].to_time] }.reverse + feeds_anns.select{|v| v['is_top'] != true}.sort_by { |a| tmp=a["postdate"].blank?;[tmp ? 0 : 1, tmp ? nil : a["postdate"].to_time] }.reverse
|
|
end
|
|
all_filter = filter_by_keywords(all_sorted,params[:keywords],params[:stime],params[:etime])
|
|
else
|
|
all_filter = filter_by_keywords(announcements,params[:keywords],params[:stime],params[:etime])
|
|
end
|
|
if page_data_count != 0
|
|
sorted = all_filter[(page_number-1)*page_data_count...page_number*page_data_count]
|
|
else
|
|
sorted = all_filter
|
|
end
|
|
annc_count = all_filter.count
|
|
total_pages = page_data_count == 0 ? 1 : (annc_count.to_f / page_data_count).ceil
|
|
[sorted,total_pages]
|
|
end
|
|
def render_view_for_annc(overridehtml=nil)
|
|
@key = Site.first.template
|
|
def render_link_to_edit(html, url_to_edit)
|
|
if html.scan("{{link_to_edit}}").length == 0
|
|
html = url_to_edit.blank? ? html : html + "<p class='admin-edit text-right'><a class='btn btn-primary' href='#{url_to_edit}'><i class='icon-edit'></i> #{t(:edit)}</a></p>"
|
|
else
|
|
html = url_to_edit.blank? ? html.gsub("{{link_to_edit}}","") : html.gsub("{{link_to_edit}}","<p class='admin-edit text-right'><a class='btn btn-primary' href='#{url_to_edit}'><i class='icon-edit'></i> #{t(:edit)}</a></p>")
|
|
end
|
|
return html
|
|
end
|
|
|
|
def parsing_repeats_again(elements,d,level)
|
|
newhtml = []
|
|
oldhtml = []
|
|
elements.each do |el|
|
|
html_to_render = ""
|
|
data_name = el.attr("data-list")
|
|
wrap_elements = el.css("*[data-list][data-level='#{level}']")
|
|
if d[data_name]
|
|
d[data_name].each_with_index do |item,i|
|
|
element = el.inner_html
|
|
if wrap_elements.count > 0
|
|
htmls = parsing_repeats_again(wrap_elements,d[data_name][i], level + 1)
|
|
htmls[0].each_with_index do |html,i|
|
|
element = element.gsub(html,htmls[1][i])
|
|
end
|
|
end
|
|
item.each do |key,value|
|
|
if !value.kind_of?(Array)
|
|
value = value.nil? ? "" : value
|
|
element = element.gsub("{{#{key}}}",value.to_s.html_safe)
|
|
element = element.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
|
|
element = render_link_to_edit(element, value) if key.eql?("url_to_edit")
|
|
end
|
|
end
|
|
html_to_render = html_to_render + element
|
|
end
|
|
temp = el.to_s
|
|
oldhtml << temp
|
|
temp = temp.gsub(el.inner_html, html_to_render)
|
|
newhtml << temp
|
|
end
|
|
end
|
|
[oldhtml,newhtml]
|
|
end
|
|
|
|
|
|
if @target_action == "index"
|
|
filename = overridehtml.nil? ? params[:layout_type] : overridehtml
|
|
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'announcement', "#{filename}.html.erb")
|
|
if !File.exists?f
|
|
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'announcement', "index.html.erb")
|
|
if !File.exists?f
|
|
return "<div class='well'>Maybe the administrator has changed the theme, please select the index page design again from the page settings.</div>".html_safe
|
|
end
|
|
end
|
|
file = File.open(f)
|
|
doc = Nokogiri::HTML(file, nil, "UTF-8")
|
|
file.close
|
|
controller = AnnouncementsController.new
|
|
begin
|
|
data = @data# rescue nil
|
|
rescue Exception => e
|
|
write_debug_file(e,'announcements',@target_action) if Site::DEBUG
|
|
end
|
|
if !data.nil?
|
|
wrap_elements = doc.css("*[data-list][data-level='0']")
|
|
htmls = parsing_repeats_again(wrap_elements,data,1)
|
|
html = doc.to_s
|
|
htmls[0].each_with_index do |h,i|
|
|
html = html.gsub(h,htmls[1][i])
|
|
end
|
|
extras = data["extras"] || {}
|
|
extras["page-title"] = Page.find_by(:page_id => params[:page_id]).name rescue "" if !extras["page-title"]
|
|
extras.each do |key,value|
|
|
value = value.nil? ? "" : value
|
|
html = html.gsub("{{#{key}}}",value.to_s.html_safe)
|
|
html = html.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
|
|
end
|
|
total_pages = data['total_pages'].to_i rescue 1
|
|
if total_pages > 1
|
|
html = html.gsub("{{pagination_goes_here}}",create_pagination(total_pages))
|
|
else
|
|
html = html.gsub("{{pagination_goes_here}}","");
|
|
end
|
|
html.html_safe
|
|
else
|
|
return "<div class='well'>No content to show.</div>".html_safe
|
|
end
|
|
else
|
|
filename = overridehtml.nil? ? @target_action : overridehtml
|
|
f = File.join(Rails.root, 'app', 'templates', "#{@key}", 'modules', 'announcement', "#{filename}.html.erb")
|
|
if File.exists?f
|
|
file = File.open(f)
|
|
doc = Nokogiri::HTML(file, nil, "UTF-8")
|
|
file.close
|
|
controller = AnnouncementsController.new
|
|
begin
|
|
data = @data# rescue nil
|
|
rescue Exception => e
|
|
write_debug_file(e,'announcements',@target_action) if Site::DEBUG
|
|
end
|
|
if data.nil?
|
|
return "<div class='well'> No content to show. </div>".html_safe
|
|
end
|
|
|
|
if data.blank? || data.empty?
|
|
file = File.open("#{Rails.root}/app/views/errors/404.html")
|
|
doc = Nokogiri::HTML(file, nil, "UTF-8")
|
|
file.close
|
|
doc.to_html.html_safe
|
|
else
|
|
unless data['impressionist'].blank?
|
|
Thread.new do
|
|
impression = data['impressionist'].impressions.create
|
|
impression.user_id = request.session['user_id']
|
|
impression.controller_name = 'announcements'
|
|
impression.action_name = @target_action
|
|
impression.ip_address = request.remote_ip
|
|
impression.session_hash = request.session.id
|
|
impression.request_hash = @impressionist_hash
|
|
impression.referrer = request.referrer
|
|
impression.save
|
|
end
|
|
data['impressionist'].inc(view_count: 1)
|
|
data["data"]["view_count"] = data["impressionist"].view_count if data["data"].present?
|
|
end
|
|
wrap_elements = doc.css("*[data-list][data-level='0']")
|
|
if wrap_elements.count == 0
|
|
wrap_element_html = doc.to_s
|
|
el = wrap_element_html
|
|
data.each do |key,value|
|
|
next if key.eql? 'impressionist'
|
|
value = value.nil? ? "" : value
|
|
el = el.gsub("{{#{key}}}",value.to_s.html_safe)
|
|
el = el.gsub("%7B%7B#{key}%7D%7D",value.to_s.html_safe)
|
|
end
|
|
el.html_safe
|
|
else
|
|
keys = data.keys
|
|
not_array_key = nil
|
|
data.keys.each do |key|
|
|
not_array_key = key if data["#{key}"].kind_of?(Hash)
|
|
end
|
|
htmls = parsing_repeats_again(wrap_elements,data,1)
|
|
html = doc.to_s
|
|
htmls[0].each_with_index do |h,i|
|
|
html = html.gsub(h,htmls[1][i])
|
|
end
|
|
extras = data["#{not_array_key}"] || {}
|
|
extras.each do |key,value|
|
|
next if key.eql? 'impressionist'
|
|
value = value.nil? ? "" : value
|
|
html = html.gsub("{{#{key}}}",value.to_s)
|
|
html = html.gsub("%7B%7B#{key}%7D%7D",value.to_s)
|
|
end
|
|
html = render_link_to_edit(html, data["url_to_edit"]) if !data["url_to_edit"].nil?
|
|
total_pages = data['total_pages'].to_i rescue 1
|
|
if @show_page == "false"
|
|
html = html.gsub("{{pagination_goes_here}}","")
|
|
else
|
|
if total_pages > 1
|
|
html = html.gsub("{{pagination_goes_here}}",create_pagination(total_pages))
|
|
else
|
|
html = html.gsub("{{pagination_goes_here}}","")
|
|
end
|
|
end
|
|
html = Nokogiri::HTML.parse(html)
|
|
html.css('.i-annc__page-title').remove
|
|
dates = html.css("*[date-format]")
|
|
if !dates.blank?
|
|
dates.each do |d|
|
|
begin
|
|
format = d.attributes["date-format"].value
|
|
date = DateTime.parse(d.inner_text)
|
|
d.inner_html = d.inner_html.gsub(d.inner_text.strip, " " + date.strftime(format))
|
|
rescue
|
|
next
|
|
end
|
|
end
|
|
end
|
|
html.css("body")[0].inner_html = html.css("body")[0].inner_html.gsub("{{page-title}}","")
|
|
html.css("body").to_html.html_safe
|
|
end
|
|
end
|
|
else
|
|
return "<div class='well'>There is a problem with the design. We will try to fix it as soon as possible. Sorry for the inconvenience!! :(</div>".html_safe
|
|
end
|
|
end
|
|
end
|
|
def get_layouts(module_app)
|
|
layout_types = []
|
|
@key = Site.first.template
|
|
f = File.join("#{Rails.root}/app/templates/#{@key}/modules/#{module_app}/info.json")
|
|
if File.exists?f
|
|
info = File.read(f)
|
|
hash = JSON.parse(info) rescue {}
|
|
frontends = hash["frontend"] || []
|
|
frontends.each do |frontend|
|
|
frontend["thumbnail"] = "/assets/#{module_app}/thumbs/#{frontend["thumbnail"]}"
|
|
layout_types << frontend
|
|
end
|
|
end
|
|
if layout_types.empty?
|
|
Dir.glob("#{Rails.root}/app/templates/#{@key}/modules/#{module_app}/*").each do |w|
|
|
next if File.ftype(w).eql?("directory")
|
|
w = File.basename(w, ".*")
|
|
w = File.basename(w, ".*")
|
|
if w[0,1] != "_" && w[0,1] != "s" && w != "info"
|
|
layout_types << w
|
|
end
|
|
end
|
|
end
|
|
layout_types
|
|
end
|
|
def render_ad_banner(event_carousel_images,data)
|
|
("<div class=\"carousel_images\">
|
|
<div class=\"w-ba-banner ba-banner-widget-1\">
|
|
<div class=\"w-ba-banner__wrap cycle-slideshow\"
|
|
data-list=\"event_carousel_images\"
|
|
data-level=\"0\"
|
|
data-cycle-slides=\".event_carousel_slide\"
|
|
data-cycle-log=\"false\"
|
|
data-cycle-auto-height=\"0\"
|
|
data-cycle-speed=\"300\"
|
|
data-cycle-timeout=\"5000\"
|
|
data-cycle-fx=\"fade\"
|
|
data-pager-active-class=\"active-slide\"
|
|
data-cycle-swipe=true
|
|
data-cycle-swipe-fx=\"scrollHorz\"
|
|
>" +
|
|
event_carousel_images.collect do |e|
|
|
"<div class=\"w-ba-banner__slide event_carousel_slide\"
|
|
data-cycle-title=\"#{e['description_text']}\"
|
|
>
|
|
<img class=\"w-ba-banner__image banner-responsive\" src=\"#{e['src']}\" alt=\"#{e['description_text']}\">
|
|
<div class=\"ad-overlay w-ad-banner__overlay event_carousel__overlay\">
|
|
<p><strong class=\"carousel__description\">#{e['description']}</strong></p>
|
|
</div>
|
|
<div class=\"transitionfade\"></div>
|
|
</div>"
|
|
end.join+
|
|
"</div>
|
|
<ul class=\"controlplay\"><a class=\"resume-slide\" title = \"#{data['resume_btn_title']}\"><i></i></a><a class=\"pause-slide\" title = \"#{data['pause_btn_title']}\"><i></i></a></ul>
|
|
<ul class=\"button-mid\">
|
|
<i class=\"fa fa-angle-left prev-button\" aria-hidden=\"true\" title = \"#{data['prev_btn_title']}\"></i>
|
|
<i class=\"fa fa-angle-right next-button\" aria-hidden=\"true\" title = \"#{data['next_btn_title']}\"></i>
|
|
</ul>
|
|
</div>
|
|
<div style=\"position: relative;\">
|
|
<h4><span class=\"active_slide\">1</span>/#{data['carousel_count']}</h4>
|
|
<ul class=\"carousel_images_slide w-annc__list row list-unstyled\" data-level=\"0\" data-list=\"event_carousel_images\">" +
|
|
event_carousel_images.collect do |e|
|
|
"<li class=\"carousel_img_item col-sm-3\">
|
|
<div class=\"carousel_img-wrap\">
|
|
<img class=\"carousel_img\" src=\"#{e['src']}\" alt=\"#{e['description_text']}\">
|
|
</div>
|
|
</li>"
|
|
end.join +
|
|
"</ul>
|
|
<ul class=\"button-mid\">
|
|
<i class=\"fa fa-angle-left prev-button prev_img\" aria-hidden=\"true\" title = \"#{data['prev_btn_title']}\"></i>
|
|
<i class=\"fa fa-angle-right next-button next_img\" aria-hidden=\"true\" title = \"#{data['next_btn_title']}\"></i>
|
|
</ul>
|
|
</div>
|
|
</div>").html_safe
|
|
end
|
|
end
|