diff --git a/Cargo.lock b/Cargo.lock index 8c933a53b1..309607ea08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1519,7 +1519,7 @@ dependencies = [ [[package]] name = "fastn" -version = "0.3.49" +version = "0.3.51" dependencies = [ "clap", "colored", diff --git a/fastn-core/src/package/package_doc.rs b/fastn-core/src/package/package_doc.rs index d8138e563f..f76aa0372d 100644 --- a/fastn-core/src/package/package_doc.rs +++ b/fastn-core/src/package/package_doc.rs @@ -434,7 +434,7 @@ pub(crate) async fn read_ftd_2022( } }; config.dependencies_during_render = lib.config.dependencies_during_render; - if let Some((url, code)) = main_ftd_doc.get_redirect() { + if let Some((url, code)) = main_ftd_doc.get_redirect()? { return Ok(FTDResult::Redirect { url, code }); } let executor = ftd::executor::ExecuteDoc::from_interpreter(main_ftd_doc)?; @@ -507,7 +507,7 @@ pub(crate) async fn read_ftd_2023( } }; config.dependencies_during_render = lib.config.dependencies_during_render; - if let Some((url, code)) = main_ftd_doc.get_redirect() { + if let Some((url, code)) = main_ftd_doc.get_redirect()? { return Ok(FTDResult::Redirect { url, code }); } diff --git a/fastn-js/js/dom.js b/fastn-js/js/dom.js index df3d4474e2..7ca6102235 100644 --- a/fastn-js/js/dom.js +++ b/fastn-js/js/dom.js @@ -1756,19 +1756,27 @@ class Node2 { this.#node.classList.remove("line-numbers"); } } else if (kind === fastn_dom.PropertyKind.CodeTheme) { + this.#extraData.code = this.#extraData.code ? this.#extraData.code : {}; + if(fastn_utils.isNull(staticValue)) { + if(!fastn_utils.isNull(this.#extraData.code.theme)) { + this.#node.classList.remove(this.#extraData.code.theme); + } + return; + } if (!ssr) { fastn_utils.addCodeTheme(staticValue); } + staticValue = fastn_utils.getStaticValue(staticValue); let theme = staticValue.replace("\.", "-"); - this.#extraData.code = this.#extraData.code ? this.#extraData.code : {}; - if (this.#extraData.code.theme) { - this.#node.classList.remove(theme); + if (this.#extraData.code.theme !== theme) { + let codeNode = this.#children[0].getNode(); + this.#node.classList.remove(this.#extraData.code.theme); + codeNode.classList.remove(this.#extraData.code.theme); + this.#extraData.code.theme = theme; + this.#node.classList.add(theme); + codeNode.classList.add(theme); + fastn_utils.highlightCode(codeNode, this.#extraData.code); } - this.#extraData.code.theme = theme; - this.#node.classList.add(theme); - let codeNode = this.#children[0].getNode(); - codeNode.classList.add(theme); - fastn_utils.highlightCode(codeNode, this.#extraData.code); } else if (kind === fastn_dom.PropertyKind.CodeLanguage) { let language = `language-${staticValue}`; this.#extraData.code = this.#extraData.code ? this.#extraData.code : {}; @@ -1824,8 +1832,7 @@ class Node2 { } else if (kind === fastn_dom.PropertyKind.StringValue) { this.#rawInnerValue = staticValue; if (!ssr) { - let escapedHtmlValue = fastn_utils.escapeHtmlInMarkdown(staticValue); - staticValue = fastn_utils.markdown_inline(escapedHtmlValue); + staticValue = fastn_utils.markdown_inline(staticValue); staticValue = fastn_utils.process_post_markdown(this.#node, staticValue); } this.#node.innerHTML = staticValue; diff --git a/fastn-js/js/utils.js b/fastn-js/js/utils.js index 70d9c89925..45fac08a34 100644 --- a/fastn-js/js/utils.js +++ b/fastn-js/js/utils.js @@ -421,21 +421,22 @@ let fastn_utils = { }, escapeHtmlInMarkdown(str) { + if(typeof str !== 'string') { + return str; + } + let result = ""; let ch_map = { - '<': "<" + '<': "<", + '>': ">", + '&': "&", + '"': """, + "'": "'", + '/': "/", }; - // To avoid replacing html characters inside body - let backtick_found = false; for (var i = 0; i < str.length; i++) { let current = str[i]; - if (current === '`') backtick_found = !backtick_found; - if (ch_map[current] !== undefined && !backtick_found) { - result += ch_map[current]; - } - else { - result += current; - } + result += ch_map[current] ?? current; } return result; }, diff --git a/fastn-js/js/virtual.js b/fastn-js/js/virtual.js index 96943ff361..15f293ebb5 100644 --- a/fastn-js/js/virtual.js +++ b/fastn-js/js/virtual.js @@ -68,7 +68,7 @@ class Node { toHtmlAsString() { const openingTag = `<${this.#tagName}${this.getDataIdString()}${this.getAttributesString()}${this.getClassString()}${this.getStyleString()}>`; const closingTag = ``; - const innerHTML = this.innerHTML; + const innerHTML = fastn_utils.escapeHtmlInMarkdown(this.innerHTML); const childNodes = this.#children.map(child => child.toHtmlAsString()).join(''); return `${openingTag}${innerHTML}${childNodes}${closingTag}`; diff --git a/fastn/Cargo.toml b/fastn/Cargo.toml index 3f2ba5399f..b2486b0765 100644 --- a/fastn/Cargo.toml +++ b/fastn/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fastn" -version = "0.3.49" +version = "0.3.51" authors.workspace = true edition.workspace = true license.workspace = true diff --git a/ftd/src/interpreter/main.rs b/ftd/src/interpreter/main.rs index 8c72928a9c..ae34cca2c1 100644 --- a/ftd/src/interpreter/main.rs +++ b/ftd/src/interpreter/main.rs @@ -1100,29 +1100,33 @@ impl Document { .collect_vec() } - pub fn get_redirect(&self) -> Option<(String, i32)> { + pub fn get_redirect(&self) -> ftd::interpreter::Result> { let components = self.get_instructions("ftd#redirect"); - let c = match components.iter().find(|v| { + + for v in &components { + let url = v + .get_interpreter_value_of_argument("url", &self.tdoc()) + .and_then(|v| v.string(self.name.as_str(), 0).ok()); + let code = v + .get_interpreter_value_of_argument("code", &self.tdoc()) + .and_then(|v| v.integer(self.name.as_str(), 0).ok()); + + if v.condition.is_none() { + return Ok(url.and_then(|url| code.map(|code| (url, code as i32)))); + } + if let Some(expr) = &v.condition.as_ref() { - if let Ok(b) = expr.eval(&self.tdoc()) { - b - } else { - false + match expr.eval(&self.tdoc()) { + Ok(b) if b => { + return Ok(url.and_then(|url| code.map(|code| (url, code as i32)))) + } + Err(e) => return Err(e), + _ => {} } - } else { - true } - }) { - Some(v) => v, - None => return None, - }; - let url = c - .get_interpreter_value_of_argument("url", &self.tdoc()) - .and_then(|v| v.string(self.name.as_str(), 0).ok()); - let code = c - .get_interpreter_value_of_argument("code", &self.tdoc()) - .and_then(|v| v.integer(self.name.as_str(), 0).ok()); - url.and_then(|url| code.map(|code| (url, code as i32))) + } + + Ok(None) } } diff --git a/ftd/src/js/mod.rs b/ftd/src/js/mod.rs index 473acebb8c..19b2b2711b 100644 --- a/ftd/src/js/mod.rs +++ b/ftd/src/js/mod.rs @@ -417,8 +417,15 @@ impl ftd::interpreter::Component { has_rive_components, ) { kernel_component_statements - } else if let Some(defined_component_statements) = - self.defined_component_to_component_statements(parent, index, doc, rdata, should_return) + } else if let Some(defined_component_statements) = self + .defined_component_to_component_statements( + parent, + index, + doc, + rdata, + should_return, + has_rive_components, + ) { defined_component_statements } else if let Some(header_defined_component_statements) = self @@ -459,7 +466,7 @@ impl ftd::interpreter::Component { ) -> Option> { if ftd::js::element::is_kernel(self.name.as_str()) { if !*has_rive_components { - *has_rive_components = ftd::js::element::is_rive_component(self.name.as_str()) + *has_rive_components = ftd::js::element::is_rive_component(self.name.as_str()); } Some( ftd::js::Element::from_interpreter_component(self, doc).to_component_statements( @@ -483,6 +490,7 @@ impl ftd::interpreter::Component { doc: &ftd::interpreter::TDoc, rdata: &ftd::js::ResolverData, should_return: bool, + has_rive_components: &mut bool, ) -> Option> { if let Some(arguments) = ftd::js::utils::get_set_property_values_for_provided_component_properties( @@ -491,6 +499,7 @@ impl ftd::interpreter::Component { self.name.as_str(), self.properties.as_slice(), self.line_number, + has_rive_components, ) { let mut component_statements = vec![]; @@ -563,6 +572,7 @@ impl ftd::interpreter::Component { component_name.as_str(), self.properties.as_slice(), self.line_number, + has_rive_components, )?; } else if !ftd::js::utils::is_ui_argument( component.arguments.as_slice(), diff --git a/ftd/src/js/utils.rs b/ftd/src/js/utils.rs index 150aa75fce..8ce8d7eb6f 100644 --- a/ftd/src/js/utils.rs +++ b/ftd/src/js/utils.rs @@ -256,6 +256,7 @@ pub(crate) fn get_set_property_values_for_provided_component_properties( component_name: &str, component_properties: &[ftd::interpreter::Property], line_number: usize, + has_rive_components: &mut bool, ) -> Option> { use itertools::Itertools; @@ -270,8 +271,17 @@ pub(crate) fn get_set_property_values_for_provided_component_properties( arguments .iter() .filter_map(|v| { - v.get_optional_value(component_properties) - .map(|val| (v.name.to_string(), val.to_set_property_value(doc, rdata))) + v.get_optional_value(component_properties).map(|val| { + ( + v.name.to_string(), + val.to_set_property_value_with_ui( + doc, + rdata, + has_rive_components, + false, + ), + ) + }) }) .collect_vec() }) diff --git a/ftd/t/js/01-basic.html b/ftd/t/js/01-basic.html index 83b955ae5b..ae244c274f 100644 --- a/ftd/t/js/01-basic.html +++ b/ftd/t/js/01-basic.html @@ -16,7 +16,7 @@ -
"Hello"
Hello
Hello
-
Start Idle
Idle/ Run
Wiper On/Off
Rainy On/Off
No Wiper On/Off
Sunny On/Off
Stationary On/Off
Bouncing On/Off
Broken On/Off
-
fastn
 
language
Enter name:
Enter score:
1
Arpita
100
2
Arpita
90
Total items are:
2
-
/-- ds.code:
+
/-- ds.code:
 lang: ftd
 
 fooo
 
;; Section Comment
 
-/-- ftd.text:
+/-- ftd.text:
 color: red
 
 This is body part of ftd.text
@@ -31,7 +31,7 @@
 
 -- ftd.text: Hello ;; This is inline comment
 
--- import: fastn-community.github.io/bling/quote
+-- import: fastn-community.github.io/bling/quote
 
 ;; Component invocation
 
@@ -96,7 +96,7 @@
 $loop$: $foo as $ui
 
;; Section Comment
 
-/-- ftd.text:
+/-- ftd.text:
 color: red
 
 This is body part of ftd.text
@@ -105,7 +105,7 @@
 
 -- ftd.text: Hello ;; This is inline comment
 
--- import: fastn-community.github.io/bling/quote
+-- import: fastn-community.github.io/bling/quote
 
 ;; Component invocation
 
diff --git a/ftd/t/js/53-link-color.html b/ftd/t/js/53-link-color.html
index a2126a6d6f..ac8937a99b 100644
--- a/ftd/t/js/53-link-color.html
+++ b/ftd/t/js/53-link-color.html
@@ -16,9 +16,9 @@
     
 
 
-
Click me
Hello world [Test](https://google.com) +
Click me
Hello world [Test](https://google.com) -This is awesome [Test](https://google.com)
diff --git a/ftd/t/js/56-title-fix.ftd b/ftd/t/js/56-title-fix.ftd new file mode 100644 index 0000000000..5336920e87 --- /dev/null +++ b/ftd/t/js/56-title-fix.ftd @@ -0,0 +1,5 @@ +-- ftd.text: + +this is a `` + +;; Escaped Output: this is a `<title>` diff --git a/ftd/t/js/56-title-fix.html b/ftd/t/js/56-title-fix.html new file mode 100644 index 0000000000..255d8cb981 --- /dev/null +++ b/ftd/t/js/56-title-fix.html @@ -0,0 +1,79 @@ +<html> +<head> + <meta charset="UTF-8"> + + <meta content="fastn" name="generator"> + + + <script> + let __fastn_package_name__ = "foo"; + </script> + + <script src="fastn-js.js"></script> + + <style> + + </style> +</head> +<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> +<body data-id="1"><div data-id="2" class="ft_column __w-1 __h-2"><div data-id="3">this is a `<title>`</div></div></body><style id="styles"> + .__w-1 { width: 100%; } + .__h-2 { height: 100%; } + </style> +<script> + (function() { + let global = { +}; +let main = function (parent) { + let __fastn_super_package_name__ = __fastn_package_name__; + __fastn_package_name__ = "foo"; + try { + let parenti0 = fastn_dom.createKernel(parent, fastn_dom.ElementKind.Text); + parenti0.setProperty(fastn_dom.PropertyKind.StringValue, "this is a `<title>`", inherited); + } finally { + __fastn_package_name__ = __fastn_super_package_name__; + } +} +global["main"] = main; +fastn_dom.codeData.availableThemes["coldark-theme.dark"] = "../../theme_css/coldark-theme.dark.css"; +fastn_dom.codeData.availableThemes["coldark-theme.light"] = "../../theme_css/coldark-theme.light.css"; +fastn_dom.codeData.availableThemes["coy-theme"] = "../../theme_css/coy-theme.css"; +fastn_dom.codeData.availableThemes["dracula-theme"] = "../../theme_css/dracula-theme.css"; +fastn_dom.codeData.availableThemes["duotone-theme.dark"] = "../../theme_css/duotone-theme.dark.css"; +fastn_dom.codeData.availableThemes["duotone-theme.earth"] = "../../theme_css/duotone-theme.earth.css"; +fastn_dom.codeData.availableThemes["duotone-theme.forest"] = "../../theme_css/duotone-theme.forest.css"; +fastn_dom.codeData.availableThemes["duotone-theme.light"] = "../../theme_css/duotone-theme.light.css"; +fastn_dom.codeData.availableThemes["duotone-theme.sea"] = "../../theme_css/duotone-theme.sea.css"; +fastn_dom.codeData.availableThemes["duotone-theme.space"] = "../../theme_css/duotone-theme.space.css"; +fastn_dom.codeData.availableThemes["fastn-theme.dark"] = "../../theme_css/fastn-theme.dark.css"; +fastn_dom.codeData.availableThemes["fastn-theme.light"] = "../../theme_css/fastn-theme.light.css"; +fastn_dom.codeData.availableThemes["fire.light"] = "../../theme_css/fire.light.css"; +fastn_dom.codeData.availableThemes["gruvbox-theme.dark"] = "../../theme_css/gruvbox-theme.dark.css"; +fastn_dom.codeData.availableThemes["gruvbox-theme.light"] = "../../theme_css/gruvbox-theme.light.css"; +fastn_dom.codeData.availableThemes["laserwave-theme"] = "../../theme_css/laserwave-theme.css"; +fastn_dom.codeData.availableThemes["material-theme.dark"] = "../../theme_css/material-theme.dark.css"; +fastn_dom.codeData.availableThemes["material-theme.light"] = "../../theme_css/material-theme.light.css"; +fastn_dom.codeData.availableThemes["nightowl-theme"] = "../../theme_css/nightowl-theme.css"; +fastn_dom.codeData.availableThemes["one-theme.dark"] = "../../theme_css/one-theme.dark.css"; +fastn_dom.codeData.availableThemes["one-theme.light"] = "../../theme_css/one-theme.light.css"; +fastn_dom.codeData.availableThemes["vs-theme.dark"] = "../../theme_css/vs-theme.dark.css"; +fastn_dom.codeData.availableThemes["vs-theme.light"] = "../../theme_css/vs-theme.light.css"; +fastn_dom.codeData.availableThemes["ztouch-theme"] = "../../theme_css/ztouch-theme.css"; + + let main_wrapper = function (parent) { + let parenti0 = fastn_dom.createKernel(parent, fastn_dom.ElementKind.Column); + parenti0.setProperty(fastn_dom.PropertyKind.Width, fastn_dom.Resizing.FillContainer, inherited); + parenti0.setProperty(fastn_dom.PropertyKind.Height, fastn_dom.Resizing.FillContainer, inherited); + main(parenti0); + } + fastn_virtual.hydrate(main_wrapper); + ftd.post_init(); + })(); + + window.onload = function() { + fastn_utils.resetFullHeight(); + fastn_utils.setFullHeight(); + }; + +</script> +</html> diff --git a/ftd/t/js/57-code-dark-mode.ftd b/ftd/t/js/57-code-dark-mode.ftd new file mode 100644 index 0000000000..b0025b8672 --- /dev/null +++ b/ftd/t/js/57-code-dark-mode.ftd @@ -0,0 +1,15 @@ +-- ftd.code: +lang: ftd +role: $inherited.types.copy-small +theme: fastn-theme.light +theme if { ftd.dark-mode }: fastn-theme.dark + +\-- ftd.column: +padding.px: 10 ;; <hl> +spacing.fixed.px: "50" +height.fixed.px: 200 +width.fixed.px: 300 ;; <hl> +overflow-y: scroll +border-color: $red-yellow +border-style: solid +border-width.px: 2 diff --git a/ftd/t/js/57-code-dark-mode.html b/ftd/t/js/57-code-dark-mode.html new file mode 100644 index 0000000000..e4a62abc00 --- /dev/null +++ b/ftd/t/js/57-code-dark-mode.html @@ -0,0 +1,103 @@ +<html> +<head> + <meta charset="UTF-8"> + + <meta content="fastn" name="generator"> + + + <script> + let __fastn_package_name__ = "foo"; + </script> + + <script src="fastn-js.js"></script> + + <style> + + </style> +</head> +<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"> +<body data-id="1"><div data-id="2" class="ft_column __w-1 __h-2"><pre data-id="3" data-line="2,5" class="language-ftd fastn-theme-light __rl-3"><code data-id="4" class="language-ftd fastn-theme-light">-- ftd.column: +padding.px: 10 +spacing.fixed.px: "50" +height.fixed.px: 200 +width.fixed.px: 300 +overflow-y: scroll +border-color: $red-yellow +border-style: solid +border-width.px: 2 +</code></pre></div></body><style id="styles"> + .__w-1 { width: 100%; } + .__h-2 { height: 100%; } + .__rl-3 { font-family: sans-serif; font-size: 14px; font-weight: 400; line-height: 24px; } + body.mobile .__rl-3 { font-family: sans-serif; font-size: 12px; font-weight: 400; line-height: 16px; } + </style> +<script> + (function() { + let global = { +}; +let main = function (parent) { + let __fastn_super_package_name__ = __fastn_package_name__; + __fastn_package_name__ = "foo"; + try { + let parenti0 = fastn_dom.createKernel(parent, fastn_dom.ElementKind.Code); + parenti0.setProperty(fastn_dom.PropertyKind.Code, "-- ftd.column:\npadding.px: 10 ;; <hl>\nspacing.fixed.px: \"50\"\nheight.fixed.px: 200\nwidth.fixed.px: 300 ;; <hl>\noverflow-y: scroll\nborder-color: $red-yellow\nborder-style: solid\nborder-width.px: 2", inherited); + parenti0.setProperty(fastn_dom.PropertyKind.CodeLanguage, "ftd", inherited); + parenti0.setProperty(fastn_dom.PropertyKind.CodeTheme, fastn.formula([ftd.dark_mode], function () { + if (function () { + return fastn_utils.getter(ftd.dark_mode); + }()) { + return "fastn-theme.dark"; + } else { + return "fastn-theme.light"; + } + } + ), inherited); + parenti0.setProperty(fastn_dom.PropertyKind.CodeShowLineNumber, false, inherited); + parenti0.setProperty(fastn_dom.PropertyKind.Role, inherited.get("types").get("copy_small"), inherited); + } finally { + __fastn_package_name__ = __fastn_super_package_name__; + } +} +global["main"] = main; +fastn_dom.codeData.availableThemes["coldark-theme.dark"] = "../../theme_css/coldark-theme.dark.css"; +fastn_dom.codeData.availableThemes["coldark-theme.light"] = "../../theme_css/coldark-theme.light.css"; +fastn_dom.codeData.availableThemes["coy-theme"] = "../../theme_css/coy-theme.css"; +fastn_dom.codeData.availableThemes["dracula-theme"] = "../../theme_css/dracula-theme.css"; +fastn_dom.codeData.availableThemes["duotone-theme.dark"] = "../../theme_css/duotone-theme.dark.css"; +fastn_dom.codeData.availableThemes["duotone-theme.earth"] = "../../theme_css/duotone-theme.earth.css"; +fastn_dom.codeData.availableThemes["duotone-theme.forest"] = "../../theme_css/duotone-theme.forest.css"; +fastn_dom.codeData.availableThemes["duotone-theme.light"] = "../../theme_css/duotone-theme.light.css"; +fastn_dom.codeData.availableThemes["duotone-theme.sea"] = "../../theme_css/duotone-theme.sea.css"; +fastn_dom.codeData.availableThemes["duotone-theme.space"] = "../../theme_css/duotone-theme.space.css"; +fastn_dom.codeData.availableThemes["fastn-theme.dark"] = "../../theme_css/fastn-theme.dark.css"; +fastn_dom.codeData.availableThemes["fastn-theme.light"] = "../../theme_css/fastn-theme.light.css"; +fastn_dom.codeData.availableThemes["fire.light"] = "../../theme_css/fire.light.css"; +fastn_dom.codeData.availableThemes["gruvbox-theme.dark"] = "../../theme_css/gruvbox-theme.dark.css"; +fastn_dom.codeData.availableThemes["gruvbox-theme.light"] = "../../theme_css/gruvbox-theme.light.css"; +fastn_dom.codeData.availableThemes["laserwave-theme"] = "../../theme_css/laserwave-theme.css"; +fastn_dom.codeData.availableThemes["material-theme.dark"] = "../../theme_css/material-theme.dark.css"; +fastn_dom.codeData.availableThemes["material-theme.light"] = "../../theme_css/material-theme.light.css"; +fastn_dom.codeData.availableThemes["nightowl-theme"] = "../../theme_css/nightowl-theme.css"; +fastn_dom.codeData.availableThemes["one-theme.dark"] = "../../theme_css/one-theme.dark.css"; +fastn_dom.codeData.availableThemes["one-theme.light"] = "../../theme_css/one-theme.light.css"; +fastn_dom.codeData.availableThemes["vs-theme.dark"] = "../../theme_css/vs-theme.dark.css"; +fastn_dom.codeData.availableThemes["vs-theme.light"] = "../../theme_css/vs-theme.light.css"; +fastn_dom.codeData.availableThemes["ztouch-theme"] = "../../theme_css/ztouch-theme.css"; + + let main_wrapper = function (parent) { + let parenti0 = fastn_dom.createKernel(parent, fastn_dom.ElementKind.Column); + parenti0.setProperty(fastn_dom.PropertyKind.Width, fastn_dom.Resizing.FillContainer, inherited); + parenti0.setProperty(fastn_dom.PropertyKind.Height, fastn_dom.Resizing.FillContainer, inherited); + main(parenti0); + } + fastn_virtual.hydrate(main_wrapper); + ftd.post_init(); + })(); + + window.onload = function() { + fastn_utils.resetFullHeight(); + fastn_utils.setFullHeight(); + }; + +</script> +</html>