riot_js-rails 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +4 -0
- data/README.md +27 -0
- data/Rakefile +10 -0
- data/lib/riot_js/rails.rb +8 -0
- data/lib/riot_js/rails/engine.rb +8 -0
- data/lib/riot_js/rails/helper.rb +51 -0
- data/lib/riot_js/rails/processors/compiler.rb +38 -0
- data/lib/riot_js/rails/processors/processor.rb +34 -0
- data/lib/riot_js/rails/railtie.rb +25 -0
- data/lib/riot_js/rails/version.rb +5 -0
- data/riot_js-rails.gemspec +30 -0
- data/vendor/assets/javascripts/compiler/compiler.js +16 -0
- data/vendor/assets/javascripts/compiler/compiler_core.js +234 -0
- data/vendor/assets/javascripts/compiler/node_runner.js +21 -0
- data/vendor/assets/javascripts/compiler/parsers.js +32 -0
- data/vendor/assets/javascripts/riot.js +1370 -0
- data/vendor/assets/javascripts/riot_rails.js +62 -0
- metadata +146 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d683957b5d3a585f6e493b42f17f4908075264b
|
4
|
+
data.tar.gz: 8532cc7d6277124a95475144d6198b6774e30bfc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 771a137a6e2e9e16a327b1b12e9b65f30fbc0dff2bab1b4983188a6a54a1e6167f1817a54d83ab12b8189589866455a68595260f2ef1fa64a1a440aaa36991dd
|
7
|
+
data.tar.gz: a7b03afec4071dfee9105283308b82d706c6f670c10dd528405b4ae5fa74f755569752ac7d0dd08132f06a40cdd56cab40b20f6f033f7ee6748d749966d8f261
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# RiotJs::Rails
|
2
|
+
|
3
|
+
Muut Riot integration with Rails
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'riot_js-rails'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
TODO: Write usage instructions here
|
20
|
+
|
21
|
+
## Contributing
|
22
|
+
|
23
|
+
1. Fork it ( https://github.com/[my-github-username]/riot_js-rails/fork )
|
24
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
25
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
26
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
27
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module RiotJs
|
2
|
+
module Rails
|
3
|
+
module Helper
|
4
|
+
|
5
|
+
def riot_component(*args, &block)
|
6
|
+
case args.count
|
7
|
+
when 2
|
8
|
+
custom_tag_riot_component(*args, &block)
|
9
|
+
when 3
|
10
|
+
html_tag_riot_component(*args, &block)
|
11
|
+
else
|
12
|
+
raise ArgumentError, 'wrong number of arguments (required 2 or 3)'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def custom_tag_riot_component(name, data, &block)
|
19
|
+
component_name, attributes = component_attributes(name, data)
|
20
|
+
|
21
|
+
component_tag(component_name, attributes, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def html_tag_riot_component(tag, name, data, &block)
|
25
|
+
component_name, attributes = component_attributes(name, data)
|
26
|
+
attributes['riot-tag'] = component_name
|
27
|
+
|
28
|
+
component_tag(tag, attributes, &block)
|
29
|
+
end
|
30
|
+
|
31
|
+
def component_attributes(name, data)
|
32
|
+
component_name = name.to_s.gsub('_', '-')
|
33
|
+
attributes = {
|
34
|
+
id: "riot-#{component_name}-#{Random.rand(10000000)}",
|
35
|
+
class: 'riot-rails-component',
|
36
|
+
data: { opts: data.to_json }
|
37
|
+
}
|
38
|
+
return component_name, attributes
|
39
|
+
end
|
40
|
+
|
41
|
+
def component_tag(tag_name, attributes, &block)
|
42
|
+
if block_given?
|
43
|
+
content_tag(tag_name, attributes, &block)
|
44
|
+
else
|
45
|
+
content_tag(tag_name, attributes) {}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
require 'execjs'
|
3
|
+
require 'byebug'
|
4
|
+
|
5
|
+
module RiotJs
|
6
|
+
module Rails
|
7
|
+
class Compiler
|
8
|
+
include ::ActionView::Helpers::JavaScriptHelper
|
9
|
+
|
10
|
+
JS_RUNTIME = ::ExecJS::ExternalRuntime.new(
|
11
|
+
name: 'Node.js (V8)',
|
12
|
+
command: ['nodejs', 'node'],
|
13
|
+
encoding: 'UTF-8',
|
14
|
+
runner_path: File.expand_path('../../../../../vendor/assets/javascripts/compiler/node_runner.js', __FILE__),
|
15
|
+
)
|
16
|
+
|
17
|
+
RIOT_COMPILER_PATH = File.expand_path('../../../../../vendor/assets/javascripts/compiler/compiler.js', __FILE__)
|
18
|
+
|
19
|
+
def self.instance
|
20
|
+
@@instance ||= new
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.compile(tag_source)
|
24
|
+
instance.compile(tag_source)
|
25
|
+
end
|
26
|
+
|
27
|
+
def compile(tag_source)
|
28
|
+
compiler_source = <<-JS
|
29
|
+
var compiler = require("#{RIOT_COMPILER_PATH}");
|
30
|
+
return compiler.compile("#{escape_javascript(tag_source)}");
|
31
|
+
JS
|
32
|
+
|
33
|
+
JS_RUNTIME.exec(compiler_source)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'riot_js/rails/processors/compiler'
|
2
|
+
|
3
|
+
module RiotJs
|
4
|
+
module Rails
|
5
|
+
class Processor
|
6
|
+
def self.instance
|
7
|
+
@instance ||= new
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.call(input)
|
11
|
+
instance.call(input)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(input)
|
15
|
+
prepare(input)
|
16
|
+
|
17
|
+
data = compile_tag
|
18
|
+
|
19
|
+
@context.metadata.merge(data: data)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def prepare(input)
|
25
|
+
@context = input[:environment].context_class.new(input)
|
26
|
+
@data = input[:data]
|
27
|
+
end
|
28
|
+
|
29
|
+
def compile_tag
|
30
|
+
::RiotJs::Rails::Compiler.compile(@data)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails/railtie'
|
2
|
+
require 'riot_js/rails/processors/processor'
|
3
|
+
require 'riot_js/rails/helper'
|
4
|
+
|
5
|
+
module RiotJs
|
6
|
+
module Rails
|
7
|
+
class Railtie < ::Rails::Railtie
|
8
|
+
initializer :setup_sprockets do |app|
|
9
|
+
app.assets.register_engine '.tag', Processor, mime_type: 'application/javascript'
|
10
|
+
|
11
|
+
if defined?(::Haml)
|
12
|
+
require 'tilt/haml'
|
13
|
+
app.assets.register_engine '.haml', ::Tilt::HamlTemplate, mime_type: 'text/html'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
initializer :add_helpers do |app|
|
18
|
+
helpers = %q{ include ::RiotJs::Rails::Helper }
|
19
|
+
::ActionView::Base.module_eval(helpers)
|
20
|
+
::Rails.application.assets.context_class.class_eval(helpers)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'riot_js/rails/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'riot_js-rails'
|
8
|
+
spec.version = RiotJs::Rails::VERSION
|
9
|
+
spec.authors = ['Bartosz Jaroszewski']
|
10
|
+
spec.email = ['b.jarosze@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Muut Riot integration with Rails.}
|
13
|
+
spec.description = %q{This gem provides integration of Muut Riot with Rails}
|
14
|
+
spec.homepage = 'https://github.com/bjarosze/riot_js-rails'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
|
23
|
+
spec.add_dependency 'rails', '~> 4'
|
24
|
+
spec.add_dependency 'execjs', '~> 2'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.8'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'minitest', '~> 5.1'
|
29
|
+
spec.add_development_dependency 'byebug', '~> 5.0'
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
var compilerPath = require('path').join(__dirname, './compiler_core.js')
|
2
|
+
|
3
|
+
global.riot = require(process.env.RIOT || '../riot')
|
4
|
+
global.riot.parsers = require('./parsers')
|
5
|
+
|
6
|
+
// Evaluate the compiler shared functions in this context
|
7
|
+
/*eslint-disable*/
|
8
|
+
eval(require('fs').readFileSync(compilerPath, 'utf8'))
|
9
|
+
/*eslint-enable*/
|
10
|
+
|
11
|
+
module.exports = {
|
12
|
+
compile: compile,
|
13
|
+
html: compileHTML,
|
14
|
+
style: compileCSS,
|
15
|
+
js: compileJS
|
16
|
+
}
|
@@ -0,0 +1,234 @@
|
|
1
|
+
var BOOL_ATTR = ('allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,default,'+
|
2
|
+
'defaultchecked,defaultmuted,defaultselected,defer,disabled,draggable,enabled,formnovalidate,hidden,'+
|
3
|
+
'indeterminate,inert,ismap,itemscope,loop,multiple,muted,nohref,noresize,noshade,novalidate,nowrap,open,'+
|
4
|
+
'pauseonexit,readonly,required,reversed,scoped,seamless,selected,sortable,spellcheck,translate,truespeed,'+
|
5
|
+
'typemustmatch,visible').split(','),
|
6
|
+
// these cannot be auto-closed
|
7
|
+
VOID_TAGS = 'area,base,br,col,command,embed,hr,img,input,keygen,link,meta,param,source,track,wbr'.split(','),
|
8
|
+
/*
|
9
|
+
Following attributes give error when parsed on browser with { exrp_values }
|
10
|
+
|
11
|
+
'd' describes the SVG <path>, Chrome gives error if the value is not valid format
|
12
|
+
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d
|
13
|
+
*/
|
14
|
+
PREFIX_ATTR = ['style', 'src', 'd'],
|
15
|
+
|
16
|
+
LINE_TAG = /^<([\w\-]+)>(.*)<\/\1>/gim,
|
17
|
+
QUOTE = /=({[^}]+})([\s\/\>]|$)/g,
|
18
|
+
SET_ATTR = /([\w\-]+)=(["'])([^\2]+?)\2/g,
|
19
|
+
EXPR = /{\s*([^}]+)\s*}/g,
|
20
|
+
// (tagname) (html) (javascript) endtag
|
21
|
+
CUSTOM_TAG = /^<([\w\-]+)\s?([^>]*)>([^\x00]*[\w\/}"']>$)?([^\x00]*?)^<\/\1>/gim,
|
22
|
+
SCRIPT = /<script(?:\s+type=['"]?([^>'"]+)['"]?)?>([^\x00]*?)<\/script>/gi,
|
23
|
+
STYLE = /<style(?:\s+([^>]+))?>([^\x00]*?)<\/style>/gi,
|
24
|
+
CSS_SELECTOR = /(^|\}|\{)\s*([^\{\}]+)\s*(?=\{)/g,
|
25
|
+
HTML_COMMENT = /<!--.*?-->/g,
|
26
|
+
CLOSED_TAG = /<([\w\-]+)([^>]*)\/\s*>/g,
|
27
|
+
BLOCK_COMMENT = /\/\*[\s\S]*?\*\//g,
|
28
|
+
LINE_COMMENT = /^\s*\/\/.*$/gm,
|
29
|
+
INPUT_NUMBER = /(<input\s[^>]*?)type=['"]number['"]/gm
|
30
|
+
|
31
|
+
function mktag(name, html, css, attrs, js) {
|
32
|
+
return 'riot.tag(\'' +
|
33
|
+
name + '\', \'' +
|
34
|
+
html + '\'' +
|
35
|
+
(css ? ', \'' + css + '\'' : '') +
|
36
|
+
(attrs ? ', \'' + attrs.replace(/'/g, "\\'") + '\'' : '') +
|
37
|
+
', function(opts) {' + js + '\n});'
|
38
|
+
}
|
39
|
+
|
40
|
+
function compileHTML(html, opts, type) {
|
41
|
+
|
42
|
+
if (!html) return ''
|
43
|
+
|
44
|
+
var brackets = riot.util.brackets,
|
45
|
+
b0 = brackets(0),
|
46
|
+
b1 = brackets(1)
|
47
|
+
|
48
|
+
// foo={ bar } --> foo="{ bar }"
|
49
|
+
html = html.replace(brackets(QUOTE), '="$1"$2')
|
50
|
+
|
51
|
+
// whitespace
|
52
|
+
html = opts.whitespace ? html.replace(/\r\n?|\n/g, '\\n') : html.replace(/\s+/g, ' ')
|
53
|
+
|
54
|
+
// strip comments
|
55
|
+
html = html.trim().replace(HTML_COMMENT, '')
|
56
|
+
|
57
|
+
// input type=numbr
|
58
|
+
html = html.replace(INPUT_NUMBER, '$1riot-type='+ b0 +'"number"'+ b1) // fake expression
|
59
|
+
|
60
|
+
// alter special attribute names
|
61
|
+
html = html.replace(SET_ATTR, function(full, name, _, expr) {
|
62
|
+
if (expr.indexOf(b0) >= 0) {
|
63
|
+
name = name.toLowerCase()
|
64
|
+
|
65
|
+
if (PREFIX_ATTR.indexOf(name) >= 0) name = 'riot-' + name
|
66
|
+
|
67
|
+
// IE8 looses boolean attr values: `checked={ expr }` --> `__checked={ expr }`
|
68
|
+
else if (BOOL_ATTR.indexOf(name) >= 0) name = '__' + name
|
69
|
+
}
|
70
|
+
|
71
|
+
return name + '="' + expr + '"'
|
72
|
+
})
|
73
|
+
|
74
|
+
// run expressions trough parser
|
75
|
+
if (opts.expr) {
|
76
|
+
html = html.replace(brackets(EXPR), function(_, expr) {
|
77
|
+
var ret = compileJS(expr, opts, type).trim().replace(/[\r\n]+/g, '').trim()
|
78
|
+
if (ret.slice(-1) == ';') ret = ret.slice(0, -1)
|
79
|
+
return b0 + ret + b1
|
80
|
+
})
|
81
|
+
}
|
82
|
+
|
83
|
+
// <foo/> -> <foo></foo>
|
84
|
+
html = html.replace(CLOSED_TAG, function(_, name, attr) {
|
85
|
+
var tag = '<' + name + (attr ? ' ' + attr.trim() : '') + '>'
|
86
|
+
|
87
|
+
// Do not self-close HTML5 void tags
|
88
|
+
if (VOID_TAGS.indexOf(name.toLowerCase()) == -1) tag += '</' + name + '>'
|
89
|
+
return tag
|
90
|
+
})
|
91
|
+
|
92
|
+
// escape single quotes
|
93
|
+
html = html.replace(/'/g, "\\'")
|
94
|
+
|
95
|
+
// \{ jotain \} --> \\{ jotain \\}
|
96
|
+
html = html.replace(brackets(/\\{|\\}/g), '\\$&')
|
97
|
+
|
98
|
+
// compact: no whitespace between tags
|
99
|
+
if (opts.compact) html = html.replace(/> </g, '><')
|
100
|
+
|
101
|
+
return html
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
|
106
|
+
function riotjs(js) {
|
107
|
+
|
108
|
+
// strip comments
|
109
|
+
js = js.replace(LINE_COMMENT, '').replace(BLOCK_COMMENT, '')
|
110
|
+
|
111
|
+
// ES6 method signatures
|
112
|
+
var lines = js.split('\n'),
|
113
|
+
es6Ident = ''
|
114
|
+
|
115
|
+
lines.forEach(function(line, i) {
|
116
|
+
var l = line.trim()
|
117
|
+
|
118
|
+
// method start
|
119
|
+
if (l[0] != '}' && ~l.indexOf('(')) {
|
120
|
+
var end = l.match(/[{}]$/),
|
121
|
+
m = end && line.match(/^(\s+)([$\w]+)\s*\(([$\w,\s]*)\)\s*\{/)
|
122
|
+
|
123
|
+
if (m && !/^(if|while|switch|for|catch|function)$/.test(m[2])) {
|
124
|
+
lines[i] = m[1] + 'this.' + m[2] + ' = function(' + m[3] + ') {'
|
125
|
+
|
126
|
+
// foo() { }
|
127
|
+
if (end[0] == '}') {
|
128
|
+
lines[i] += ' ' + l.slice(m[0].length - 1, -1) + '}.bind(this)'
|
129
|
+
|
130
|
+
} else {
|
131
|
+
es6Ident = m[1]
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
}
|
136
|
+
|
137
|
+
// method end
|
138
|
+
if (line.slice(0, es6Ident.length + 1) == es6Ident + '}') {
|
139
|
+
lines[i] = es6Ident + '}.bind(this);'
|
140
|
+
es6Ident = ''
|
141
|
+
}
|
142
|
+
|
143
|
+
})
|
144
|
+
|
145
|
+
return lines.join('\n')
|
146
|
+
|
147
|
+
}
|
148
|
+
|
149
|
+
function scopedCSS (tag, style, type) {
|
150
|
+
// 1. Remove CSS comments
|
151
|
+
// 2. Find selectors and separate them by conmma
|
152
|
+
// 3. keep special selectors as is
|
153
|
+
// 4. prepend tag and [riot-tag]
|
154
|
+
return style.replace(BLOCK_COMMENT, '').replace(CSS_SELECTOR, function (m, p1, p2) {
|
155
|
+
return p1 + ' ' + p2.split(/\s*,\s*/g).map(function(sel) {
|
156
|
+
var s = sel.trim()
|
157
|
+
var t = (/:scope/.test(s) ? '' : ' ') + s.replace(/:scope/, '')
|
158
|
+
return s[0] == '@' || s == 'from' || s == 'to' || /%$/.test(s) ? s :
|
159
|
+
tag + t + ', [riot-tag="' + tag + '"]' + t
|
160
|
+
}).join(',')
|
161
|
+
}).trim()
|
162
|
+
}
|
163
|
+
|
164
|
+
function compileJS(js, opts, type) {
|
165
|
+
if (!js) return ''
|
166
|
+
var parser = opts.parser || (type ? riot.parsers.js[type] : riotjs)
|
167
|
+
if (!parser) throw new Error('Parser not found "' + type + '"')
|
168
|
+
return parser(js.replace(/\r\n?/g, '\n'), opts)
|
169
|
+
}
|
170
|
+
|
171
|
+
function compileTemplate(lang, html) {
|
172
|
+
var parser = riot.parsers.html[lang]
|
173
|
+
if (!parser) throw new Error('Template parser not found "' + lang + '"')
|
174
|
+
return parser(html.replace(/\r\n?/g, '\n'))
|
175
|
+
}
|
176
|
+
|
177
|
+
function compileCSS(style, tag, type, scoped) {
|
178
|
+
if (type === 'scoped-css') scoped = 1
|
179
|
+
else if (riot.parsers.css[type]) style = riot.parsers.css[type](tag, style)
|
180
|
+
else if (type !== 'css') throw new Error('CSS parser not found: "' + type + '"')
|
181
|
+
if (scoped) style = scopedCSS(tag, style)
|
182
|
+
return style.replace(/\s+/g, ' ').replace(/\\/g, '\\\\').replace(/'/g, "\\'").trim()
|
183
|
+
}
|
184
|
+
|
185
|
+
function compile(src, opts) {
|
186
|
+
|
187
|
+
if (!opts) opts = {}
|
188
|
+
else {
|
189
|
+
|
190
|
+
if (opts.brackets) riot.settings.brackets = opts.brackets
|
191
|
+
|
192
|
+
if (opts.template) src = compileTemplate(opts.template, src)
|
193
|
+
}
|
194
|
+
|
195
|
+
src = src.replace(LINE_TAG, function(_, tagName, html) {
|
196
|
+
return mktag(tagName, compileHTML(html, opts), '', '', '')
|
197
|
+
})
|
198
|
+
|
199
|
+
return src.replace(CUSTOM_TAG, function(_, tagName, attrs, html, js) {
|
200
|
+
var style = '',
|
201
|
+
type = opts.type
|
202
|
+
|
203
|
+
if (html) {
|
204
|
+
|
205
|
+
// js wrapped inside <script> tag
|
206
|
+
if (!js.trim()) {
|
207
|
+
html = html.replace(SCRIPT, function(_, _type, script) {
|
208
|
+
if (_type) type = _type.replace('text/', '')
|
209
|
+
js = script
|
210
|
+
return ''
|
211
|
+
})
|
212
|
+
}
|
213
|
+
|
214
|
+
// styles in <style> tag
|
215
|
+
html = html.replace(STYLE, function(_, types, _style) {
|
216
|
+
var scoped = /(?:^|\s+)scoped(\s|=|$)/i.test(types),
|
217
|
+
type = types && types.match(/(?:^|\s+)type\s*=\s*['"]?([^'"\s]+)['"]?/i)
|
218
|
+
if (type) type = type[1].replace('text/', '')
|
219
|
+
style += (style ? ' ' : '') + compileCSS(_style.trim(), tagName, type || 'css', scoped)
|
220
|
+
return ''
|
221
|
+
})
|
222
|
+
}
|
223
|
+
|
224
|
+
return mktag(
|
225
|
+
tagName,
|
226
|
+
compileHTML(html, opts, type),
|
227
|
+
style,
|
228
|
+
compileHTML(attrs, ''),
|
229
|
+
compileJS(js, opts, type)
|
230
|
+
)
|
231
|
+
|
232
|
+
})
|
233
|
+
|
234
|
+
}
|