1# frozen_string_literal: true
2
3require "blather"
4
5class FormTemplate
6 def initialize(template, filename="template", **kwargs)
7 @args = kwargs
8 @template = template
9 @filename = filename
10 freeze
11 end
12
13 def self.render(path, **kwargs)
14 full_path = File.dirname(__dir__) + "/forms/#{path}.rb"
15 new(File.read(full_path), full_path, **kwargs).render
16 end
17
18 def render(**kwargs)
19 one = OneRender.new(**@args.merge(kwargs))
20 one.instance_eval(@template, @filename)
21 one.form
22 end
23
24 class OneRender
25 def initialize(**kwargs)
26 kwargs.each do |k, v|
27 instance_variable_set("@#{k}", v)
28 end
29 @__form = Blather::Stanza::X.new
30 @__builder = Nokogiri::XML::Builder.with(@__form)
31 end
32
33 def form!
34 @__type_set = true
35 @__form.type = :form
36 end
37
38 def result!
39 @__type_set = true
40 @__form.type = :result
41 end
42
43 def title(s)
44 @__form.title = s
45 end
46
47 def instructions(s)
48 @__form.instructions = s
49 end
50
51 def validate(field, datatype: nil, **kwargs)
52 Nokogiri::XML::Builder.with(field) do |xml|
53 xml.validate(
54 xmlns: "http://jabber.org/protocol/xdata-validate",
55 datatype: datatype || "xs:string"
56 ) do
57 xml.basic unless validation_type(xml, **kwargs)
58 end
59 end
60 end
61
62 def validation_type(xml, open: false, regex: nil, range: nil)
63 xml.open if open
64 xml.range(min: range.first, max: range.last) if range
65 xml.regex(regex.source) if regex
66 open || regex || range
67 end
68
69 def field(datatype: nil, open: false, regex: nil, range: nil, **kwargs)
70 f = Blather::Stanza::X::Field.new(kwargs)
71 if datatype || open || regex || range
72 validate(f, datatype: datatype, open: open, regex: regex, range: range)
73 end
74 @__form.fields += [f]
75 end
76
77 def xml
78 @__builder
79 end
80
81 def form
82 raise "Type never set" unless @__type_set
83
84 @__form
85 end
86 end
87end