cml 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +33 -0
- data/README.rdoc +13 -3
- data/Rakefile +9 -49
- data/cml.gemspec +23 -125
- data/lib/cml/converters/jsawesome.rb +3 -3
- data/lib/cml/gold.rb +12 -7
- data/lib/cml/liquid_filters.rb +4 -0
- data/lib/cml/logic.rb +424 -0
- data/lib/cml/logic_tree/graph.rb +107 -0
- data/lib/cml/logic_tree/solver.rb +43 -0
- data/lib/cml/parser.rb +47 -7
- data/lib/cml/tag.rb +42 -21
- data/lib/cml/tags/checkbox.rb +14 -4
- data/lib/cml/tags/checkboxes.rb +4 -0
- data/lib/cml/tags/group.rb +4 -0
- data/lib/cml/tags/hours.rb +263 -0
- data/lib/cml/tags/iterate.rb +4 -0
- data/lib/cml/tags/meta.rb +4 -0
- data/lib/cml/tags/option.rb +4 -0
- data/lib/cml/tags/radio.rb +13 -4
- data/lib/cml/tags/radios.rb +4 -0
- data/lib/cml/tags/ratings.rb +9 -1
- data/lib/cml/tags/search.rb +8 -2
- data/lib/cml/tags/select.rb +6 -2
- data/lib/cml/tags/taxonomy.rb +148 -0
- data/lib/cml/tags/thumb.rb +4 -0
- data/lib/cml/tags/unknown.rb +4 -0
- data/lib/cml/version.rb +3 -0
- data/lib/cml.rb +3 -0
- data/spec/converters/jsawesome_spec.rb +0 -9
- data/spec/fixtures/logic_broken.cml +5 -0
- data/spec/fixtures/logic_circular.cml +5 -0
- data/spec/fixtures/logic_grouped.cml +7 -0
- data/spec/fixtures/logic_nested.cml +7 -0
- data/spec/fixtures/logic_none.cml +7 -0
- data/spec/fixtures/logic_not_nested.cml +7 -0
- data/spec/liquid_filter_spec.rb +19 -0
- data/spec/logic_depends_on_spec.rb +242 -0
- data/spec/logic_spec.rb +207 -0
- data/spec/logic_tree_graph_spec.rb +465 -0
- data/spec/logic_tree_solver_spec.rb +58 -0
- data/spec/meta_spec.rb +12 -2
- data/spec/show_data_spec.rb +3 -2
- data/spec/spec_helper.rb +22 -6
- data/spec/tags/checkboxes_spec.rb +2 -2
- data/spec/tags/group_spec.rb +5 -5
- data/spec/tags/hours_spec.rb +404 -0
- data/spec/tags/radios_spec.rb +2 -2
- data/spec/tags/ratings_spec.rb +1 -1
- data/spec/tags/select_spec.rb +45 -0
- data/spec/tags/tag_spec.rb +25 -0
- data/spec/tags/taxonomy_spec.rb +112 -0
- data/spec/validation_spec.rb +52 -0
- metadata +112 -17
- data/VERSION +0 -1
data/lib/cml/tag.rb
CHANGED
@@ -2,9 +2,28 @@ require 'cgi'
|
|
2
2
|
|
3
3
|
module CML
|
4
4
|
class Tag
|
5
|
+
|
6
|
+
include CML::TagLogic
|
7
|
+
|
5
8
|
attr_reader :attrs, :tag, :data, :cml, :opts
|
6
9
|
#liquid_methods :raw_label
|
7
10
|
|
11
|
+
#memoize hotness
|
12
|
+
def self.memoize(*methods)
|
13
|
+
methods.each do |m|
|
14
|
+
class_eval %Q{
|
15
|
+
alias :original_#{m} :#{m}
|
16
|
+
|
17
|
+
def #{m}(*args)
|
18
|
+
@#{m}_cache ||= {}
|
19
|
+
key = {:prefix => @opts[:prefix], :missed => @opts[:missed]}.merge(:_args => args)
|
20
|
+
return @#{m}_cache[key] if @#{m}_cache[key]
|
21
|
+
@#{m}_cache[key] = self.original_#{m}(*args)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
8
27
|
def initialize(cml, opts = {})
|
9
28
|
@cml = cml.is_a?(String) ? Parser.parse(cml).at("/root/*") : cml
|
10
29
|
@attrs = @cml.attributes#Hash[*cml.attributes.map {|k,v| [k.intern,v]}.flatten]
|
@@ -16,10 +35,14 @@ module CML
|
|
16
35
|
def prefix(name)
|
17
36
|
if @opts[:iteration]
|
18
37
|
m = case @tag
|
19
|
-
when "checkbox"
|
20
|
-
|
21
|
-
when "
|
22
|
-
|
38
|
+
when "checkbox"
|
39
|
+
"[{{i}}][]"
|
40
|
+
when "radio"
|
41
|
+
"[{{i}}]"
|
42
|
+
when "rating"
|
43
|
+
@opts[:normalize] ? "[{{i}}][]" : "[{{i}}]"
|
44
|
+
when "text", "textarea"
|
45
|
+
@opts[:normalize] ? "[{{i}}][]" : "[]"
|
23
46
|
else
|
24
47
|
"[]"
|
25
48
|
end
|
@@ -52,7 +75,8 @@ module CML
|
|
52
75
|
#:list means an array of values in the result csv
|
53
76
|
#:columnlist means a new column that is a list
|
54
77
|
def multi_type
|
55
|
-
grouped =
|
78
|
+
grouped = self.parent_multiples
|
79
|
+
|
56
80
|
if @attrs["multiple"] || !grouped.empty?
|
57
81
|
if @cml.at(".//cml:checkboxes|.//cml:radios|.//cml:ratings")
|
58
82
|
:column
|
@@ -72,6 +96,11 @@ module CML
|
|
72
96
|
end
|
73
97
|
end
|
74
98
|
|
99
|
+
def parent_multiples
|
100
|
+
@cml.xpath("ancestor::cml:*[@multiple]")
|
101
|
+
end
|
102
|
+
memoize :parent_multiples
|
103
|
+
|
75
104
|
def gold?
|
76
105
|
@attrs["gold"] ? @cml : @cml.at("./cml:gold")
|
77
106
|
end
|
@@ -191,7 +220,7 @@ module CML
|
|
191
220
|
end
|
192
221
|
|
193
222
|
def validations
|
194
|
-
@validations ||= validators.map {|v| "validates-#{v}"}
|
223
|
+
@validations ||= validators.map {|v| v.to_s.empty? ? nil : "validates-#{v}"}.compact
|
195
224
|
end
|
196
225
|
|
197
226
|
def instructions
|
@@ -264,6 +293,10 @@ module CML
|
|
264
293
|
})
|
265
294
|
end
|
266
295
|
|
296
|
+
def finite_value?
|
297
|
+
(@attrs['is-finite'] && @attrs['is-finite'].value=='true') || false
|
298
|
+
end
|
299
|
+
|
267
300
|
protected
|
268
301
|
|
269
302
|
def data_attributes
|
@@ -288,21 +321,9 @@ module CML
|
|
288
321
|
|
289
322
|
attributes.join(" ")
|
290
323
|
end
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
methods.each do |m|
|
295
|
-
class_eval %Q{
|
296
|
-
alias :original_#{m} :#{m}
|
297
|
-
|
298
|
-
def #{m}(*args)
|
299
|
-
@#{m}_cache ||= {}
|
300
|
-
key = {:prefix => @opts[:prefix], :missed => @opts[:missed]}.merge(:_args => args)
|
301
|
-
return @#{m}_cache[key] if @#{m}_cache[key]
|
302
|
-
@#{m}_cache[key] = send(:original_#{m}, *args)
|
303
|
-
end
|
304
|
-
}
|
305
|
-
end
|
324
|
+
|
325
|
+
def title_attribute
|
326
|
+
@attrs['title'].nil? ? "" :"title=\"#{@attrs['title']}\""
|
306
327
|
end
|
307
328
|
end
|
308
329
|
end
|
data/lib/cml/tags/checkbox.rb
CHANGED
@@ -7,7 +7,7 @@ module CML
|
|
7
7
|
HTML
|
8
8
|
|
9
9
|
Template = <<-HTML.freeze
|
10
|
-
{{default_normalized}}<div class="cml_row"><label class="{{gold_class}}">#{BareTemplate} {{label}}</label></div>
|
10
|
+
{{default_normalized}}<div class="cml_row" {{title}}><label class="{{gold_class}}">#{BareTemplate} {{label}}</label></div>
|
11
11
|
HTML
|
12
12
|
|
13
13
|
def prefix(name)
|
@@ -20,6 +20,14 @@ module CML
|
|
20
20
|
@opts[:bare] || (@cml.parent && @cml.parent.name == "checkboxes")
|
21
21
|
end
|
22
22
|
|
23
|
+
def in_logic_graph?
|
24
|
+
!grouped?
|
25
|
+
end
|
26
|
+
|
27
|
+
def finite_value?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
23
31
|
def wrapper(parsed)
|
24
32
|
grouped? || @opts[:no_reason] ? parsed : super
|
25
33
|
end
|
@@ -47,7 +55,7 @@ module CML
|
|
47
55
|
end
|
48
56
|
elsif preload = preloaded_data
|
49
57
|
manipulated = true
|
50
|
-
if preload.map{|x| x.to_s.downcase }.include?(value.to_s.downcase)
|
58
|
+
if Array(preload).map{|x| x.to_s.downcase }.include?(value.to_s.downcase)
|
51
59
|
return "checked=\"checked\""
|
52
60
|
end
|
53
61
|
end
|
@@ -70,8 +78,10 @@ module CML
|
|
70
78
|
"default" => default,
|
71
79
|
"default_normalized" => default_normalized,
|
72
80
|
"checked" => c,
|
73
|
-
"label" => @attrs["label"].to_s
|
81
|
+
"label" => @attrs["label"].to_s,
|
82
|
+
"title" => title_attribute
|
83
|
+
})
|
74
84
|
end
|
75
85
|
end
|
76
86
|
end
|
77
|
-
end
|
87
|
+
end
|
data/lib/cml/tags/checkboxes.rb
CHANGED
data/lib/cml/tags/group.rb
CHANGED
@@ -0,0 +1,263 @@
|
|
1
|
+
module CML
|
2
|
+
|
3
|
+
class TimeSelect
|
4
|
+
HOURS = [12, 1.upto(11).to_a]
|
5
|
+
MINUTES = [0, 15, 30, 45]
|
6
|
+
SUFFIXES = [:am, :pm]
|
7
|
+
|
8
|
+
BlankOption = "<option value=\"\">Select one:</option>"
|
9
|
+
GoldBlankOption = "<option value=\"\">(Any)</option>"
|
10
|
+
NotListedOption = "<option{{selected_att}} value=\"not_listed\">(Not listed)</option>"
|
11
|
+
|
12
|
+
# Builds a time <select> input that submits military time values.
|
13
|
+
def self.build( name, gold=false, opts={} )
|
14
|
+
opts = {
|
15
|
+
:selected => nil,
|
16
|
+
:allow_unlisted => false
|
17
|
+
}.merge( opts )
|
18
|
+
|
19
|
+
time_options = SUFFIXES.map do |am_pm|
|
20
|
+
HOURS.flatten.map do |h|
|
21
|
+
h_mil = h
|
22
|
+
h_mil = 0 if h_mil == 12 && am_pm == :am
|
23
|
+
MINUTES.map do |m|
|
24
|
+
time_label = "#{h}:#{self.zero_pad(m)}#{am_pm}"
|
25
|
+
mil_time = self.to_military( h_mil, m, am_pm )
|
26
|
+
selected_att = mil_time == opts[:selected] ? " selected=\"selected\"" : ""
|
27
|
+
"<option#{selected_att} value=\"#{mil_time}\">#{time_label}</option>"
|
28
|
+
end.join("")
|
29
|
+
end.join("")
|
30
|
+
end.join("")
|
31
|
+
extras = gold ? GoldBlankOption : BlankOption
|
32
|
+
|
33
|
+
# Add the not listed field and select it if needed
|
34
|
+
if opts[:allow_unlisted]
|
35
|
+
selected_att = "not_listed" == opts[:selected] ? " selected=\"selected\"" : ""
|
36
|
+
not_listed_html = Liquid::Template.parse( NotListedOption ).render( "selected_att" => selected_att )
|
37
|
+
extras += not_listed_html
|
38
|
+
end
|
39
|
+
|
40
|
+
"<select name=\"#{name}\" class=\"cml_hours_time\">#{extras}#{time_options}</select>"
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def self.zero_pad( num )
|
46
|
+
'%02d' % num
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.to_military( hour, minute, am_pm )
|
50
|
+
if am_pm == :am
|
51
|
+
hour = 0 if minute == 0 && hour == 12
|
52
|
+
elsif hour < 12
|
53
|
+
hour = hour + 12
|
54
|
+
end
|
55
|
+
|
56
|
+
"#{self.zero_pad( hour )}:#{self.zero_pad( minute )}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# =============
|
61
|
+
# = CML:Hours =
|
62
|
+
# =============
|
63
|
+
|
64
|
+
module Tags
|
65
|
+
class Hours < Tag
|
66
|
+
|
67
|
+
DAYS = [
|
68
|
+
{ :key => 'mon', :label => "Monday" },
|
69
|
+
{ :key => 'tue', :label => "Tuesday" },
|
70
|
+
{ :key => 'wed', :label => "Wednesday" },
|
71
|
+
{ :key => 'thu', :label => "Thursday" },
|
72
|
+
{ :key => 'fri', :label => "Friday" },
|
73
|
+
{ :key => 'sat', :label => "Saturday" },
|
74
|
+
# { :key => 'cat', :label => "Caturday" },
|
75
|
+
{ :key => 'sun', :label => "Sunday" }
|
76
|
+
]
|
77
|
+
|
78
|
+
# =============
|
79
|
+
# = Templates =
|
80
|
+
# =============
|
81
|
+
|
82
|
+
Template = <<-HTML.freeze
|
83
|
+
{{label}}
|
84
|
+
<table class="cml_hours cml_row {{classes}}">
|
85
|
+
{{rows_html}}
|
86
|
+
</table>
|
87
|
+
HTML
|
88
|
+
|
89
|
+
RowTemplate = Liquid::Template.parse(<<-HTML.freeze)
|
90
|
+
<tr class="cml_hours_{{day_key}}">
|
91
|
+
<td class="cml_hours_day">{{day_label}}</td>
|
92
|
+
<td class="cml_hours_hours">
|
93
|
+
<p class="cml_hours_1">
|
94
|
+
<span class="cml_hours_selects">{{hours_open_1}}</span>
|
95
|
+
<span class="cml_hours_to">to</span>
|
96
|
+
<span class="cml_hours_selects">{{hours_close_1}}</span>
|
97
|
+
</p>
|
98
|
+
<p class="cml_hours_2">
|
99
|
+
<span class="cml_hours_selects">{{hours_open_2}}</span>
|
100
|
+
<span class="cml_hours_to">to</span>
|
101
|
+
<span class="cml_hours_selects">{{hours_close_2}}</span>
|
102
|
+
</p>
|
103
|
+
</td>
|
104
|
+
<td class="cml_hours_open_close">
|
105
|
+
<p class="cml_hours_openallday">
|
106
|
+
{{open_checkbox}}
|
107
|
+
</p>
|
108
|
+
<p class="cml_hours_closedallday">
|
109
|
+
{{closed_checkbox}}
|
110
|
+
</p>
|
111
|
+
</td>
|
112
|
+
</tr>
|
113
|
+
HTML
|
114
|
+
|
115
|
+
TrueFalseCheckboxTemplate = Liquid::Template.parse(<<-HTML)
|
116
|
+
<input type="hidden" name="{{name}}" value="FALSE" />
|
117
|
+
<input {{checked}}type="checkbox" name="{{name}}" id="{{id}}" value="TRUE" />
|
118
|
+
<label for="{{id}}">{{label}}</label>
|
119
|
+
HTML
|
120
|
+
|
121
|
+
TimeSelectTemplate = Liquid::Template.parse( TimeSelect.build( "{{name}}", false ) )
|
122
|
+
TimeSelectTemplateAllowUnlisted = Liquid::Template.parse( TimeSelect.build( "{{name}}", false, :allow_unlisted => true ) )
|
123
|
+
|
124
|
+
def initialize(cml, opts = {})
|
125
|
+
super( cml, opts )
|
126
|
+
@attrs["matcher"] = "hours"
|
127
|
+
@attrs["validates"] = @attrs["validates"].to_s + " hours"
|
128
|
+
@attrs["allowunlisted"] = !(@attrs["allowunlisted"].to_s =~ /^t/i).nil?
|
129
|
+
end
|
130
|
+
|
131
|
+
def finite_value?
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
# =============
|
136
|
+
# = Rendering =
|
137
|
+
# =============
|
138
|
+
|
139
|
+
def to_html
|
140
|
+
data = self.data.merge({
|
141
|
+
"rows_html" => rows_html
|
142
|
+
})
|
143
|
+
rendered = Liquid::Template.parse( Template ).render( data )
|
144
|
+
wrapper( rendered )
|
145
|
+
end
|
146
|
+
|
147
|
+
# =============
|
148
|
+
# = Normalize =
|
149
|
+
# =============
|
150
|
+
|
151
|
+
def normalize?
|
152
|
+
@opts[:normalize]
|
153
|
+
end
|
154
|
+
|
155
|
+
def raw_data
|
156
|
+
@opts[:data] || {}
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns data value as array of values or nil, if none.
|
160
|
+
def normalized_data_value( name )
|
161
|
+
val = raw_data[name]
|
162
|
+
if val && !val.empty?
|
163
|
+
Array( val )
|
164
|
+
else
|
165
|
+
nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# "true", true, "coolio" --> true
|
170
|
+
# "false", false, "", nil --> false
|
171
|
+
def truthy_checkbox_value?( value )
|
172
|
+
value = value.is_a?(Array) ? value[0].to_s : value.to_s
|
173
|
+
!( value.empty? || value =~ /^f/i )
|
174
|
+
end
|
175
|
+
|
176
|
+
# ===============
|
177
|
+
# = Field names =
|
178
|
+
# ===============
|
179
|
+
|
180
|
+
# Builds a field name for the given day and suffix. e.g:
|
181
|
+
# field_name( <tue>, "open_1" ) --> "u123[my_field_tue_open_1]"
|
182
|
+
def field_name( day, field_suffix )
|
183
|
+
prefix( name( true, "#{day[:key]}_#{field_suffix}" ) )
|
184
|
+
end
|
185
|
+
|
186
|
+
protected
|
187
|
+
|
188
|
+
# Render a time <select> for the given day and field suffix ("open_1",
|
189
|
+
# "closed_1", etc.)
|
190
|
+
def time_select_html( day, suffix )
|
191
|
+
key = name( true, "#{day[:key]}_#{suffix}" )
|
192
|
+
name = field_name( day, suffix )
|
193
|
+
allow_unlisted = @attrs["allowunlisted"]
|
194
|
+
|
195
|
+
if normalize?
|
196
|
+
if values = self.normalized_data_value( key )
|
197
|
+
# With preloaded values
|
198
|
+
values.map do |value|
|
199
|
+
TimeSelect.build( name, true, {
|
200
|
+
:selected => value,
|
201
|
+
:allow_unlisted => allow_unlisted
|
202
|
+
})
|
203
|
+
end.join( "\n" )
|
204
|
+
else
|
205
|
+
# No preloaded values
|
206
|
+
TimeSelect.build( name, true, :allow_unlisted => allow_unlisted )
|
207
|
+
end
|
208
|
+
else
|
209
|
+
template = allow_unlisted ? TimeSelectTemplateAllowUnlisted : TimeSelectTemplate
|
210
|
+
template.render( 'name' => name )
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Turn any string into a reasonable id attribute
|
215
|
+
def make_id( str )
|
216
|
+
"id_#{str}".gsub(/[^a-z0-9\{\}]/, "_").gsub(/_+/, "_").sub(/_+$/, "")
|
217
|
+
end
|
218
|
+
|
219
|
+
# Render HTML with a <tr> of inputs for every day of the week
|
220
|
+
def rows_html
|
221
|
+
DAYS.map do |day|
|
222
|
+
RowTemplate.render({
|
223
|
+
"day_key" => day[:key],
|
224
|
+
"day_label" => day[:label],
|
225
|
+
'open_checkbox' => self.open_all_day_html( day ),
|
226
|
+
'closed_checkbox' => self.closed_all_day_html( day ),
|
227
|
+
"hours_open_1" => self.time_select_html( day, "open_1" ),
|
228
|
+
"hours_close_1" => self.time_select_html( day, "close_1" ),
|
229
|
+
"hours_open_2" => self.time_select_html( day, "open_2" ),
|
230
|
+
"hours_close_2" => self.time_select_html( day, "close_2" )
|
231
|
+
})
|
232
|
+
end.join("\n")
|
233
|
+
end
|
234
|
+
|
235
|
+
def open_all_day_html( day )
|
236
|
+
self.checkbox_html( "Open all day", day, "openallday" )
|
237
|
+
end
|
238
|
+
|
239
|
+
def closed_all_day_html( day )
|
240
|
+
self.checkbox_html( "Closed all day", day, "closedallday" )
|
241
|
+
end
|
242
|
+
|
243
|
+
# Build HTML for a "TRUE" / "FALSE" checkbox with the usual hidden input
|
244
|
+
# hackery.
|
245
|
+
def checkbox_html( label, day, suffix )
|
246
|
+
key = name( true, "#{day[:key]}_#{suffix}" )
|
247
|
+
name = field_name( day, suffix )
|
248
|
+
if truthy_checkbox_value?( raw_data[key] )
|
249
|
+
checked = "checked=\"checked\" "
|
250
|
+
else
|
251
|
+
checked = ""
|
252
|
+
end
|
253
|
+
|
254
|
+
TrueFalseCheckboxTemplate.render({
|
255
|
+
'name' => name,
|
256
|
+
'id' => self.make_id( name ),
|
257
|
+
'label' => label,
|
258
|
+
'checked' => checked
|
259
|
+
})
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
data/lib/cml/tags/iterate.rb
CHANGED
data/lib/cml/tags/meta.rb
CHANGED
data/lib/cml/tags/option.rb
CHANGED
data/lib/cml/tags/radio.rb
CHANGED
@@ -6,7 +6,7 @@ module CML
|
|
6
6
|
HTML
|
7
7
|
|
8
8
|
Template = <<-HTML.freeze
|
9
|
-
<div class="cml_row"><label class="{{gold_class}}">#{BareTemplate} {{label}}</label></div>
|
9
|
+
<div class="cml_row" {{title}}><label class="{{gold_class}}">#{BareTemplate} {{label}}</label></div>
|
10
10
|
HTML
|
11
11
|
|
12
12
|
#Radios should always be grouped, but for consistency with checkboxes, we check
|
@@ -14,6 +14,14 @@ module CML
|
|
14
14
|
@opts[:bare] || (@cml.parent && ["radios","ratings"].include?(@cml.parent.name))
|
15
15
|
end
|
16
16
|
|
17
|
+
def in_logic_graph?
|
18
|
+
!grouped?
|
19
|
+
end
|
20
|
+
|
21
|
+
def finite_value?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
17
25
|
def wrapper(parsed)
|
18
26
|
grouped? ? parsed : super
|
19
27
|
end
|
@@ -30,7 +38,7 @@ module CML
|
|
30
38
|
manipulated = !@opts[:missed].nil?
|
31
39
|
if preload = preloaded_data
|
32
40
|
manipulated = true
|
33
|
-
if preload.map{|x| x.to_s.downcase }.include?(value.to_s.downcase)
|
41
|
+
if Array(preload).map{|x| x.to_s.downcase }.include?(value.to_s.downcase)
|
34
42
|
return "checked=\"checked\""
|
35
43
|
end
|
36
44
|
end
|
@@ -40,9 +48,10 @@ module CML
|
|
40
48
|
def data
|
41
49
|
super.merge({
|
42
50
|
"checked" => checked,
|
43
|
-
"label" => @attrs["label"].to_s
|
51
|
+
"label" => @attrs["label"].to_s,
|
52
|
+
"title" => title_attribute
|
44
53
|
})
|
45
54
|
end
|
46
55
|
end
|
47
56
|
end
|
48
|
-
end
|
57
|
+
end
|
data/lib/cml/tags/radios.rb
CHANGED
data/lib/cml/tags/ratings.rb
CHANGED
@@ -39,6 +39,10 @@ module CML
|
|
39
39
|
def gold_classes
|
40
40
|
ratings.map {|rating| rating.gold_class }
|
41
41
|
end
|
42
|
+
|
43
|
+
def children
|
44
|
+
ratings
|
45
|
+
end
|
42
46
|
|
43
47
|
def ratings
|
44
48
|
if @cml.xpath(".//cml:rating").empty?
|
@@ -56,6 +60,10 @@ module CML
|
|
56
60
|
end
|
57
61
|
end
|
58
62
|
memoize :ratings
|
63
|
+
|
64
|
+
def finite_value?
|
65
|
+
true
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
61
|
-
end
|
69
|
+
end
|
data/lib/cml/tags/search.rb
CHANGED
@@ -25,6 +25,10 @@ module CML
|
|
25
25
|
!(@attrs["field"] && @attrs["field"].to_s == "false")
|
26
26
|
end
|
27
27
|
|
28
|
+
def in_logic_graph?
|
29
|
+
is_field?
|
30
|
+
end
|
31
|
+
|
28
32
|
def search_terms_classes
|
29
33
|
(@attrs["default"] ? "default " : "") + engine + " no_validate"
|
30
34
|
end
|
@@ -46,11 +50,13 @@ module CML
|
|
46
50
|
end
|
47
51
|
|
48
52
|
def search_terms_value
|
49
|
-
((@opts[:data] || {})[search_terms_name] || @attrs["default"])
|
53
|
+
val = ((@opts[:data] || {})[search_terms_name] || @attrs["default"])
|
54
|
+
val.is_a?(Array) ? val[0].to_s : val.to_s
|
50
55
|
end
|
51
56
|
|
52
57
|
def search_result_value
|
53
|
-
(@attrs["value"] || (@opts[:data] || {})[name] || "")
|
58
|
+
val = (@attrs["value"] || (@opts[:data] || {})[name] || "")
|
59
|
+
val.is_a?(Array) ? val[0].to_s : val.to_s
|
54
60
|
end
|
55
61
|
|
56
62
|
def data
|
data/lib/cml/tags/select.rb
CHANGED
@@ -34,7 +34,7 @@ module CML
|
|
34
34
|
# Preloaded data
|
35
35
|
preload = preloaded_data
|
36
36
|
|
37
|
-
cloned.
|
37
|
+
cloned.children.first.add_previous_sibling(d[0].cml) if d.length > 0
|
38
38
|
cloned.xpath(".//cml:*[not(self::cml:option)]").remove
|
39
39
|
cloned.xpath(".//cml:option").each_with_index do |r,i|
|
40
40
|
r.namespace = nil
|
@@ -45,6 +45,10 @@ module CML
|
|
45
45
|
cloned.to_xhtml.gsub(/<\/?cml:select[^>]*?>|<\/?>/,'')
|
46
46
|
end
|
47
47
|
memoize :content
|
48
|
+
|
49
|
+
def finite_value?
|
50
|
+
true
|
51
|
+
end
|
48
52
|
end
|
49
53
|
end
|
50
|
-
end
|
54
|
+
end
|