diff --git a/lib/Surveys.jl b/lib/Surveys.jl
index c390037..600e24a 100644
--- a/lib/Surveys.jl
+++ b/lib/Surveys.jl
@@ -344,11 +344,11 @@ isvalid(r::Response, s::Survey) =
# General htmlrenderer
# ---------------------
-htmlcontent(::FormField, value) = ""
-htmlelement(::FormField) = "?"
-htmlattrs(::FormField, value) = []
-htmlvoidelem(::FormField) = false
-htmlpostprocess(::FormField, ::Symbol) = identity
+html_content(::FormField, value) = ""
+html_element(::FormField) = "?"
+html_attrs(::FormField, value) = []
+html_voidelem(::FormField) = false
+html_postprocess(::FormField, ::Symbol) = identity
elem(e::AbstractString, content::AbstractString="", attrs::Pair{Symbol,<:Any}...) =
Html.normal_element(content, e, [], attrs...)
@@ -357,20 +357,28 @@ elem(e::AbstractString, attrs::Pair{Symbol,<:Any}...) = elem(e, "", attrs...)
velem(e::AbstractString, attrs::Pair{Symbol,<:Any}...) =
Html.void_element(e, [], Vector{Pair{Symbol,Any}}(collect(attrs)))
+const html_escape_characters =
+ Dict('"' => """,
+ '&' => "&",
+ '<' => "<",
+ '>' => ">")
+html_escape(s::String) = replace(s, r"\"|&|<|>" => c -> html_escape_characters[c[1]])
+html_escape(::Missing) = ""
+
function htmlrender(field::FormField, value::Any, id, mandatory, invalid)
- element = htmlelement(field)
- attrs = vcat(htmlattrs(field, value),
+ element = html_element(field)
+ attrs = vcat(html_attrs(field, value),
[:id => string("qn-", id),
:name => id,
Symbol("aria-invalid") => invalid,
:required => mandatory && !isa(field, Checkbox)])
- if htmlvoidelem(field)
+ if html_voidelem(field)
velem(element, attrs...)
else
- content = htmlcontent(field, value)
+ content = html_content(field, value)
elem(element, if ismissing(content) "" else string(content) end,
attrs...)
- end |> htmlpostprocess(field, id)
+ end |> html_postprocess(field, id)
end
# ---------------------
@@ -388,28 +396,28 @@ struct FormInput{T} <: FormField{T}
end
end
-htmlelement(::FormInput) = "input"
-htmlvoidelem(::FormInput) = true
-htmlattrs(::FormInput, value) =
- [:value => if ismissing(value) false else string(value) end]
+html_element(::FormInput) = "input"
+html_voidelem(::FormInput) = true
+html_attrs(::FormInput, value) =
+ [:value => if ismissing(value) false else html_escape(string(value)) end]
#
interpret(::FormInput{Bool}, value::AbstractString) = value == "yes"
-htmlattrs(::FormInput{Bool}, value::Union{Bool, Missing}) =
+html_attrs(::FormInput{Bool}, value::Union{Bool, Missing}) =
[:type => "checkbox", :value => "yes", :checked => !ismissing(value) && value === true]
-htmlpostprocess(::FormInput{Bool}, id::Symbol) =
+html_postprocess(::FormInput{Bool}, id::Symbol) =
s -> string(input(type="hidden", name=id, value="no"), s)
#
-function htmlattrs(::FormInput{T}, value) where {T <: Union{Date, Number, Integer, String}}
+function html_attrs(::FormInput{T}, value) where {T <: Union{Date, Number, Integer, String}}
type = Dict(Date => "date",
Number => "number",
Integer => "number",
String => "text")[T]
[:type => type,
- :value => if ismissing(value) false else string(value) end]
+ :value => if ismissing(value) false else html_escape(string(value)) end]
end
const Checkbox = FormInput{Bool}
@@ -426,8 +434,8 @@ struct TextArea <: FormField{String} end
default_validators(::TextArea) = Function[wordlimit(500), charlimit(2500)]
-htmlelement(::TextArea) = "textarea"
-htmlcontent(::TextArea, value) = value
+html_element(::TextArea) = "textarea"
+html_content(::TextArea, value) = html_escape(value)
#