#--
# Copyright (c) 2012+ Damjan Rems
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
########################################################################
# Renders code for displaying a poll. Polls may replace forms when user interaction
# is required in browser.
########################################################################
class DcPollRenderer
include CmsCommonHelper
include DcApplicationHelper
include ActionView::Helpers::FormHelper # for form helpers
include ActionView::Helpers::FormOptionsHelper # for select helper
########################################################################
# Object initialization.
########################################################################
def initialize( parent, opts={} ) #:nodoc:
@parent = parent
@opts = opts
@part_css = ''
@part_js = ''
self
end
########################################################################
# Dummy params method for accesing session params object from form.
########################################################################
def params
@parent.params
end
########################################################################
# Outputs code required for poll item. Subroutine of default method.
########################################################################
def do_one_item(poll, yaml)
html = ''
yaml['separator'] ||= ''
yaml['text'] ||= ''
# label
text = yaml['text'].match(/\./) ? t(yaml['text']) : yaml['text']
if yaml['mandatory']
text << ( poll.display == 'in' ? ' *' : ' *' )
yaml['html'] ||= {}
yaml['html']['required'] = true
else
text << " " if poll.display == 'lr' and !yaml['type'].match(/submit_tag|link_to/)
end
# Just add text if comment and go to next one
if yaml['type'] == 'comment'
html << if poll.display == 'lr'
"
"
else
""
end
return html
end
# Set default value, if not already set
if yaml['default']
if yaml['default'].match('eval')
e = yaml['default'].match(/\((.*?)\)/)[1]
yaml['default'] = eval e
elsif yaml['default'].match('params')
param_name = yaml['default'].split(/\.|\ |\,/)[1]
yaml['default'] = @parent.params[param_name]
end
key = "p_#{yaml['name']}"
params[key] = yaml['default'] unless params[key]
end
# Label as placeholder
if poll.display == 'in'
yaml['html'] ||= {}
yaml['html']['placeholder'] = text
end
# create form_field object and retrieve html code
clas_string = yaml['type'].camelize
field_html = if DrgcmsFormFields.const_defined?(clas_string)
clas = DrgcmsFormFields.const_get(clas_string)
field = clas.new(@parent, @record, yaml).render
@part_js << field.js
field.html
else # error string
"Error: Code for field type #{yaml['type']} not defined!"
end
if yaml['type'].match(/submit_tag|link_to/)
# There can be more than one links on form. End the data at first link or submit.
if !@end_of_data
html << if poll.display == 'lr'
"
\n"
else
"\n"
end
# captcha
if poll.captcha_type.to_s.size > 1
@opts.merge!(:captcha_type => poll.captcha_type)
captcha = DcCaptchaRenderer.new(@parent, @opts)
html << captcha.render_html
@part_css = captcha.render_css
end
@end_of_data = true
end
# submit and link tag
clas = yaml['type'].match(/submit_tag/) ? '' : 'dc-link-submit'
html << "#{field_html}#{yaml['separator']}"
# other fields
else
html << case
when poll.display == 'lr' then
"\n"
when poll.display == 'td' then
"#{text}
#{field_html}#{yaml['separator']}
\n"
else
"#{field_html}#{yaml['separator']}
\n"
end
end
end
########################################################################
# Call method before poll is displayed. Usefull for filling predefined values into flash[:record][value]
# Method cane be defined as ClassName.method or only method.
# If only method is defined then method name must exist in helpers.
#
# Called method must return at least one result if process can continue.
########################################################################
def eval_pre_display(code)
a = code.strip.split('.')
if a.size == 1
continue, message = @parent.send(a.first)
else
klass = a.first.classify.constantize
continue, message = klass.send(a.last,@parent)
end
[continue, message]
end
########################################################################
# Default poll renderer method. Renders data for specified pool.
########################################################################
def default
# poll_id may be defined in params or opts
poll_id = @opts[:poll_id] || @parent.params[:poll_id]
return '
Poll id is not defined?
' if poll_id.nil?
poll = DcPoll.find(poll_id)
poll = DcPoll.find_by(name: poll_id) if poll.nil? # name instead of id
return "Invalid Poll id #{poll_id}
" if poll.nil?
# If parent cant be seen. so cant be polls
can_view, message = dc_user_can_view(@parent, @parent.page)
return "#{message}
" unless can_view
html = @opts[:div] ? "" : ''
html << '
'
unless poll.pre_display.blank?
begin
continue, message = eval_pre_display(poll.pre_display)
rescue Exception => e
return "
Error! Poll pre display. Error: #{e.message}
"
end
return message unless continue
html << message if message
end
# there might be more than one poll displayed on page. Check if messages and values are for me
if @parent.flash[:poll_id].nil? || @parent.flash[:poll_id].to_s == poll_id.to_s
# If flash[:record] is present copy content to params record hash
@parent.flash[:record].each {|k,v| @parent.params["p_#{k}"] = v } if @parent.flash[:record]
# Error during procesing request
html << "
#{@parent.flash[:error]}
\n" if @parent.flash[:error].to_s.size > 0
html << "
#{@parent.flash[:info]}
\n" if @parent.flash[:info]
end
# div and form tag
html << "
\n"
# edit link
if @opts[:edit_mode] > 1
@opts[:editparams].merge!( controller: 'cmsedit', action: 'edit', id: poll._id, table: 'dc_poll', form_name: 'dc_poll' )
@opts[:editparams].merge!(title: "#{t('drgcms.edit')}: #{poll.name}")
@opts[:editparams].delete(:ids) # this is from page, but it gets in a way
html << dc_link_for_edit( @opts[:editparams] )
end
html << case
when poll.operation == 'poll_submit' then
@parent.form_tag(action: poll.operation, method: :put)
when poll.operation == 'link' then
@parent.form_tag( poll.parameters, method: :put)
end
# header, - on first position will not display title
html << "
#{poll.title}
" unless poll.title[0] == '-'
html << poll.sub_text.to_s
html << if poll.display == 'lr'
"\n" + '
'
else
'
' + "\n"
end
# items. Convert each item to yaml
@end_od_data = false
if poll.form.to_s.size < 10
items = poll.dc_poll_items
items.sort! { |a,b| a.order <=> b.order }
items.each do |item|
next unless item.active # disabled items
# convert options to yaml
yaml = YAML.load(item.options) || {}
yaml = {} if yaml.class == String
yaml['name'] = item.name
yaml['html'] ||= {}
yaml['html']['size'] = item.size
(yaml['html']['class'] ||= 'dc-submit') if item.type == 'submit_tag'
yaml['text'] = item.text
yaml['mandatory'] = item.mandatory
yaml['type'] = item.type
html << do_one_item(poll, yaml)
end
# FORM. Just call do_one_item for each form item
else
yaml = YAML.load(poll.form.gsub(' ',' ')) # very annoying. They come with copy&paste ;-)
# if entered without numbering yaml is returned as Hash otherwise as Array
yaml.each { |i| html << do_one_item(poll, (i.class == Hash ? i : i.last)) } #
end
# hide some fields usefull as parameters
html << @parent.hidden_field_tag('return_to', @opts[:return_to] || @parent.params[:return_to] || @parent.request.url)
html << @parent.hidden_field_tag('return_to_error', @parent.request.url )
html << @parent.hidden_field_tag('poll_id', poll_id )
html << @parent.hidden_field_tag('page_id', @parent.page.id )
# Add javascript code
html << @parent.javascript_tag(@part_js + poll.js.to_s)
html << "
"
html << '
' if @opts[:div]
@part_css = poll.css
html
end
########################################################################
# Renderer dispatcher. Method returns HTML part of code.
########################################################################
def render_html
method = @opts[:method] || 'default'
respond_to?(method) ? send(method) : "Error DcPoll: Method #{method} doesn't exist!"
end
########################################################################
# Return CSS part of code.
########################################################################
def render_css
@part_css
end
end