tmpl.v: fix of is_html_open_tag function and allow usage of V template sign '@' in JS code (#13067)
parent
d3317cbd4f
commit
a73e1462f0
|
@ -15,25 +15,30 @@ enum State {
|
|||
// span // span.{
|
||||
}
|
||||
|
||||
const tmpl_str_end = "')\n"
|
||||
|
||||
// check HTML open tag `<name attr="x" >`
|
||||
fn is_html_open_tag(name string, s string) bool {
|
||||
mut len := s.len
|
||||
trimmed_line := s.trim_space()
|
||||
mut len := trimmed_line.len
|
||||
|
||||
if len < name.len {
|
||||
return false
|
||||
}
|
||||
mut sub := s[0..1]
|
||||
|
||||
mut sub := trimmed_line[0..1]
|
||||
if sub != '<' { // not start with '<'
|
||||
return false
|
||||
}
|
||||
sub = s[len - 1..len]
|
||||
sub = trimmed_line[len - 1..len]
|
||||
if sub != '>' { // not end with '<'
|
||||
return false
|
||||
}
|
||||
sub = s[len - 2..len - 1]
|
||||
sub = trimmed_line[len - 2..len - 1]
|
||||
if sub == '/' { // self-closing
|
||||
return false
|
||||
}
|
||||
sub = s[1..len - 1]
|
||||
sub = trimmed_line[1..len - 1]
|
||||
if sub.contains_any('<>') { // `<name <bad> >`
|
||||
return false
|
||||
}
|
||||
|
@ -51,6 +56,21 @@ fn is_html_open_tag(name string, s string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn insert_template_code(fn_name string, tmpl_str_start string, line string) string {
|
||||
// HTML, may include `@var`
|
||||
// escaped by cgen, unless it's a `vweb.RawHtml` string
|
||||
trailing_bs := parser.tmpl_str_end + 'sb_${fn_name}.write_b(92)\n' + tmpl_str_start
|
||||
round1 := ['\\', '\\\\', r"'", "\\'", r'@', r'$']
|
||||
round2 := [r'$$', r'\@', r'.$', r'.@']
|
||||
mut rline := line.replace_each(round1).replace_each(round2)
|
||||
|
||||
if rline.ends_with('\\') {
|
||||
rline = rline[0..rline.len - 2] + trailing_bs
|
||||
}
|
||||
|
||||
return rline
|
||||
}
|
||||
|
||||
// compile_file compiles the content of a file by the given path as a template
|
||||
pub fn (mut p Parser) compile_template_file(template_file string, fn_name string) string {
|
||||
mut lines := os.read_lines(template_file) or {
|
||||
|
@ -60,7 +80,6 @@ pub fn (mut p Parser) compile_template_file(template_file string, fn_name string
|
|||
basepath := os.dir(template_file)
|
||||
lstartlength := lines.len * 30
|
||||
tmpl_str_start := "sb_${fn_name}.write_string('"
|
||||
tmpl_str_end := "')\n"
|
||||
mut source := strings.new_builder(1000)
|
||||
source.writeln('
|
||||
import strings
|
||||
|
@ -170,24 +189,24 @@ fn vweb_tmpl_${fn_name}() string {
|
|||
source.write_string(line[pos + 6..line.len - 1])
|
||||
source.writeln('" rel="stylesheet" type="text/css">')
|
||||
} else if line.contains('@if ') {
|
||||
source.writeln(tmpl_str_end)
|
||||
source.writeln(parser.tmpl_str_end)
|
||||
pos := line.index('@if') or { continue }
|
||||
source.writeln('if ' + line[pos + 4..] + '{')
|
||||
source.writeln(tmpl_str_start)
|
||||
} else if line.contains('@end') {
|
||||
// Remove new line byte
|
||||
source.go_back(1)
|
||||
source.writeln(tmpl_str_end)
|
||||
source.writeln(parser.tmpl_str_end)
|
||||
source.writeln('}')
|
||||
source.writeln(tmpl_str_start)
|
||||
} else if line.contains('@else') {
|
||||
// Remove new line byte
|
||||
source.go_back(1)
|
||||
source.writeln(tmpl_str_end)
|
||||
source.writeln(parser.tmpl_str_end)
|
||||
source.writeln(' } else { ')
|
||||
source.writeln(tmpl_str_start)
|
||||
} else if line.contains('@for') {
|
||||
source.writeln(tmpl_str_end)
|
||||
source.writeln(parser.tmpl_str_end)
|
||||
pos := line.index('@for') or { continue }
|
||||
source.writeln('for ' + line[pos + 4..] + '{')
|
||||
source.writeln(tmpl_str_start)
|
||||
|
@ -216,28 +235,22 @@ fn vweb_tmpl_${fn_name}() string {
|
|||
source.writeln('</div>')
|
||||
}
|
||||
} else if state == .js {
|
||||
// replace `$` to `\$` at first to escape JavaScript template literal syntax
|
||||
source.writeln(line.replace(r'$', r'\$').replace(r'$$', r'@').replace(r'.$',
|
||||
r'.@').replace(r"'", r"\'"))
|
||||
if line.contains('//V_TEMPLATE') {
|
||||
source.writeln(insert_template_code(fn_name, tmpl_str_start, line))
|
||||
} else {
|
||||
// replace `$` to `\$` at first to escape JavaScript template literal syntax
|
||||
source.writeln(line.replace(r'$', r'\$').replace(r'$$', r'@').replace(r'.$',
|
||||
r'.@').replace(r"'", r"\'"))
|
||||
}
|
||||
} else if state == .css {
|
||||
// disable template variable declaration in inline stylesheet
|
||||
// because of some CSS rules prefixed with `@`.
|
||||
source.writeln(line.replace(r'.$', r'.@').replace(r"'", r"\'"))
|
||||
} else {
|
||||
// HTML, may include `@var`
|
||||
// escaped by cgen, unless it's a `vweb.RawHtml` string
|
||||
trailing_bs := tmpl_str_end + 'sb_${fn_name}.write_b(92)\n' + tmpl_str_start
|
||||
round1 := ['\\', '\\\\', r"'", "\\'", r'@', r'$']
|
||||
round2 := [r'$$', r'\@', r'.$', r'.@']
|
||||
rline := line.replace_each(round1).replace_each(round2)
|
||||
if rline.ends_with('\\') {
|
||||
source.writeln(rline[0..rline.len - 2] + trailing_bs)
|
||||
} else {
|
||||
source.writeln(rline)
|
||||
}
|
||||
source.writeln(insert_template_code(fn_name, tmpl_str_start, line))
|
||||
}
|
||||
}
|
||||
source.writeln(tmpl_str_end)
|
||||
source.writeln(parser.tmpl_str_end)
|
||||
source.writeln('_tmpl_res_$fn_name := sb_${fn_name}.str() ')
|
||||
source.writeln('return _tmpl_res_$fn_name')
|
||||
source.writeln('}')
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// V won't parse that
|
||||
<script>
|
||||
var non_interpolated_labels = @benchmark_plot_data.dates;
|
||||
var non_interpolated_values = @benchmark_plot_data.numerical_result;
|
||||
</script>
|
||||
|
||||
// V will parse that
|
||||
<script>
|
||||
var real_labels = @benchmark_plot_data.dates; //V_TEMPLATE
|
||||
var real_values = @benchmark_plot_data.numerical_result; //V_TEMPLATE
|
||||
</script>
|
|
@ -0,0 +1,16 @@
|
|||
module main
|
||||
|
||||
struct PlotData {
|
||||
dates []string
|
||||
numerical_result []int
|
||||
}
|
||||
|
||||
fn test_template_interpolation_can_be_selectively_turned_on_in_script_tags() {
|
||||
benchmark_plot_data := PlotData{['2012-11-30', '2022-12-29'], [5, 6, 7, 1]}
|
||||
text := $tmpl('tmpl/selective_interpolation_in_script_tag.html')
|
||||
// dump(text)
|
||||
assert text.contains('var non_interpolated_labels = @benchmark_plot_data.dates;')
|
||||
assert text.contains('var non_interpolated_values = @benchmark_plot_data.numerical_result;')
|
||||
assert text.contains("var real_labels = ['2012-11-30', '2022-12-29']; //V_TEMPLATE")
|
||||
assert text.contains('var real_values = [5, 6, 7, 1]; //V_TEMPLATE')
|
||||
}
|
Loading…
Reference in New Issue