manatee 0.0.1.pre1
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.
- checksums.yaml +7 -0
- data/Gemfile +23 -0
- data/LICENSE.txt +22 -0
- data/README.mdown +55 -0
- data/Rakefile +7 -0
- data/app/assets/javascripts/manatee.js +1 -0
- data/app/assets/javascripts/manatee/helpers.js +4 -0
- data/app/assets/javascripts/manatee/helpers/asset_tag.jsh.coffee +138 -0
- data/app/assets/javascripts/manatee/helpers/asset_url.jsh.coffee +90 -0
- data/app/assets/javascripts/manatee/helpers/csrf.jsh.coffee +5 -0
- data/app/assets/javascripts/manatee/helpers/date.jsh.coffee +54 -0
- data/app/assets/javascripts/manatee/helpers/debug.jsh.coffee +2 -0
- data/app/assets/javascripts/manatee/helpers/form.jsh.coffee +25 -0
- data/app/assets/javascripts/manatee/helpers/form_builder.jsh.coffee +24 -0
- data/app/assets/javascripts/manatee/helpers/form_options.jsh.coffee +267 -0
- data/app/assets/javascripts/manatee/helpers/form_tag.jsh.coffee +204 -0
- data/app/assets/javascripts/manatee/helpers/javascript.jsh.coffee +15 -0
- data/app/assets/javascripts/manatee/helpers/number.jsh.coffee +58 -0
- data/app/assets/javascripts/manatee/helpers/sanitize.jsh.coffee +5 -0
- data/app/assets/javascripts/manatee/helpers/tag.jsh.coffee +58 -0
- data/app/assets/javascripts/manatee/helpers/text.jsh.coffee +12 -0
- data/app/assets/javascripts/manatee/helpers/translation.jsh.coffee +7 -0
- data/app/assets/javascripts/manatee/helpers/url.jsh.coffee +36 -0
- data/app/assets/javascripts/manatee/helpers/util.jsh.coffee +41 -0
- data/app/assets/javascripts/manatee/rails_helpers.js +2 -0
- data/app/assets/javascripts/manatee/rails_helpers/routes.js.erb +195 -0
- data/app/assets/javascripts/manatee/rails_routes.js +1 -0
- data/app/assets/javascripts/manatee/renderer.js.erb +53 -0
- data/app/assets/javascripts/manatee_railsless.js +1 -0
- data/lib/manatee.rb +87 -0
- data/lib/manatee/config.rb +51 -0
- data/lib/manatee/handler.rb +45 -0
- data/lib/manatee/rails.rb +6 -0
- data/lib/manatee/rails/extensions.rb +23 -0
- data/lib/manatee/rails/handler.rb +16 -0
- data/lib/manatee/rails/hash_visitor.rb +35 -0
- data/lib/manatee/rails/helper.rb +9 -0
- data/lib/manatee/rails/resolver.rb +70 -0
- data/lib/manatee/rails/routes_compiler.rb +34 -0
- data/lib/manatee/sprockets.rb +8 -0
- data/lib/manatee/sprockets/jsh_processor_2x.rb +32 -0
- data/lib/manatee/sprockets/jsh_processor_3x.rb +31 -0
- data/lib/manatee/version.rb +3 -0
- data/manatee.gemspec +32 -0
- data/test/example/renderer.js.erb +8 -0
- data/test/example/translations.en.yml +410 -0
- data/test/example/views/index.jst.eco +12 -0
- data/test/helpers/asset_tag_test.rb +175 -0
- data/test/helpers/asset_url_test.rb +349 -0
- data/test/helpers/form_options_test.rb +718 -0
- data/test/helpers/form_tag_test.rb +387 -0
- data/test/helpers/javascript_test.rb +39 -0
- data/test/helpers/number_test.rb +111 -0
- data/test/helpers/tag_test.rb +71 -0
- data/test/support/dom_assertion.rb +49 -0
- data/test/support/view_test.rb +91 -0
- data/test/test_helper.rb +17 -0
- metadata +213 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b3ae1dccef7459bc5825b9dabd5b4db64da0363
|
4
|
+
data.tar.gz: d018454a024148225f218275b15f551a5ec22a01
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4aca549a3f05eda647491d3b56ca2547c83e52cf576a73ff09c9f80f05ef1dfe5964b243d1f978b231e50e221d2cd7ddf66ec1843f0f457cf798b8fc70602af1
|
7
|
+
data.tar.gz: 717fd9676054a86710b75e9e25402312adcd9213e384a195888b1f64842939387b40fcfbd3ec46c014fa9ae34c32af371203fb0374fb8082561201f6bcfa9e04
|
data/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in manatee.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'i18n-js', path: '../i18n-js'
|
7
|
+
|
8
|
+
gem 'sprockets', '~> 2'
|
9
|
+
# gem 'sprockets', '~> 3'
|
10
|
+
|
11
|
+
platform :ruby do
|
12
|
+
gem 'therubyracer'
|
13
|
+
end
|
14
|
+
|
15
|
+
platform :jruby do
|
16
|
+
gem 'therubyrhyno'
|
17
|
+
end
|
18
|
+
|
19
|
+
group :development, :test do
|
20
|
+
gem 'eco'
|
21
|
+
gem 'pry'
|
22
|
+
gem 'test-unit'
|
23
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Dalton
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.mdown
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Manatee
|
2
|
+
|
3
|
+
Javascript Template Render [for Rails]?
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Use only with TheRubyRacer or TheRubyRhyno gem.
|
8
|
+
|
9
|
+
Other ExecJS adapter like Node.js, doesn't translates Ruby lambdas to Javascript functions, and some have unicode characters issues
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'manatee'
|
15
|
+
```
|
16
|
+
|
17
|
+
And then execute:
|
18
|
+
|
19
|
+
$ bundle
|
20
|
+
|
21
|
+
Or install it yourself as:
|
22
|
+
|
23
|
+
$ gem install manatee
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
__It's unstable, may change.__
|
28
|
+
|
29
|
+
### With Rails
|
30
|
+
|
31
|
+
Create an initializer file, for example, config/initializers/manatee.rb with:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
Manatee.subscribe_on_rails
|
35
|
+
# Manatee.config do |config|
|
36
|
+
# config.some_conf = 'value'
|
37
|
+
# config.lambda_conf{ |c| 'value' }
|
38
|
+
# end
|
39
|
+
```
|
40
|
+
|
41
|
+
If need to change an option, for now, check out at lib/manatee.rb to see all options, I dont want to document that right now.
|
42
|
+
|
43
|
+
As you see, I'm lazy enough to not explain how to use it... Figure it out by yourself.
|
44
|
+
|
45
|
+
### Without Rails
|
46
|
+
|
47
|
+
Check out test file test/test\_helper.rb, and lib/manatee.rb to see all options and understand how to use it with any app that uses sprockets.
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. Fork it ( https://github.com/akidog/manatee/fork )
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= require ./manatee/rails_helpers
|
@@ -0,0 +1,138 @@
|
|
1
|
+
helper 'audioTag', (paths...) ->
|
2
|
+
options = paths[paths.length - 1]
|
3
|
+
if typeof options == 'object'
|
4
|
+
paths.pop()
|
5
|
+
else
|
6
|
+
options = {}
|
7
|
+
path_options = {}
|
8
|
+
path_options['format'] = options['format']
|
9
|
+
options['format'] = undefined
|
10
|
+
if paths.length == 1
|
11
|
+
options['src'] = @audioPath paths[0], path_options
|
12
|
+
@tag 'audio', options
|
13
|
+
else
|
14
|
+
content = ''
|
15
|
+
source_options
|
16
|
+
if options['source']
|
17
|
+
source_options = options['source']
|
18
|
+
options['source'] = undefined
|
19
|
+
else
|
20
|
+
source_options = {}
|
21
|
+
for i, path of paths
|
22
|
+
source_options['src'] = @audioPath path, path_options
|
23
|
+
content += @tag 'source', source_options
|
24
|
+
@contentTag 'audio', content, options
|
25
|
+
|
26
|
+
helper 'autoDiscoveryLinkTag', (type = 'rss', url = @_context.domain.app, options = {}) ->
|
27
|
+
options = @_clone options
|
28
|
+
options['href'] = @assetUrl(url || @_context.domain.app)
|
29
|
+
options['rel'] ||= 'alternate'
|
30
|
+
unless options['type']
|
31
|
+
if type == 'rss'
|
32
|
+
options['type'] = 'application/rss+xml'
|
33
|
+
options['title'] ||= 'RSS'
|
34
|
+
if type == 'atom'
|
35
|
+
options['type'] = 'application/atom+xml'
|
36
|
+
options['title'] ||= 'ATOM'
|
37
|
+
options['title'] ||= ''
|
38
|
+
@tag 'link', options
|
39
|
+
|
40
|
+
helper 'faviconLinkTag', (path = 'favicon.ico', options = {}) ->
|
41
|
+
options['rel'] ||= 'shortcut icon'
|
42
|
+
options['type'] ||= 'image/x-icon'
|
43
|
+
options['href'] = path
|
44
|
+
@tag 'link', options
|
45
|
+
|
46
|
+
helper 'imageAlt', (source) ->
|
47
|
+
basename = new String(source).substring(source.lastIndexOf('/') + 1);
|
48
|
+
basename = basename.substring(0, basename.lastIndexOf(".")) if basename.lastIndexOf(".") != -1
|
49
|
+
basename = basename[0..-34] if (/\-[0-9a-z]{32}/ig).test(basename[-33..-1])
|
50
|
+
basename = basename.replace(/[-_\s]+/g, ' ')
|
51
|
+
basename[0].toUpperCase() + basename.slice(1);
|
52
|
+
|
53
|
+
handleSizeAttribute = (options) ->
|
54
|
+
if typeof options['size'] == 'string'
|
55
|
+
size = options['size'].toLowerCase()
|
56
|
+
options['size'] = undefined
|
57
|
+
if (/\d+X\d+/i).test(size)
|
58
|
+
xIndex = size.lastIndexOf('x');
|
59
|
+
options['width'] ||= size.substring 0, xIndex
|
60
|
+
options['height'] ||= size.substring xIndex+1
|
61
|
+
if (new RegExp("\\d{" + size.length + "}")).test(size)
|
62
|
+
options['width'] ||= size
|
63
|
+
options['height'] ||= size
|
64
|
+
|
65
|
+
helper 'imageTag', (source, options = {}) ->
|
66
|
+
options = @_clone options
|
67
|
+
handleSizeAttribute options
|
68
|
+
|
69
|
+
if source == '' || source[0..4] == 'data:'
|
70
|
+
options['src'] = source
|
71
|
+
options['alt'] = undefined if options['alt'] == null
|
72
|
+
else
|
73
|
+
options['src'] = @imagePath source
|
74
|
+
if options['alt'] == null
|
75
|
+
options['alt'] = undefined
|
76
|
+
else
|
77
|
+
options['alt'] = @imageAlt(source) if options['alt'] == undefined
|
78
|
+
@tag 'img', options
|
79
|
+
|
80
|
+
helper 'javascriptIncludeTag', (sources...) ->
|
81
|
+
path_options = if typeof sources[sources.length-1] == 'object'
|
82
|
+
sources.pop()
|
83
|
+
else
|
84
|
+
{}
|
85
|
+
|
86
|
+
result = ''
|
87
|
+
for index, source of sources
|
88
|
+
options = { src: @javascriptPath(source, path_options) }
|
89
|
+
result += @contentTag 'script', '', options
|
90
|
+
result
|
91
|
+
|
92
|
+
helper 'stylesheetLinkTag', (sources...) ->
|
93
|
+
path_options = {}
|
94
|
+
options = if typeof sources[sources.length - 1] == 'object'
|
95
|
+
opts = sources.pop()
|
96
|
+
path_options['format'] = opts['format']
|
97
|
+
path_options['type'] = opts['type']
|
98
|
+
opts['format'] = undefined
|
99
|
+
opts['type'] = undefined
|
100
|
+
opts['rel'] ||= 'stylesheet'
|
101
|
+
opts['media'] ||= 'screen'
|
102
|
+
opts
|
103
|
+
else
|
104
|
+
{ rel: 'stylesheet', media: 'screen' }
|
105
|
+
|
106
|
+
result = ''
|
107
|
+
for index, source of sources
|
108
|
+
options['href'] = @stylesheetPath source, path_options
|
109
|
+
result += @tag 'link', options
|
110
|
+
result
|
111
|
+
|
112
|
+
helper 'videoTag', (paths...) ->
|
113
|
+
options = if typeof paths[paths.length - 1] == 'object'
|
114
|
+
@_clone paths.pop()
|
115
|
+
else
|
116
|
+
{}
|
117
|
+
|
118
|
+
handleSizeAttribute options
|
119
|
+
options['poster'] = @imagePath(options['poster']) if options['poster']
|
120
|
+
|
121
|
+
path_options = {}
|
122
|
+
path_options['format'] = options['format']
|
123
|
+
options['format'] = undefined
|
124
|
+
if paths.length == 1
|
125
|
+
options['src'] = @videoPath paths[0], path_options
|
126
|
+
@tag 'video', options
|
127
|
+
else
|
128
|
+
content = ''
|
129
|
+
source_options
|
130
|
+
if options['source']
|
131
|
+
source_options = options['source']
|
132
|
+
options['source'] = undefined
|
133
|
+
else
|
134
|
+
source_options = {}
|
135
|
+
for i, path of paths
|
136
|
+
source_options['src'] = @videoPath path, path_options
|
137
|
+
content += @tag 'source', source_options
|
138
|
+
@contentTag 'video', content, options
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# TODO: Think about digests
|
2
|
+
helper 'computeAssetPath', (source, options = {}) ->
|
3
|
+
options['type'] ||= 'asset'
|
4
|
+
|
5
|
+
if @_context.forceAssetDomain
|
6
|
+
options['domain'] ||= @_context.domain[ options['type'] ]
|
7
|
+
|
8
|
+
format = if options['format'] == undefined
|
9
|
+
@_context.defaultFormat[ options['type'] ]
|
10
|
+
else
|
11
|
+
options['format']
|
12
|
+
|
13
|
+
if format
|
14
|
+
sharp_index = source.lastIndexOf '#'
|
15
|
+
query_index = source.lastIndexOf '?'
|
16
|
+
|
17
|
+
index = if sharp_index == -1
|
18
|
+
query_index
|
19
|
+
else
|
20
|
+
if query_index == -1
|
21
|
+
sharp_index
|
22
|
+
else
|
23
|
+
if query_index > sharp_index
|
24
|
+
sharp_index
|
25
|
+
else
|
26
|
+
query_index
|
27
|
+
|
28
|
+
if index == -1
|
29
|
+
source += '.' + format unless source[(-format.length-1)..-1] == ('.' + format)
|
30
|
+
else
|
31
|
+
prefix = source.slice 0, index
|
32
|
+
sufix = source.slice index
|
33
|
+
if prefix[(-format.length-1)..-1] == ('.' + format)
|
34
|
+
source = prefix + sufix
|
35
|
+
else
|
36
|
+
source = prefix + '.' + format + sufix
|
37
|
+
|
38
|
+
source = if source[0] == '/'
|
39
|
+
source
|
40
|
+
else
|
41
|
+
prefix_path = @_context.defaultPath[options['type']]
|
42
|
+
if prefix_path[prefix_path.length-1] == '/'
|
43
|
+
prefix_path + source
|
44
|
+
else
|
45
|
+
prefix_path + '/' + source
|
46
|
+
|
47
|
+
source = '/' + source if source[0] != '/'
|
48
|
+
|
49
|
+
if options['domain']
|
50
|
+
source = options['domain'] + source
|
51
|
+
|
52
|
+
source
|
53
|
+
|
54
|
+
helper 'assetPath', (source, options = {}) ->
|
55
|
+
source = source.toString()
|
56
|
+
options = @_clone options
|
57
|
+
|
58
|
+
fullDoaminPath = /[\w\d]+\:\/\//i
|
59
|
+
return source if fullDoaminPath.test(source) || source[0..1] == '//'
|
60
|
+
|
61
|
+
@computeAssetPath source, options
|
62
|
+
|
63
|
+
helper 'assetUrl', (source, options = {}) ->
|
64
|
+
source = source.toString()
|
65
|
+
options = @_clone options
|
66
|
+
|
67
|
+
options['domain'] ||= if options['type']
|
68
|
+
@_context.domain[options['type']] || @_context.domain.asset
|
69
|
+
else
|
70
|
+
@_context.domain.asset
|
71
|
+
|
72
|
+
@assetPath source, options
|
73
|
+
|
74
|
+
assetPathBuilder = (_type) ->
|
75
|
+
type_built = _type
|
76
|
+
(source, options = {}) ->
|
77
|
+
options = @_clone options
|
78
|
+
options['type'] = type_built if options['type'] == undefined
|
79
|
+
@assetPath source, options
|
80
|
+
|
81
|
+
assetUrlBuilder = (_type) ->
|
82
|
+
type_built = _type
|
83
|
+
(source, options = {}) ->
|
84
|
+
options = @_clone options
|
85
|
+
options['type'] = type_built if options['type'] == undefined
|
86
|
+
@assetUrl source, options
|
87
|
+
|
88
|
+
for index, type of ['audio', 'font', 'image', 'video', 'javascript', 'stylesheet']
|
89
|
+
helper (type+'Path'), assetPathBuilder.call(this,type)
|
90
|
+
helper (type+'Url'), assetUrlBuilder.call(this,type)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
helper 'strftime', (date, pattern) ->
|
2
|
+
I18n.strftime date, pattern
|
3
|
+
|
4
|
+
helper 'distanceOfTimeInWords', (from_time, to_time, withSeconds = false) ->
|
5
|
+
distance_in_minutes = Math.abs((to_time - from_time) / 60000)
|
6
|
+
[key, options] = switch
|
7
|
+
when distance_in_minutes < 1
|
8
|
+
if withSeconds
|
9
|
+
distance_in_seconds = Math.abs((to_time - from_time) / 1000)
|
10
|
+
switch
|
11
|
+
when distance_in_seconds < 5 then [ 'less_than_x_seconds', { count: 5 } ]
|
12
|
+
when distance_in_seconds < 10 then [ 'less_than_x_seconds', { count: 10 } ]
|
13
|
+
when distance_in_seconds < 20 then [ 'less_than_x_seconds', { count: 20 } ]
|
14
|
+
when distance_in_seconds < 40 then [ 'half_a_minute', { } ]
|
15
|
+
when distance_in_seconds < 60 then [ 'less_than_x_minutes', { count: 1 } ]
|
16
|
+
else ['x_minutes', { count: 1 }]
|
17
|
+
else
|
18
|
+
['less_than_x_minutes', { count: 1 }]
|
19
|
+
when distance_in_minutes < 45 then [ 'x_minutes', { count: Math.floor(distance_in_minutes) } ]
|
20
|
+
when distance_in_minutes < 90 then [ 'about_x_hours', { count: 1 } ]
|
21
|
+
when distance_in_minutes < 1440 then [ 'about_x_hours', { count: Math.floor(distance_in_minutes / 60.0) } ]
|
22
|
+
when distance_in_minutes < 2520 then [ 'x_days', { count: 1 } ]
|
23
|
+
when distance_in_minutes < 43200 then [ 'x_days', { count: Math.floor(distance_in_minutes / 1440.0) } ]
|
24
|
+
when distance_in_minutes < 86400 then [ 'about_x_months', { count: Math.floor(distance_in_minutes / 43200.0) } ]
|
25
|
+
when distance_in_minutes < 525600 then [ 'x_months', { count: Math.floor(distance_in_minutes / 43200.0) } ]
|
26
|
+
else
|
27
|
+
remainder = distance_in_minutes % 525600
|
28
|
+
distance_in_years = Math.floor( distance_in_minutes / 525600 )
|
29
|
+
if remainder < 131400
|
30
|
+
['about_x_years', { count: distance_in_years } ]
|
31
|
+
else if remainder < 394200
|
32
|
+
['over_x_years', { count: distance_in_years } ]
|
33
|
+
else
|
34
|
+
['almost_x_years', { count: distance_in_years + 1 } ]
|
35
|
+
location_key = 'datetime.distance_in_words.' + key
|
36
|
+
@translate location_key, options
|
37
|
+
|
38
|
+
helper 'distanceOfTimeInWordsToNow', (from_time, withSeconds = false) ->
|
39
|
+
@distanceOfTimeInWords from_time, new Date(), withSeconds
|
40
|
+
alias 'timeAgoInWords', 'distanceOfTimeInWordsToNow'
|
41
|
+
|
42
|
+
# date_select
|
43
|
+
# datetime_select
|
44
|
+
# select_date
|
45
|
+
# select_datetime
|
46
|
+
# select_day
|
47
|
+
# select_hour
|
48
|
+
# select_minute
|
49
|
+
# select_month
|
50
|
+
# select_second
|
51
|
+
# select_time
|
52
|
+
# select_year
|
53
|
+
# time_select
|
54
|
+
# time_tag
|
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
# check_box
|
3
|
+
# color_field
|
4
|
+
# date_field
|
5
|
+
# datetime_field
|
6
|
+
# datetime_local_field
|
7
|
+
# email_field
|
8
|
+
# fields_for
|
9
|
+
# file_field
|
10
|
+
# form_for
|
11
|
+
# hidden_field
|
12
|
+
# label
|
13
|
+
# month_field
|
14
|
+
# number_field
|
15
|
+
# password_field
|
16
|
+
# phone_field
|
17
|
+
# radio_button
|
18
|
+
# range_field
|
19
|
+
# search_field
|
20
|
+
# telephone_field
|
21
|
+
# text_area
|
22
|
+
# text_field
|
23
|
+
# time_field
|
24
|
+
# url_field
|
25
|
+
# week_field
|