cml 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/cml.gemspec +129 -0
- data/lib/cml/converters/jsawesome.rb +103 -0
- data/lib/cml/gold.rb +33 -0
- data/lib/cml/liquid_filters.rb +13 -0
- data/lib/cml/parser.rb +160 -0
- data/lib/cml/tag.rb +308 -0
- data/lib/cml/tags/checkbox.rb +77 -0
- data/lib/cml/tags/checkboxes.rb +38 -0
- data/lib/cml/tags/group.rb +25 -0
- data/lib/cml/tags/hidden.rb +17 -0
- data/lib/cml/tags/iterate.rb +86 -0
- data/lib/cml/tags/meta.rb +12 -0
- data/lib/cml/tags/multiple_text.rb +11 -0
- data/lib/cml/tags/option.rb +29 -0
- data/lib/cml/tags/radio.rb +48 -0
- data/lib/cml/tags/radios.rb +36 -0
- data/lib/cml/tags/ratings.rb +61 -0
- data/lib/cml/tags/search.rb +97 -0
- data/lib/cml/tags/select.rb +50 -0
- data/lib/cml/tags/text.rb +45 -0
- data/lib/cml/tags/textarea.rb +45 -0
- data/lib/cml/tags/thumb.rb +25 -0
- data/lib/cml/tags/unknown.rb +21 -0
- data/lib/cml.rb +15 -0
- data/spec/complex_spec.rb +127 -0
- data/spec/converters/jsawesome_spec.rb +75 -0
- data/spec/fixtures/complex.cml +23 -0
- data/spec/fixtures/html.cml +34 -0
- data/spec/fixtures/invalid.cml +10 -0
- data/spec/fixtures/script-style.cml +12 -0
- data/spec/fixtures/segfault.cml +1 -0
- data/spec/gold_spec.rb +29 -0
- data/spec/meta_spec.rb +47 -0
- data/spec/normalize_spec.rb +214 -0
- data/spec/show_data_spec.rb +308 -0
- data/spec/sorta_match.rb +41 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/tags/checkbox_spec.rb +155 -0
- data/spec/tags/checkboxes_spec.rb +171 -0
- data/spec/tags/group_spec.rb +108 -0
- data/spec/tags/hidden_spec.rb +17 -0
- data/spec/tags/iterate_spec.rb +259 -0
- data/spec/tags/meta_spec.rb +14 -0
- data/spec/tags/multiple_text_spec.rb +40 -0
- data/spec/tags/radios_spec.rb +81 -0
- data/spec/tags/ratings_spec.rb +79 -0
- data/spec/tags/search_spec.rb +132 -0
- data/spec/tags/select_spec.rb +76 -0
- data/spec/tags/tag_spec.rb +93 -0
- data/spec/tags/text_spec.rb +66 -0
- data/spec/tags/textarea_spec.rb +58 -0
- data/spec/tags/thumb_spec.rb +20 -0
- data/spec/tags/unknown_spec.rb +19 -0
- data/spec/validation_spec.rb +62 -0
- metadata +182 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Ratings < Tag
|
4
|
+
Template = <<-HTML.freeze
|
5
|
+
{{legend}}
|
6
|
+
<div class="cml_row">
|
7
|
+
<table>
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th></th>
|
11
|
+
{% for rating in ratings limit:10 %}
|
12
|
+
<th class="{{gold_classes[forloop.index0]}}">{{rating.raw_label}}</th>
|
13
|
+
{% endfor %}
|
14
|
+
<th></th>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
<tbody>
|
18
|
+
<tr>
|
19
|
+
<td>{{from}}</td>
|
20
|
+
{% for rating in ratings limit:10 %}
|
21
|
+
<td class="{{gold_classes[forloop.index0]}}">{{rating}}</td>
|
22
|
+
{% endfor %}
|
23
|
+
<td>{{to}}</td>
|
24
|
+
</tr>
|
25
|
+
</tbody>
|
26
|
+
</table>
|
27
|
+
</div>
|
28
|
+
HTML
|
29
|
+
|
30
|
+
def data
|
31
|
+
super.merge({
|
32
|
+
"ratings" => ratings,
|
33
|
+
"from" => @attrs["from"].to_s,
|
34
|
+
"to" => @attrs["to"].to_s,
|
35
|
+
"gold_classes" => gold_classes
|
36
|
+
})
|
37
|
+
end
|
38
|
+
|
39
|
+
def gold_classes
|
40
|
+
ratings.map {|rating| rating.gold_class }
|
41
|
+
end
|
42
|
+
|
43
|
+
def ratings
|
44
|
+
if @cml.xpath(".//cml:rating").empty?
|
45
|
+
max = @attrs["points"] ? @attrs["points"].to_s.to_i : 4
|
46
|
+
tags = Parser.parse((1..max).map do |r|
|
47
|
+
"<cml:rating label='#{r}' />"
|
48
|
+
end.join("\n")).xpath("root/cml:rating")
|
49
|
+
else
|
50
|
+
tags = @cml.xpath(".//cml:rating")
|
51
|
+
end
|
52
|
+
tags.map do |c|
|
53
|
+
c["validates"] ||= @attrs["validates"].to_s
|
54
|
+
c["name"] ||= name
|
55
|
+
(@opts[:normalize] ? Checkbox : Radio).new(c, @opts.merge(:bare => true))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
memoize :ratings
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Search < Tag
|
4
|
+
DEFAULT_CSE = "002077591359011991755:yygrm1glnxq"
|
5
|
+
BareTemplate = <<-HTML.freeze
|
6
|
+
<div class="cml_row search" data-engine="{{engine}}" data-cse="{{custom_search_engine}}" >
|
7
|
+
<input name="{{prefixed_search_terms_name}}" type="text" value="{{search_terms_value}}" class="{{search_terms_classes}}"/> <input type="button" value="Search" class="no_validate" />
|
8
|
+
</div>
|
9
|
+
<div class="cml_row results"></div>
|
10
|
+
{{inputs}}
|
11
|
+
HTML
|
12
|
+
|
13
|
+
Template = <<-HTML.freeze
|
14
|
+
{{label}}
|
15
|
+
#{BareTemplate}
|
16
|
+
HTML
|
17
|
+
|
18
|
+
InputTemplate = <<-HTML.freeze
|
19
|
+
<div class="cml_row selected_result">
|
20
|
+
<input name="{{name}}" type="text" class="{{classes}}" value="{{search_result_value}}" />
|
21
|
+
</div>
|
22
|
+
HTML
|
23
|
+
|
24
|
+
def is_field?
|
25
|
+
!(@attrs["field"] && @attrs["field"].to_s == "false")
|
26
|
+
end
|
27
|
+
|
28
|
+
def search_terms_classes
|
29
|
+
(@attrs["default"] ? "default " : "") + engine + " no_validate"
|
30
|
+
end
|
31
|
+
|
32
|
+
def engine
|
33
|
+
(@attrs["engine"] ? @attrs["engine"].to_s : nil) || "googlecse"
|
34
|
+
end
|
35
|
+
|
36
|
+
def custom_search_engine
|
37
|
+
engine.to_s == "googlecse" ? (@attrs["cse"] || DEFAULT_CSE).to_s : ""
|
38
|
+
end
|
39
|
+
|
40
|
+
def search_terms_name
|
41
|
+
name(true, "search_terms")
|
42
|
+
end
|
43
|
+
|
44
|
+
def prefixed_search_terms_name
|
45
|
+
prefix(search_terms_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def search_terms_value
|
49
|
+
((@opts[:data] || {})[search_terms_name] || @attrs["default"]).to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def search_result_value
|
53
|
+
(@attrs["value"] || (@opts[:data] || {})[name] || "").to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def data
|
57
|
+
super.merge({
|
58
|
+
"search_terms_classes" => search_terms_classes,
|
59
|
+
"engine" => engine,
|
60
|
+
"search_terms_name" => search_terms_name,
|
61
|
+
"prefixed_search_terms_name" => prefixed_search_terms_name,
|
62
|
+
"search_terms_value" => search_terms_value,
|
63
|
+
"search_result_value" => search_result_value,
|
64
|
+
"custom_search_engine" => custom_search_engine
|
65
|
+
})
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_html
|
69
|
+
if is_field?
|
70
|
+
if @opts[:normalize]
|
71
|
+
seeds = Array((@opts[:data] || {})[name])
|
72
|
+
seeds << nil if seeds.length == 0
|
73
|
+
|
74
|
+
inputs = seeds.map do |input|
|
75
|
+
Liquid::Template.parse(InputTemplate).render(data.merge({
|
76
|
+
"search_result_value" => input.to_s,
|
77
|
+
"classes" => classes+(input ? " cml_gold_loaded" : "")
|
78
|
+
}))
|
79
|
+
end.join("\n")
|
80
|
+
else
|
81
|
+
inputs = Liquid::Template.parse(InputTemplate).render(data)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
inputs = ""
|
85
|
+
end
|
86
|
+
|
87
|
+
wrapper(Liquid::Template.parse(Template).render(data.merge({
|
88
|
+
"inputs" => inputs
|
89
|
+
}), [LiquidFilters]))
|
90
|
+
end
|
91
|
+
|
92
|
+
def wrapper_classes
|
93
|
+
super + " text"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Select < Tag
|
4
|
+
Template = <<-HTML.freeze
|
5
|
+
{{label}}
|
6
|
+
<div class="cml_row"><select name="{{name}}" class="{{classes}}">
|
7
|
+
{{content}}
|
8
|
+
</select></div>
|
9
|
+
HTML
|
10
|
+
|
11
|
+
#Auto magically prepend a default option if required
|
12
|
+
def default
|
13
|
+
default = [Option.new("<cml:option value=\"\">#{@cml["default"]}</cml:option>", @opts)] if @cml["default"]
|
14
|
+
default ||= [Option.new("<cml:option value=\"\">Select one</cml:option>", @opts)] if validations.include?('validates-required')
|
15
|
+
default || []
|
16
|
+
end
|
17
|
+
|
18
|
+
def children
|
19
|
+
default + @cml.xpath(".//cml:option").map do |c|
|
20
|
+
Option.new(c, @opts)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
memoize :children
|
24
|
+
|
25
|
+
def data
|
26
|
+
super.merge({"content" => content})
|
27
|
+
end
|
28
|
+
|
29
|
+
def content
|
30
|
+
cloned= @cml.dup
|
31
|
+
c = children
|
32
|
+
# Add the default...
|
33
|
+
d = default
|
34
|
+
# Preloaded data
|
35
|
+
preload = preloaded_data
|
36
|
+
|
37
|
+
cloned.add_child(d[0].cml) if d.length > 0
|
38
|
+
cloned.xpath(".//cml:*[not(self::cml:option)]").remove
|
39
|
+
cloned.xpath(".//cml:option").each_with_index do |r,i|
|
40
|
+
r.namespace = nil
|
41
|
+
c[i].selected = true if preload && preload == c[i].value
|
42
|
+
r.replace(c[i].convert)
|
43
|
+
end
|
44
|
+
#Remove the surrounding tag
|
45
|
+
cloned.to_xhtml.gsub(/<\/?cml:select[^>]*?>|<\/?>/,'')
|
46
|
+
end
|
47
|
+
memoize :content
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Text < Tag
|
4
|
+
BareTemplate = <<-HTML.freeze
|
5
|
+
<div class="cml_row"><input name="{{name}}" type="text" value="{{value}}" class="{{classes}}"/></div>
|
6
|
+
HTML
|
7
|
+
|
8
|
+
Template = <<-HTML.freeze
|
9
|
+
{{label}}
|
10
|
+
#{BareTemplate}
|
11
|
+
HTML
|
12
|
+
|
13
|
+
def classes
|
14
|
+
super + (@attrs["default"] ? " default" : "")
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
(@attrs["value"] || @attrs["default"]).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_html
|
22
|
+
if @opts[:normalize]
|
23
|
+
#Making some text boxes
|
24
|
+
seeds = Array(@opts[:data][@opts[:parser].golds[name(false)]] || @opts[:data][name(false)])
|
25
|
+
seeds = @opts[:iteration] ? [seeds[@opts[:iteration]]].flatten : seeds
|
26
|
+
seeds << nil if seeds.length == 0
|
27
|
+
inputs = seeds.map do |input|
|
28
|
+
Liquid::Template.parse(BareTemplate).render(data.merge({
|
29
|
+
"value" => CGI.escapeHTML(input.to_s),
|
30
|
+
"classes" => classes+(input ? " cml_gold_loaded" : "")
|
31
|
+
}))
|
32
|
+
end.join("\n")
|
33
|
+
wrapper("#{label}\n#{inputs}")
|
34
|
+
elsif preload = preloaded_data
|
35
|
+
wrapper(Liquid::Template.parse(Template).render(data.merge({
|
36
|
+
"value" => CGI.escapeHTML(preload.to_s),
|
37
|
+
"classes" => classes
|
38
|
+
})))
|
39
|
+
else
|
40
|
+
wrapper(Liquid::Template.parse(Template).render(data, [LiquidFilters]))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Textarea < Tag
|
4
|
+
BareTemplate = <<-HTML.freeze
|
5
|
+
<div class="cml_row"><textarea name="{{name}}" class="{{classes}}">{{value}}</textarea></div>
|
6
|
+
HTML
|
7
|
+
|
8
|
+
Template = <<-HTML.freeze
|
9
|
+
{{label}}
|
10
|
+
#{BareTemplate}
|
11
|
+
HTML
|
12
|
+
|
13
|
+
def classes
|
14
|
+
super + (@attrs["default"] ? " default" : "")
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
(@attrs["value"] || @attrs["default"]).to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_html
|
22
|
+
if @opts[:normalize]
|
23
|
+
#Making some text boxes
|
24
|
+
seeds = Array(@opts[:data][@opts[:parser].golds[name(false)]] || @opts[:data][name(false)])
|
25
|
+
seeds = @opts[:iteration] ? [seeds[@opts[:iteration]]].flatten : seeds
|
26
|
+
seeds << nil if seeds.length == 0
|
27
|
+
inputs = seeds.map do |input|
|
28
|
+
Liquid::Template.parse(BareTemplate).render(data.merge({
|
29
|
+
"value" => input.to_s,
|
30
|
+
"classes" => classes+(input ? " cml_gold_loaded" : "")
|
31
|
+
}))
|
32
|
+
end.join("\n")
|
33
|
+
wrapper("#{label}\n#{inputs}")
|
34
|
+
elsif preload = preloaded_data
|
35
|
+
wrapper(Liquid::Template.parse(Template).render(data.merge({
|
36
|
+
"value" => preload.to_s,
|
37
|
+
"classes" => classes
|
38
|
+
})))
|
39
|
+
else
|
40
|
+
wrapper(Liquid::Template.parse(Template).render(data, [LiquidFilters]))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Thumb < Tag
|
4
|
+
Template = <<-HTML.freeze
|
5
|
+
<img src="http://nodenailer.crowdflower.com/?{{query_string}}" />
|
6
|
+
HTML
|
7
|
+
|
8
|
+
def validate?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def query_string
|
13
|
+
params = {}
|
14
|
+
[["w","width"], ["h", "height"], ["method", "method"], ["url", "src"]].each do |param, atr|
|
15
|
+
params[param] = CGI.escape(@attrs[atr].to_s) if @attrs[atr]
|
16
|
+
end
|
17
|
+
params.map {|v| v.join("=") }.join("&")
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
super.merge("query_string" => query_string)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CML
|
2
|
+
module Tags
|
3
|
+
class Unknown < Tag
|
4
|
+
Template = <<-HTML.freeze
|
5
|
+
{{content}}
|
6
|
+
HTML
|
7
|
+
|
8
|
+
def validate?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def wrapper_classes
|
13
|
+
super + " unknown"
|
14
|
+
end
|
15
|
+
|
16
|
+
def data
|
17
|
+
super.merge({"content" => @cml.inner_html})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/cml.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'json'
|
4
|
+
require 'liquid'
|
5
|
+
|
6
|
+
require 'cml/parser'
|
7
|
+
require 'cml/liquid_filters'
|
8
|
+
require 'cml/tag'
|
9
|
+
require 'cml/gold'
|
10
|
+
CML::TagClasses = {}
|
11
|
+
Dir[File.dirname(__FILE__) + '/cml/tags/*.rb'].each do |dir|
|
12
|
+
require dir
|
13
|
+
camelcase = dir.split(/\//).last.sub(/\.rb/,"")
|
14
|
+
CML::TagClasses[camelcase] = CML::Tags.const_get(camelcase.gsub(/(^|_)(.)/) { $2.upcase }.intern)
|
15
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "CML Complex" do
|
4
|
+
it "parses" do
|
5
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/complex.cml"), {:prefix => "u12345"})
|
6
|
+
#puts Parser.escape(@p.to_html).gsub(/\n/,"<br/>")
|
7
|
+
@p.to_html.should sorta_match(<<-HTML)
|
8
|
+
<div class="cml" id="u12345">
|
9
|
+
<h1>This is my name</h1>
|
10
|
+
<p>This is a description about me</p>
|
11
|
+
<div class="select cml_field">
|
12
|
+
<label class="legend">Awesome</label>
|
13
|
+
<div class="cml_row"><select name="u12345[awesome]" class="awesome validates-required">
|
14
|
+
<option value="">Choose an option</option>
|
15
|
+
<option>Awesome</option>
|
16
|
+
<option>Cool</option>
|
17
|
+
<option>Rad</option>
|
18
|
+
<option>Neat</option>
|
19
|
+
</select></div>
|
20
|
+
<p class="instructions">Just be cool about it</p>
|
21
|
+
</div>
|
22
|
+
<div class="text cml_field large">
|
23
|
+
<label class="legend">Opinion</label>
|
24
|
+
<div class="cml_row"><input name="u12345[opinion]" class="opinion validates-minLength:30 large" type="text" value=""></div>
|
25
|
+
</div>
|
26
|
+
<div class="text cml_field">
|
27
|
+
<label class="legend">Email</label>
|
28
|
+
<div class="cml_row"><input name="u12345[email]" class="email validates-required validates-email" type="text" value=""></div>
|
29
|
+
</div>
|
30
|
+
<div class="rad">
|
31
|
+
<div class="checkbox cml_field">
|
32
|
+
<div class="cml_row"><label class="">
|
33
|
+
<input name="u12345[you_sure]" class="you_sure" type="checkbox" value="yes"> You sure?</label></div>
|
34
|
+
</div>
|
35
|
+
</div>
|
36
|
+
<div class="group logic-only-if:awesome" style="color:red">
|
37
|
+
|
38
|
+
<div class="checkboxes cml_field">
|
39
|
+
<h2 class="legend">Cool checkboxes</h2>
|
40
|
+
|
41
|
+
<div class="cml_row"><label class="">
|
42
|
+
<input name="u12345[rad][]" class="rad" type="checkbox" value="Wanna do it?">
|
43
|
+
Wanna do it?</label></div>
|
44
|
+
|
45
|
+
<div class="cml_row"><label class="">
|
46
|
+
<input name="u12345[rad][]" class="rad" type="checkbox" value="Sure?">
|
47
|
+
Sure?</label></div>
|
48
|
+
<p class=\"instructions\">This <i>is</i> cool</p>
|
49
|
+
</div>
|
50
|
+
<div class="text cml_field">
|
51
|
+
<label class="legend">nice</label>
|
52
|
+
<div class="cml_row"><input name="u12345[nice]" class="nice" type="text" value=""></div>
|
53
|
+
</div>
|
54
|
+
<div class="hidden cml_field">
|
55
|
+
<input type="hidden" name="u12345[secret]" value="cool" class="secret" />
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
HTML
|
60
|
+
end
|
61
|
+
|
62
|
+
it "doesn't segfault" do
|
63
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/segfault.cml"), {:prefix => "u12345"})
|
64
|
+
@p.to_html
|
65
|
+
end
|
66
|
+
|
67
|
+
it "script / styles" do
|
68
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/script-style.cml"), {:prefix => "u12345"})
|
69
|
+
@p.to_html.should sorta_match(<<-HTML)
|
70
|
+
<div class="cml" id="u12345"><script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=Knx84fDV34H2VnhVU1DoD7chT1wjJ2r36uf4dZW7Vc5si9sqQRAYU_g8fo7zV.wF"> </script>
|
71
|
+
<script src="/javascripts/upload.js" type="text/javascript" charset="utf-8"> </script>
|
72
|
+
|
73
|
+
<script type="text/javascript">
|
74
|
+
var cool ='cool\'s';
|
75
|
+
</script>
|
76
|
+
<style type="text/css">
|
77
|
+
a { font: awesome;}
|
78
|
+
</style>
|
79
|
+
</div>
|
80
|
+
HTML
|
81
|
+
end
|
82
|
+
|
83
|
+
it "parses scripts and styles" do
|
84
|
+
@p = Parser.new(File.read(File.dirname(__FILE__) + "/fixtures/html.cml"), {:prefix => "u12345"})
|
85
|
+
@p.to_html.length.should > 900
|
86
|
+
#puts Parser.escape(@p.to_html).gsub(/\n/,"<br/>")
|
87
|
+
|
88
|
+
@p.to_html.should sorta_match(<<-HTML)
|
89
|
+
<div class="cml" id="u12345"><hr />
|
90
|
+
<a target="_blank" class="toggle" href="#">toggle series description</a>
|
91
|
+
<div style="display:none">
|
92
|
+
{{seriesdescription | textilize}}
|
93
|
+
</div>
|
94
|
+
<br style="clear:both" />
|
95
|
+
{% for image in image_name %}
|
96
|
+
<div class="wrap">
|
97
|
+
<img src="{{url}}/{{image}}" style="width:110px" /></div>
|
98
|
+
{% endfor %}
|
99
|
+
<br style="clear:both" />
|
100
|
+
<div class="text cml_field"><label class="legend">Cool dude</label>
|
101
|
+
<div class="cml_row"><input name="u12345[cool_dude]" class="cool_dude" value="" type="text" /></div>
|
102
|
+
</div>
|
103
|
+
<style media="screen" type="text/css">
|
104
|
+
div.wrap {
|
105
|
+
position:relative;
|
106
|
+
float:left;
|
107
|
+
margin:5px 5px 0 0;
|
108
|
+
}
|
109
|
+
</style>
|
110
|
+
<script type="text/javascript" charset="utf-8">
|
111
|
+
// query1 = 'compare'
|
112
|
+
// query2 = 'base'
|
113
|
+
if (1 < 1) {
|
114
|
+
var x = 0;
|
115
|
+
}
|
116
|
+
var ranking = [null]
|
117
|
+
//Some really long comment that doesn't get borked by libxml... don't you dare insert a new line.
|
118
|
+
//Why are my && disapearing?
|
119
|
+
if(ranking && !false) {
|
120
|
+
//Preserve my curlies
|
121
|
+
var unit_id = {{_unit_id}};
|
122
|
+
var rad = "even inside strings {{awesome}}"
|
123
|
+
}
|
124
|
+
</script></div>
|
125
|
+
HTML
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../../lib/cml/converters/jsawesome")
|
3
|
+
|
4
|
+
describe "JSAwesome Converter" do
|
5
|
+
it "converts" do
|
6
|
+
json = "[[
|
7
|
+
[\"text_field\", \"default value\"],
|
8
|
+
[\"#text_area\", \"\"],
|
9
|
+
[\"single_select\", [\"boo|moo\", \"~yah\"]],
|
10
|
+
[\"^check\", [\"One|totally_rad\", [\"two\",true], \"three\"]],
|
11
|
+
[\"*radio\", [\"a\", \"b|D\", [\"c\", true]]],
|
12
|
+
[\"_hidden\",\"hot\"],
|
13
|
+
[[\"^single_check\"],[\"^Edge|edge_case\", false]]
|
14
|
+
],
|
15
|
+
{\"text_field\": \"JSAwesome\",
|
16
|
+
\"text_area\": {
|
17
|
+
\"required\":true,
|
18
|
+
\"validation\": [\"\\d+\", \"Field must contain atleast one digit\"],
|
19
|
+
\"label\": \"Input some text with atleast one digit\"
|
20
|
+
},
|
21
|
+
\"single_select\": {
|
22
|
+
\"required\":true
|
23
|
+
},
|
24
|
+
\"gold\": {
|
25
|
+
\"rando\": \"so_cool\",
|
26
|
+
\"check\": \"check_gold\",
|
27
|
+
\"_awesome_gold_strict\": true,
|
28
|
+
\"text_field\": \"awesome_gold\",
|
29
|
+
\"_awesome_gold_regex\": [\"\\\\.asdf\\\\.\", \"i\"]
|
30
|
+
}}]"
|
31
|
+
@c = Converters::JSAwesome.new(json)
|
32
|
+
@c.convert.should sorta_match(<<-HTML)
|
33
|
+
<cml:text name="text_field" label="JSAwesome" default="default value">
|
34
|
+
<gold src="awesome_gold" flags="i" regex="\\.asdf\\." strict="true" />
|
35
|
+
</cml:text>
|
36
|
+
<cml:textarea name="text_area" validates="required" label="Input some text with atleast one digit" />
|
37
|
+
<cml:select label="Single select" validates="required">
|
38
|
+
<cml:option label="Boo" value="moo" />
|
39
|
+
<cml:option label="Yah" />
|
40
|
+
</cml:select>
|
41
|
+
<cml:checkboxes label="Check" gold="true">
|
42
|
+
<cml:checkbox label="One" value="totally_rad" />
|
43
|
+
<cml:checkbox label="Two" checked="true" />
|
44
|
+
<cml:checkbox label="Three" />
|
45
|
+
</cml:checkboxes>
|
46
|
+
<cml:radios label="Radio">
|
47
|
+
<cml:radio label="A" />
|
48
|
+
<cml:radio label="B" value="D" />
|
49
|
+
<cml:radio label="C" checked="true" />
|
50
|
+
</cml:radios>
|
51
|
+
<cml:hidden label="Hidden" value="hot" />
|
52
|
+
<cml:checkbox label="Single check" />
|
53
|
+
<cml:checkbox label="Edge" name="edge_case" default="false" />
|
54
|
+
<cml:meta name="rando" gold="so_cool"/>
|
55
|
+
HTML
|
56
|
+
end
|
57
|
+
|
58
|
+
it "Gets all complex" do
|
59
|
+
json = '[[["#w_forth_st",""],[["city",""],["stateprovince",""]],[["zippostal_code",""],["country",""]],["#extra_address_information",""],["^any_issues",["No address could be found even after checking the url or searching the web|searching_the_web"]]],{"w_forth_st":{"label":"Street address (eg. 35 W Forth St.)","required":true},"city":{"required":true},"stateprovince":{"label":"State\/Province"},"any_issues":{"label":"Any issues?"},"country":{"required":true},"zippostal_code":{"validation":["^[\\d-]*$","Postal code must only be numbers and dashes"],"label":"Zip\/Postal Code"},"extra_address_information":{"label":"Any extra company or address information?"}}]'
|
60
|
+
@c = Converters::JSAwesome.new(json)
|
61
|
+
@c.convert.should sorta_match(<<-HTML)
|
62
|
+
<cml:textarea label="Street address (eg. 35 W Forth St.)" name="w_forth_st" validates="required" />
|
63
|
+
<cml:text label="City" validates="required" />
|
64
|
+
<cml:text label="State/Province" name="stateprovince" />
|
65
|
+
HTML
|
66
|
+
|
67
|
+
#For some reason can't get this spec to pass... not worth my time right now.
|
68
|
+
#<cml:text label="Zip/Postal Code" name="zippostal_code" />
|
69
|
+
#<cml:text label="Country" validates="required" />
|
70
|
+
#<cml:textarea label="Any extra company or address information?" name="extra_address_information"/>
|
71
|
+
#<cml:checkboxes label="Any issues?" name="any_issues">
|
72
|
+
# <cml:checkbox label="No address could be found even after checking the url or searching the web" name="searching_the_web" />
|
73
|
+
#</cml:checkboxes>
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h1>This is my name</h1>
|
2
|
+
<p>This is a description about me</p>
|
3
|
+
<cml:select label="Awesome" validates="required" default="Choose an option" instructions="Just be cool about it">
|
4
|
+
<cml:gold src="awesome_gold" regex="\\.asdf\\." flags="i" no_escape="true" strict="true" />
|
5
|
+
<cml:option label="Awesome" />
|
6
|
+
<cml:option label="Cool" />
|
7
|
+
<cml:option label="Rad" />
|
8
|
+
<cml:option label="Neat" />
|
9
|
+
</cml:select>
|
10
|
+
<cml:text label="Opinion" validates="minLength:30" class="large" />
|
11
|
+
<cml:text label="Email" validates="required email" />
|
12
|
+
<div class="rad">
|
13
|
+
<cml:checkbox label="You sure?" value="yes" gold="true" />
|
14
|
+
</div>
|
15
|
+
<cml:group only-if="awesome" style="color:red">
|
16
|
+
<cml:checkboxes label="Cool checkboxes" name="rad">
|
17
|
+
<cml:instructions>This <i>is</i> great</cml:instructions>
|
18
|
+
<cml:checkbox label="Wanna do it?"/>
|
19
|
+
<cml:checkbox label="Sure?"/>
|
20
|
+
</cml:checkboxes>
|
21
|
+
<cml:text label="nice"/>
|
22
|
+
<cml:hidden name="secret" value="cool"/>
|
23
|
+
</cml:group>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<hr>
|
2
|
+
<a target="_blank" class="toggle" href="#">toggle series description</a>
|
3
|
+
<div style="display:none">
|
4
|
+
{{seriesdescription | textilize}}
|
5
|
+
</div>
|
6
|
+
<br style="clear:both">
|
7
|
+
{% for image in image_name %}
|
8
|
+
<div class="wrap">
|
9
|
+
<img src="{{url}}/{{image}}" style="width:110px"></div>
|
10
|
+
{% endfor %}
|
11
|
+
<br style="clear:both">
|
12
|
+
<cml:text label="Cool dude"/>
|
13
|
+
<style media="screen" type="text/css">
|
14
|
+
div.wrap {
|
15
|
+
position:relative;
|
16
|
+
float:left;
|
17
|
+
margin:5px 5px 0 0;
|
18
|
+
}
|
19
|
+
</style>
|
20
|
+
<script type="text/javascript" charset="utf-8">
|
21
|
+
// query1 = 'compare'
|
22
|
+
// query2 = 'base'
|
23
|
+
if (1 < 1) {
|
24
|
+
var x = 0;
|
25
|
+
}
|
26
|
+
var ranking = [null]
|
27
|
+
//Some really long comment that doesn't get borked by libxml... don't you dare insert a new line.
|
28
|
+
//Why are my && disapearing?
|
29
|
+
if(ranking && !false) {
|
30
|
+
//Preserve my curlies
|
31
|
+
var unit_id = {{_unit_id}};
|
32
|
+
var rad = "even inside strings {{awesome}}"
|
33
|
+
}
|
34
|
+
</script>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<cml:select label="Awesome">
|
2
|
+
<cml:gold src="awesome_gold" regex="\\.asdf\\." flags="i" no_escape="true" strict="true" />
|
3
|
+
<cml:option label="Awesome" />
|
4
|
+
<cml:option label="Rad" />
|
5
|
+
<cml:option label="Rad" />
|
6
|
+
<cml:option label="Neat" />
|
7
|
+
</cml:select>
|
8
|
+
<cml:text label="Opinion" validates="minLength:30" class="large" />
|
9
|
+
<cml:text label="Awesome" validates="required email" />
|
10
|
+
<cml:checkbox label="" value="yes" gold="true" />
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<script type="text/javascript" src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=Knx84fDV34H2VnhVU1DoD7chT1wjJ2r36uf4dZW7Vc5si9sqQRAYU_g8fo7zV.wF"></script>
|
2
|
+
<script src="/javascripts/upload.js" type="text/javascript" charset="utf-8"></script>
|
3
|
+
|
4
|
+
|
5
|
+
<script type="text/javascript">
|
6
|
+
var cool = 'cool\'s'
|
7
|
+
</script>
|
8
|
+
<style type="text/css">
|
9
|
+
.invisible{
|
10
|
+
a { font: awesome;}
|
11
|
+
}
|
12
|
+
</style>
|