dolores-cml 0.3.0

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 ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Van Pelt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = cml
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2009 Chris Van Pelt. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,56 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "cml"
8
+ gem.summary = "CML is CrowdFlower Markup Language"
9
+ gem.description = "CML let's you easily create form elements and custom interfaces for the CrowdFlower Croud Labor platform"
10
+ gem.email = "vanpelt@doloreslabs.com"
11
+ gem.homepage = "http://github.com/dolores/cml"
12
+ gem.authors = ["Chris Van Pelt"]
13
+ gem.add_dependency 'liquid', '>= 2.0.0'
14
+ gem.add_dependency 'nokogiri', '>= 1.3.3'
15
+ gem.add_dependency 'json_pure', '>= 1.1.3'
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :refresh_builder => [:build] do
36
+ cp "pkg/cml-#{File.read("VERSION").strip}.gem", "../builder/gems/cache/"
37
+ rm_rf "../builder/gems/gems/cml-#{File.read("VERSION").strip}/"
38
+ `cd ../builder && bin/thor merb:gem:redeploy`
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION.yml')
46
+ config = YAML.load(File.read('VERSION.yml'))
47
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
48
+ else
49
+ version = ""
50
+ end
51
+
52
+ rdoc.rdoc_dir = 'rdoc'
53
+ rdoc.title = "cml #{version}"
54
+ rdoc.rdoc_files.include('README*')
55
+ rdoc.rdoc_files.include('lib/**/*.rb')
56
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
data/cml.gemspec ADDED
@@ -0,0 +1,103 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{cml}
5
+ s.version = "0.3.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Chris Van Pelt"]
9
+ s.date = %q{2009-08-25}
10
+ s.description = %q{CML let's you easily create form elements and custom interfaces for the CrowdFlower Croud Labor platform}
11
+ s.email = %q{vanpelt@doloreslabs.com}
12
+ s.extra_rdoc_files = [
13
+ "LICENSE",
14
+ "README.rdoc"
15
+ ]
16
+ s.files = [
17
+ ".document",
18
+ ".gitignore",
19
+ "LICENSE",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "cml.gemspec",
24
+ "lib/cml.rb",
25
+ "lib/cml/converters/jsawesome.rb",
26
+ "lib/cml/liquid_filters.rb",
27
+ "lib/cml/parser.rb",
28
+ "lib/cml/tag.rb",
29
+ "lib/cml/tags/checkbox.rb",
30
+ "lib/cml/tags/checkboxes.rb",
31
+ "lib/cml/tags/group.rb",
32
+ "lib/cml/tags/hidden.rb",
33
+ "lib/cml/tags/meta.rb",
34
+ "lib/cml/tags/option.rb",
35
+ "lib/cml/tags/radio.rb",
36
+ "lib/cml/tags/radios.rb",
37
+ "lib/cml/tags/ratings.rb",
38
+ "lib/cml/tags/select.rb",
39
+ "lib/cml/tags/text.rb",
40
+ "lib/cml/tags/textarea.rb",
41
+ "lib/cml/tags/unknown.rb",
42
+ "spec/complex_spec.rb",
43
+ "spec/converters/jsawesome_spec.rb",
44
+ "spec/fixtures/complex.cml",
45
+ "spec/fixtures/invalid.cml",
46
+ "spec/meta_spec.rb",
47
+ "spec/sorta_match.rb",
48
+ "spec/spec_helper.rb",
49
+ "spec/tags/checkbox_spec.rb",
50
+ "spec/tags/checkboxes_spec.rb",
51
+ "spec/tags/group_spec.rb",
52
+ "spec/tags/hidden_spec.rb",
53
+ "spec/tags/meta_spec.rb",
54
+ "spec/tags/radios_spec.rb",
55
+ "spec/tags/select_spec.rb",
56
+ "spec/tags/text_spec.rb",
57
+ "spec/tags/textarea_spec.rb",
58
+ "spec/tags/unknown_spec.rb",
59
+ "spec/validation_spec.rb"
60
+ ]
61
+ s.homepage = %q{http://github.com/dolores/cml}
62
+ s.rdoc_options = ["--charset=UTF-8"]
63
+ s.require_paths = ["lib"]
64
+ s.rubygems_version = %q{1.3.4}
65
+ s.summary = %q{CML is CrowdFlower Markup Language}
66
+ s.test_files = [
67
+ "spec/complex_spec.rb",
68
+ "spec/converters/jsawesome_spec.rb",
69
+ "spec/meta_spec.rb",
70
+ "spec/sorta_match.rb",
71
+ "spec/spec_helper.rb",
72
+ "spec/tags/checkbox_spec.rb",
73
+ "spec/tags/checkboxes_spec.rb",
74
+ "spec/tags/group_spec.rb",
75
+ "spec/tags/hidden_spec.rb",
76
+ "spec/tags/meta_spec.rb",
77
+ "spec/tags/radios_spec.rb",
78
+ "spec/tags/select_spec.rb",
79
+ "spec/tags/text_spec.rb",
80
+ "spec/tags/textarea_spec.rb",
81
+ "spec/tags/unknown_spec.rb",
82
+ "spec/validation_spec.rb"
83
+ ]
84
+
85
+ if s.respond_to? :specification_version then
86
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
87
+ s.specification_version = 3
88
+
89
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
90
+ s.add_runtime_dependency(%q<liquid>, [">= 2.0.0"])
91
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.3"])
92
+ s.add_runtime_dependency(%q<json_pure>, [">= 1.1.3"])
93
+ else
94
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
95
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
96
+ s.add_dependency(%q<json_pure>, [">= 1.1.3"])
97
+ end
98
+ else
99
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
100
+ s.add_dependency(%q<nokogiri>, [">= 1.3.3"])
101
+ s.add_dependency(%q<json_pure>, [">= 1.1.3"])
102
+ end
103
+ end
@@ -0,0 +1,102 @@
1
+ module CML
2
+ module Converters
3
+ class JSAwesome
4
+ def initialize(json)
5
+ parsed = JSON.parse(json)
6
+ @json = parsed[0] || []
7
+ @labels = parsed[1] || {}
8
+ @tags = []
9
+ end
10
+
11
+ def convert
12
+ @json.map do |k,v|
13
+ if k.is_a?(Array)
14
+ (k << v).map {|k,v| process(k,v)}
15
+ else
16
+ process(k,v)
17
+ end
18
+ end.join("\n") + meta
19
+ end
20
+
21
+ def meta
22
+ (@labels["gold"] || {}).select do |k,v|
23
+ next if k =~ /^_/
24
+ !@tags.map {|t| t.name }.include?(k)
25
+ end.map do |k,v|
26
+ tag("meta", k, {:meta => true})
27
+ end.join("\n")
28
+ end
29
+
30
+ def label(k)
31
+ k = k.sub(/^[_#*^~]?\+?/,'')
32
+ l = @labels[k]
33
+ label = l.is_a?(Hash) ? l["label"] : l if l
34
+ label ||= k.capitalize.gsub(/_/,' ')
35
+ end
36
+
37
+ def tag(tag, val, opts = {})
38
+ val = Array(val)
39
+ parts = val[0].split("|")
40
+ key = parts[0].sub(/^[_#*^~]?\+?/,'')
41
+ label = label(parts[0])
42
+ parts << key if label != key.capitalize.gsub(/_/,' ') || opts[:meta]
43
+ attrs = opts[:meta] ? [] : ["label=\"#{label}\""]
44
+ attrs << "name=\"#{parts[1]}\"" if parts[1]
45
+ attrs << "checked=\"true\"" if val[1]
46
+ attrs << "validates=\"required\"" if @labels[key] && @labels[key]["required"]
47
+ opts.reject {|k,v| v.to_s.strip.length == 0 || k.is_a?(Symbol) }.each do |k,v|
48
+ attrs << "#{k}=\"#{v}\""
49
+ end
50
+ if @labels["gold"] && @labels["gold"][key]
51
+ opts["gold"] = {}
52
+ src = @labels["gold"][key]
53
+ opts["gold"]["src"] = src
54
+ opts["gold"]["regex"], opts["gold"]["flags"] = Array(@labels["gold"]["_"+src+"_regex"])
55
+ opts["gold"]["strict"] = @labels["gold"]["_"+src+"_strict"]
56
+ else
57
+ opts["gold"] = false
58
+ end
59
+
60
+ tag = Parser.tag_class(tag).new("<cml:#{tag} #{attrs.join(" ")} />")
61
+ tag.gold = opts["gold"]
62
+ opts[:children].each { |c| tag.cml.add_child(tag(*c).cml) } if opts[:children]
63
+ @tags << tag if opts[:parent]
64
+ tag
65
+ end
66
+
67
+ def process(k,v)
68
+ select_default = @labels['{}'] || "Choose Category"
69
+ cml = case v
70
+ #a select tag or group of radios/checkboxes
71
+ when Array:
72
+ if(k =~ /^[^_]/)
73
+ if $~[0] == "*"
74
+ parent = "radios"
75
+ child = "radio"
76
+ elsif $~[0] == "^"
77
+ parent = "checkboxes"
78
+ child = "checkbox"
79
+ else
80
+ parent = "select"
81
+ child = "option"
82
+ end
83
+ tag(parent, k, {:children => v.map { |c| [child, c]}, :parent => true })
84
+ #Multiple hidden fields...
85
+ elsif(k =~ /^_/)
86
+ v.map { |c| tag("hidden", c, :parent => true)}.join("\n")
87
+ end
88
+ else
89
+ if(k =~ /^#/)
90
+ tag("textarea", k, {"default" => v, :parent => true})
91
+ elsif(k =~ /^_/)
92
+ tag("hidden", k, {"value" => v, :parent => true})
93
+ elsif(k =~ /^\^/)
94
+ tag("checkbox", k, {"default" => v, :parent => true})
95
+ else
96
+ tag("text", k, {"default" => v, :parent => true})
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,7 @@
1
+ module CML
2
+ module LiquidFilters
3
+ def to_json(input)
4
+ input.to_json
5
+ end
6
+ end
7
+ end
data/lib/cml/parser.rb ADDED
@@ -0,0 +1,107 @@
1
+ module CML
2
+ class Parser
3
+ attr_reader :doc, :cftags, :tags, :errors
4
+
5
+ def initialize(content, opts = {})
6
+ @opts = opts
7
+ @doc = Parser.parse(content)
8
+ @cftags = @doc.xpath("//cml:*[not(ancestor::cml:*)]")
9
+ @tags = @cftags.map do |t|
10
+ Parser.tag_class(t.name).new(t, @opts)
11
+ end
12
+ end
13
+
14
+ def self.parse(content)
15
+ Nokogiri::XML("<root xmlns:cml=\"http://crowdflower.com\">#{content}</root>")
16
+ end
17
+
18
+ def convert(opts = nil)
19
+ @opts = opts if opts
20
+ cloned = @doc.dup
21
+ cloned.xpath("//cml:*[not(ancestor::cml:*)]").each_with_index do |t,i|
22
+ t.replace(@tags[i].convert(opts))
23
+ end
24
+ cloned
25
+ end
26
+
27
+ def fields
28
+ @fields = {}
29
+ @tags.each do |g|
30
+ agg = g.attrs["aggregation"]
31
+ @fields[g.name] = agg.to_s if agg
32
+ end
33
+ @fields
34
+ end
35
+
36
+ def golds
37
+ return @golds if @golds
38
+ @golds = {}
39
+ @tags.each do |g|
40
+ gold = g.gold?
41
+ next unless gold
42
+ val = (gold.attributes["gold"] || gold.attributes["src"]).to_s
43
+ val = "#{g.name}_gold" if val =~ /^(true|\s*)$/
44
+ @golds[g.name] = val
45
+ ["strict","regex"].each do |attrs|
46
+ if a = gold.attributes[attrs]
47
+ @golds["_#{val}_#{attrs}"] = attrs == "regex" ? [a.to_s, gold.attributes["flags"].to_s] : a.to_s
48
+ end
49
+ end
50
+ end
51
+ @golds
52
+ end
53
+
54
+ def valid?
55
+ @errors = []
56
+ if e = @doc.errors.select {|e| s.fatal? }.last
57
+ @errors << "Malformed CML (#{e.level}). #{e.message.chomp} on line #{e.line} column #{e.column}."
58
+ end
59
+ @tags.select {|t| t.validate? && t.name =~ /^\s*$/ }.each do |t|
60
+ @errors << "#{t.to_s.split("\n")[0]} does not have a label or name specified."
61
+ end
62
+ dupes = @tags.select do |tag|
63
+ tag.validate? && @tags.select {|t| t.name == tag.name}.length > 1
64
+ end
65
+ (dupes[1..-1] || []).each do |t|
66
+ @errors << "#{t.to_s.split("\n")[0]} has a duplicated name, please specify a unique name attribute."
67
+ end
68
+ @tags.each do |t|
69
+ next unless t.children
70
+ dupes = t.children.select do |child|
71
+ t.children.select {|c| c.value == child.value}.length > 1
72
+ end
73
+ (dupes[1..-1] || []).each do |c|
74
+ @errors << "#{c} a child of #{t.to_s.split("\n")[0]} has a duplicated value, please specify a unique value attribute."
75
+ end
76
+ end
77
+ @errors.length == 0
78
+ end
79
+
80
+ def wrap(content)
81
+ @opts[:no_wrap] ? content : "<div class=\"cml#{" "+@opts[:class] if @opts[:class]}\" id=\"#{@opts[:prefix]}\">#{content}</div>"
82
+ end
83
+
84
+ def to_s
85
+ @doc.root.children.to_s
86
+ end
87
+
88
+ def to_html(opts = nil)
89
+ xml = convert(opts)
90
+ wrap(xml.at("root").inner_html)
91
+ end
92
+
93
+ def self.escape( string )
94
+ string.to_s.gsub( /&/, "&amp;" ).
95
+ gsub( /</, "&lt;" ).
96
+ gsub( />/, "&gt;" ).
97
+ gsub( /"/, "&quot;" )
98
+ end
99
+
100
+ #This takes the name of the tag and converts it to the appropriate task
101
+ def self.tag_class(name)
102
+ CML::Tags.module_eval(name.gsub(/(^|_)(.)/) { $2.upcase })
103
+ rescue
104
+ CML::Tags::Unknown
105
+ end
106
+ end
107
+ end
data/lib/cml/tag.rb ADDED
@@ -0,0 +1,134 @@
1
+ module CML
2
+ class Tag
3
+ attr_reader :attrs, :tag, :data, :cml
4
+
5
+ def initialize(cml, opts = {})
6
+ @cml = cml.is_a?(String) ? Parser.parse(cml).at("/root/*") : cml
7
+ @attrs = @cml.attributes#Hash[*cml.attributes.map {|k,v| [k.intern,v]}.flatten]
8
+ @tag = @cml.name
9
+ @opts = opts
10
+ end
11
+
12
+ def prefix(name)
13
+ @opts[:prefix] ? "#{@opts[:prefix]}[#{name}]" : "#{name}"
14
+ end
15
+
16
+ def gold?
17
+ @attrs["gold"] ? @cml : @cml.at("./cml:gold")
18
+ end
19
+
20
+ def gold=(opts = {})
21
+ cur = gold?
22
+ advanced = ["strict", "regex"].any? {|k| opts && opts[k] }
23
+ if !cur
24
+ cur = advanced ? @cml.add_child(Parser.parse("<cml:gold/>").at("/root/*")) : @cml
25
+ end
26
+
27
+ if cur.name == "gold"
28
+ if !opts
29
+ cur.remove
30
+ elsif advanced
31
+ opts.each do |k,v|
32
+ cur[k] = v.to_s if v
33
+ end
34
+ else
35
+ cur.remove
36
+ cur = @cml
37
+ end
38
+ end
39
+
40
+ if cur.name != "gold"
41
+ if !opts
42
+ @cml.remove_attribute("gold")
43
+ elsif opts["src"] && opts["src"] != "#{name}_gold"
44
+ @cml["gold"] = opts["src"]
45
+ else
46
+ @cml["gold"] = "true"
47
+ end
48
+ end
49
+ end
50
+
51
+ def name
52
+ (@attrs["name"] || @attrs["label"]).to_s.downcase.gsub(/\s/,"_").gsub(/\W/,"")
53
+ end
54
+
55
+ def wrapper_classes
56
+ extras = @attrs["only-if"] ? "only-if:#{@attrs["only-if"]}" : ""
57
+ "#{@tag} #{extras}".strip
58
+ end
59
+
60
+ def children
61
+ false
62
+ end
63
+
64
+ def classes
65
+ @classes ||= [name] << validations << @attrs["class"].to_s.split(/ /)
66
+ @classes.uniq.reject {|c| c.length == 0 }.join(" ").strip
67
+ end
68
+
69
+ def convert(opts = nil)
70
+ @opts = opts if opts
71
+ html = to_html
72
+ html.strip.length == 0 ? Nokogiri::XML::Text.new(html, @cml.document) : Nokogiri::HTML.fragment(html)
73
+ end
74
+
75
+ def to_html
76
+ wrapper(Liquid::Template.parse(self.class::Template).render(data, [LiquidFilters]))
77
+ end
78
+
79
+ def to_s
80
+ @cml.to_s
81
+ end
82
+
83
+ def label(label, tag = "label")
84
+ label ||= @attrs["name"].to_s.capitalize
85
+ required = " <span class=\"required\">(required)</span>" if validations.include?("required")
86
+ "<#{tag}>#{label}#{required}</#{tag.split(" ")[0]}>" if label.to_s != ""
87
+ end
88
+
89
+ def legend(label)
90
+ label(label, "legend") if label
91
+ end
92
+
93
+ def to_liquid
94
+ to_html
95
+ end
96
+
97
+ def validations
98
+ @validations ||= @attrs["validates"].to_s.split(/ /).map {|v| "validates-#{v}"}
99
+ end
100
+
101
+ def instructions
102
+ @instructions ||= @attrs["instructions"] || (@cml.at("./cml:instructions") ? @cml.at("./cml:instructions").inner_html : nil)
103
+ @instructions ? "<p class=\"instructions\">#{@instructions}</p>" : nil
104
+ end
105
+
106
+ def validate?
107
+ true
108
+ end
109
+
110
+ def wrapper(parsed, tag = "div")
111
+ #Deal with a label only wrapper... kinda jank
112
+ if tag == "label" && instructions
113
+ tag = "div"
114
+ parsed = "<label>#{parsed}</label>"
115
+ end
116
+ #Inserting instructions here makes it a non-variable input maybe...
117
+ "<#{tag} class=\"#{wrapper_classes}\">#{parsed}#{instructions}</#{tag}>"
118
+ end
119
+
120
+ def value
121
+ @attrs["value"].to_s
122
+ end
123
+
124
+ def data
125
+ (@opts[:data] || {}).merge({
126
+ "name" => prefix(name),
127
+ "label" => label(@attrs["label"]),
128
+ "legend" => label(@attrs["label"], "h2 class=\"legend\""),
129
+ "classes" => classes,
130
+ "value" => value
131
+ })
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,37 @@
1
+ module CML
2
+ module Tags
3
+ class Checkbox < Tag
4
+ Template = <<-HTML.freeze
5
+ {{default}}
6
+ <label><input name="{{name}}" type="checkbox" value="{{value}}" class="{{classes}}" {{checked}}/> {{label}}</label>
7
+ HTML
8
+
9
+ def prefix(name)
10
+ super(name) + (grouped? ? "[]" : "")
11
+ end
12
+
13
+ def grouped?
14
+ @cml.parent && @cml.parent.name == "checkboxes"
15
+ end
16
+
17
+ def wrapper(parsed)
18
+ grouped? ? parsed : super
19
+ end
20
+
21
+ def value
22
+ (@attrs["value"] || (grouped? ? @attrs["label"] : "true")).to_s
23
+ end
24
+
25
+ def data
26
+ default = ""
27
+ if @attrs["default"]
28
+ default = Hidden.new("<cml:hidden name=\"#{name}\" value=\"#{@attrs["default"]}\"/>", @opts).to_html
29
+ end
30
+ super.merge({
31
+ "default" => default,
32
+ "checked" => @attrs["checked"] ? "checked=\"checked\"" : "",
33
+ "label" => @attrs["label"].to_s})
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ module CML
2
+ module Tags
3
+ class Checkboxes < Tag
4
+ Template = <<-HTML.freeze
5
+ {{legend}}
6
+ {% for checkbox in checkboxes %}
7
+ {{checkbox}}
8
+ {% endfor %}
9
+ HTML
10
+
11
+ def data
12
+ super.merge({"checkboxes" => children})
13
+ end
14
+
15
+ def children
16
+ @cml.xpath("cml:checkbox").map do |c|
17
+ c["name"] ||= name
18
+ c["validates"] ||= @attrs["validates"].to_s
19
+ Checkbox.new(c, @opts)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module CML
2
+ module Tags
3
+ class Group < Tag
4
+ Template = <<-HTML.freeze
5
+ {{label}}
6
+ {{content}}
7
+ HTML
8
+
9
+ def validate?
10
+ false
11
+ end
12
+
13
+ def data
14
+ super.merge({"content" => Parser.new(@cml.inner_html, @opts.merge(:no_wrap => true)).to_html})
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module CML
2
+ module Tags
3
+ class Hidden < Tag
4
+ Template = <<-HTML.freeze
5
+ <input name="{{name}}" type="hidden" value="{{value}}" class="{{classes}}"/>
6
+ HTML
7
+
8
+ def wrapper(parsed)
9
+ parsed
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module CML
2
+ module Tags
3
+ class Meta < Tag
4
+ Template = <<-HTML.freeze
5
+ HTML
6
+
7
+ def wrapper(parsed)
8
+ parsed
9
+ end
10
+ end
11
+ end
12
+ end