Module: Plugins::CamaContactForm::MainHelper
- Includes:
- Recaptcha::Adapters::ViewMethods
- Included in:
- AdminFormsController, CamaContactForm, FrontController
- Defined in:
- app/helpers/plugins/cama_contact_form/main_helper.rb
Constant Summary collapse
- CF_PLACEHOLDER =
Substitute every placeholder in ONE pass, so no replacement is ever scanned for the next placeholder. Substituting in sequence meant
[label ci]was searched for in the field markup[ci]had just produced -- so a visitor typing the literal[label ci]into a message had the author's label spliced into the middle of the textarea that was echoing it back.[ci]and[descr ci]keep first-occurrence semantics and[label ci]all-occurrence, which is what the three separate sub/sub/gsub calls did.The block form of #gsub is used throughout: a String replacement would treat
\1or\\in the value as a backreference and silently mangle it. /\[(?:ci|label ci|descr ci)\]/- CF_REPEATABLE_PLACEHOLDERS =
['[label ci]'].freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#cama_form_element_bootstrap_object(form, object, values) ⇒ Object
form contact with css bootstrap.
- #cama_form_select_multiple_bootstrap(ob, title, type, values) ⇒ Object
-
#cama_form_shortcode(slug) ⇒ Object
HTML ================== This returns the format of the plugin shortcode.
-
#cf_attrs(attrs) ⇒ Object
Nothing in this file escapes anything, by design.
- #cf_substitute(template, replacements) ⇒ Object
- #contact_form_admin_before_load ⇒ Object
- #contact_form_app_before_load ⇒ Object
- #contact_form_front_before_load ⇒ Object
-
#contact_form_on_active(plugin) ⇒ Object
here all actions on going to active you can run sql commands like this: results = ActiveRecord::Base.connection.execute(query); plugin: plugin model.
-
#contact_form_on_destroy(plugin) ⇒ Object
here all actions on plugin destroying plugin: plugin model.
- #contact_form_on_export(args) ⇒ Object
- #contact_form_on_import(args) ⇒ Object
-
#contact_form_on_inactive(plugin) ⇒ Object
here all actions on going to inactive plugin: plugin model.
Class Method Details
.included(klass) ⇒ Object
3 4 5 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 3 def self.included(klass) klass.helper_method [:cama_form_element_bootstrap_object, :cama_form_shortcode] rescue "" # here your methods accessible from views end |
Instance Method Details
#cama_form_element_bootstrap_object(form, object, values) ⇒ Object
form contact with css bootstrap
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 125 def cama_form_element_bootstrap_object(form, object, values) html = "" object.each do |ob| ob[:label] = ob[:label].to_s.translate ob[:description] = ob[:description].to_s.translate r = {field: ob, form: form, template: (ob[:field_options][:template].present? ? ob[:field_options][:template] : Plugins::CamaContactForm::CamaContactForm::field_template), custom_class: (ob[:field_options][:field_class] rescue nil), custom_attrs: {id: ob[:cid] }.merge((JSON.parse(ob[:field_options][:field_attributes]) rescue {})) } hooks_run("contact_form_item_render", r) ob = r[:field] ob[:custom_class] = r[:custom_class] ob[:custom_attrs] = r[:custom_attrs] # `cama_true?`, not `to_bool`: `to_bool` raises ArgumentError on anything outside its two # patterns, so a stored `required` of `maybe` was a 500 on every visit to the page. ob[:custom_attrs][:required] = 'true' if ob[:required].to_s.cama_true? = ob[:field_options] for_name = ob[:label].to_s f_name = "fields[#{ob[:cid]}]" cid = ob[:cid].to_sym temp2 = "" # Both a redisplayed submission and the author's default_value render verbatim: each was # validated before it could be stored or stashed, so neither can carry anything the submitter # was not permitted to write. current_value = values[cid] || ob[:default_value].to_s.translate case ob[:field_type].to_s when 'paragraph','textarea' temp2 = "<textarea #{cf_attrs(ob[:custom_attrs])} name=\"#{f_name}\" maxlength=\"#{[:maxlength] || 500}\" class=\"#{ob[:custom_class].presence || 'form-control'} \">#{current_value}</textarea>" when 'radio' temp2= cama_form_select_multiple_bootstrap(ob, ob[:label], ob[:field_type],values) when 'checkboxes' temp2= cama_form_select_multiple_bootstrap(ob, ob[:label], "checkbox",values) when 'submit' temp2 = "<button #{cf_attrs(ob[:custom_attrs])} type=\"#{ob[:field_type]}\" name=\"#{f_name}\" class=\"#{ob[:custom_class].presence || 'btn btn-default'}\">#{ob[:label]}</button>" when 'button' temp2 = "<button #{cf_attrs(ob[:custom_attrs])} type='button' name=\"#{f_name}\" class=\"#{ob[:custom_class].presence || 'btn btn-default'}\">#{ob[:label]}</button>" when 'reset_button' temp2 = "<button #{cf_attrs(ob[:custom_attrs])} type='reset' name=\"#{f_name}\" class=\"#{ob[:custom_class].presence || 'btn btn-default'}\">#{ob[:label]}</button>" when 'text', 'website', 'email' class_type = "" class_type = "railscf-field-#{ob[:field_type]}" if ob[:field_type]=="website" class_type = "railscf-field-#{ob[:field_type]}" if ob[:field_type]=="email" temp2 = "<input #{cf_attrs(ob[:custom_attrs])} type=\"#{ob[:field_type]}\" value=\"#{current_value}\" name=\"#{f_name}\" class=\"#{ob[:custom_class].presence || 'form-control'} #{class_type}\">" when 'captcha' if form.recaptcha_enabled? temp2 = else # The one field type whose attributes do not go through cf_attrs: cama_captcha_tag builds # its markup with Rails' `tag`, which escapes values and rewrites malformed names. That is # a documented exception to this file's verbatim contract rather than a gap in it -- `tag` # is the stricter of the two, so a trusted author's quoted value is escaped here and a # malformed attribute name is mangled rather than emitted. Left as it is deliberately: # reproducing cf_attrs would mean rebuilding the helper's output by string surgery, which # is a real risk of breaking the captcha for a consistency gain and no security gain. temp2 = cama_captcha_tag(5, {}, {class: "#{ob[:custom_class].presence || 'form-control'} field-captcha required"}.merge(ob[:custom_attrs])) end when 'file' temp2 = "<input multiple=\"multiple\" type=\"file\" value=\"\" name=\"#{f_name}[]\" #{cf_attrs(ob[:custom_attrs])} class=\"#{ob[:custom_class].presence || 'form-control'}\">" when 'dropdown' temp2 = cama_form_select_multiple_bootstrap(ob, ob[:label], "select",values) else end r[:template] = cf_substitute(r[:template], '[ci]' => temp2, '[descr ci]' => [:description].to_s.translate, '[label ci]' => for_name).sub('<p></p>', '') html += r[:template] end html end |
#cama_form_select_multiple_bootstrap(ob, title, type, values) ⇒ Object
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 196 def cama_form_select_multiple_bootstrap(ob, title, type, values) # Defensive, because a form saved before the gate required a well-formed option list carries # whatever it carries -- and `nil.each`, or `op[:label]` on a String, is a 500 on every visit to # the page. `Array()` alone will not do: on a Hash it yields key/value pairs. = ob[:field_options][:options] = (.is_a?(Hash) ? .values : Array()) .select { |op| op.is_a?(Hash) } include_other_option = ob[:field_options][:include_other_option] other_input = "" f_name = "fields[#{ob[:cid]}]" cid = ob[:cid].to_sym html = "" custom_class = ob[:custom_class].to_s if type == "radio" || type == "checkbox" other_input = (include_other_option)? "<div class=\"#{type} #{custom_class}\"> <label for=\"#{ob[:cid]}\"><input id=\"#{ob[:cid]}-other\" type=\"#{type}\" name=\"#{title.downcase}[]\" class=\"\">Other <input type=\"text\" /></label></div>" : " " else html = "<select #{cf_attrs(ob[:custom_attrs])} name=\"#{f_name}\" class=\"#{custom_class}\">" end .each do |op| label = op[:label].to_s.translate if type == "radio" || type == "checkbox" html += "<div class=\"#{type} #{custom_class}\"> <label for=\"#{ob[:cid]}\"> <input #{cf_attrs(ob[:custom_attrs])} type=\"#{type}\" #{'checked' if op[:checked].to_s.cama_true?} name=\"#{f_name}[]\" class=\"\" value=\"#{label.downcase}\"> #{label} </label> </div>" else # A dropdown submits the label lowercased with spaces collapsed to underscores. Derived once # so the emitted value and the `selected` comparison cannot drift apart -- but only here: # radio and checkbox have always submitted the plain lowercased label, and unifying the two # would silently change what every existing response row is compared against. option_value = label.downcase.gsub(" ", "_") html += "<option value=\"#{option_value}\" #{"selected" if option_value == values[cid] || op[:checked].to_s.cama_true? } >#{label}</option>" end end if type == "radio" || type == "checkbox" html += other_input else html += " </select>" end end |
#cama_form_shortcode(slug) ⇒ Object
HTML ==================
This returns the format of the plugin shortcode.
71 72 73 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 71 def cama_form_shortcode(slug) "[forms slug=#{slug}]" end |
#cf_attrs(attrs) ⇒ Object
Nothing in this file escapes anything, by design. Every value it interpolates -- an author's labels, descriptions, classes, default values, wrappers and templates, a visitor's redisplayed submission, and the structural identifiers the form builder generates -- reaches the page VERBATIM.
That is safe because it is enforced at the gate rather than at the sink. The admin controller refuses to store content an untrusted author may not write, and refuses structurally malformed values from anyone; the front controller refuses a submission carrying anything malign and echoes it back not at all. Stored content therefore always equals written content, so rendering it verbatim introduces nothing the writer did not put there -- and an author holding :manage, :contact_form_unfiltered_html can put markup, or script, anywhere in a form and have guests receive it exactly as written.
Emit a field's custom attributes verbatim.
Camaleon's Hash#to_attr_format is deliberately NOT used here. That method escapes values and drops keys that are not valid attribute names, which is exactly right for its other callers -- plugins and themes handing it data from who-knows-where -- but wrong for this one. field_attributes is authored content: it is validated when the form is saved, and an author holding the unfiltered-HTML grant is entitled to emit an event handler through it.
95 96 97 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 95 def cf_attrs(attrs) (attrs || {}).map { |key, value| "#{key} = \"#{value}\"" }.join(' ') end |
#cf_substitute(template, replacements) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 112 def cf_substitute(template, replacements) seen = Hash.new(0) template.to_s.gsub(CF_PLACEHOLDER) do |placeholder| seen[placeholder] += 1 if seen[placeholder] == 1 || CF_REPEATABLE_PLACEHOLDERS.include?(placeholder) replacements.fetch(placeholder, placeholder) else placeholder end end end |
#contact_form_admin_before_load ⇒ Object
57 58 59 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 57 def contact_form_admin_before_load ("settings", {icon: "envelope-o", title: t('plugins.cama_contact_form.title', default: 'Contact Form'), url: admin_plugins_cama_contact_form_admin_forms_path, datas: "data-intro='This plugin permit you to create you contact forms with desired fields and paste your short_code in any content.' data-position='right'"}) end |
#contact_form_app_before_load ⇒ Object
61 62 63 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 61 def contact_form_app_before_load shortcode_add('forms', plugin_view("forms_shorcode"), "This is a shortocode for contact form to permit you to put your contact form in any content. Sample: [forms slug='key-for-my-form']") end |
#contact_form_front_before_load ⇒ Object
65 66 67 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 65 def contact_form_front_before_load end |
#contact_form_on_active(plugin) ⇒ Object
here all actions on going to active you can run sql commands like this: results = ActiveRecord::Base.connection.execute(query); plugin: plugin model
47 48 49 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 47 def contact_form_on_active(plugin) end |
#contact_form_on_destroy(plugin) ⇒ Object
here all actions on plugin destroying plugin: plugin model
39 40 41 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 39 def contact_form_on_destroy(plugin) end |
#contact_form_on_export(args) ⇒ Object
7 8 9 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 7 def contact_form_on_export(args) args[:obj][:plugins][self_plugin_key] = JSON.parse(current_site.contact_forms.to_json(:include => [:responses])) end |
#contact_form_on_import(args) ⇒ Object
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 11 def contact_form_on_import(args) plugins = args[:data][:plugins] if plugins[self_plugin_key.to_sym].present? plugins[self_plugin_key.to_sym].each do |contact| unless current_site.contact_forms.where(slug: contact[:slug]).first.present? sba_data = ActionController::Parameters.new(contact) contact_new = current_site.contact_forms.new(sba_data.permit(:name, :slug, :count, :description, :value, :settings)) if contact_new.save! if contact[:get_field_groups] # save group fields save_field_group(contact_new, contact[:get_field_groups]) end save_field_values(contact_new, contact[:field_values]) if contact[:responses].present? # saving responses for this contact contact[:responses].each do |response| sba_data = ActionController::Parameters.new(response) contact_new.responses.create!(sba_data.permit(:name, :slug, :count, :description, :value, :settings)) end end args[:messages] << "Saved Plugin Contact Form: #{contact_new.name}" end end end end end |
#contact_form_on_inactive(plugin) ⇒ Object
here all actions on going to inactive plugin: plugin model
53 54 55 |
# File 'app/helpers/plugins/cama_contact_form/main_helper.rb', line 53 def contact_form_on_inactive(plugin) end |