Skip to content

Commit

Permalink
Merge pull request #88 from ivanceras/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ivanceras authored Apr 1, 2024
2 parents c979dd7 + 06b335a commit 5dbf299
Show file tree
Hide file tree
Showing 71 changed files with 3,283 additions and 1,943 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ test-fixtures = ["sauron-core/test-fixtures"] #include the test-fixtures for upd
with-node-macro = ["sauron-macro"]
custom_element = ["sauron-macro","sauron-core/custom_element"]
html-parser = ["sauron-html-parser"]
use-template = ["sauron-core/use-template"]
use-skipdiff = ["sauron-core/use-skipdiff"]


[dev-dependencies]
Expand All @@ -48,7 +50,7 @@ wasm-bindgen-test = "0.3"
wasm-bindgen-futures = "0.4.31"
regex = "1"
sauron-html-parser = { path = "crates/html-parser" }
sauron = { path = ".", features = ["test-fixtures"] }
sauron = { path = ".", features = ["test-fixtures", "html-parser", "log-patches"] }

[dev-dependencies.web-sys]
version = "0.3"
Expand Down
32 changes: 31 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@
}
```
- [ ] Make the compilation error in `jss!`, `style!`, more informative
- [ ] Optimize handling of style by diffing each style properties
- Update only specific stype instead of setting the whole style attributes


## Internal
Expand Down Expand Up @@ -225,6 +227,7 @@
add these events:
- `on_interval(|i32|{})` for attaching interval in the Window
Http can be done with task
- [ ] Make Http functions return a Task
- [ ] Make `Sub` as counterpart to `Cmd`
- We can use `Sub` in the `Component`
```rust
Expand Down Expand Up @@ -254,14 +257,37 @@
- This is anchored as next to the last sibling
- This can not just be backtrack to the parent, as it defeats the purpose of
doing as little diff as possible.
- [ ] Make a TemplateView struct and a variant of Leat
- [X] Make a TemplateView struct and a variant of Leaf
```rust
struct TemplatedView<MSG>{
template: Box<dyn Fn() -> Node<MSG>>,
skip_diff: Box<dyn Fn() -> SkipDiff>,
view: Node<MSG> ,
}
```
- [X] remove `SafeHtml` variant in leaf, instead provide a safe_html which is parsed and converted into node
- using safe html alters the dom tree
- [X] add `symbol_html` for html entities such as `&nbsp;` `&gt`, `&lt` etc.
- this should be safe to be inserted
- [X] remove `innerHTML` func in AttributeValue as it could alter the DOM node tree
- [X] Keep track of which attributes to be skipped in `SkipDiff{shall:false}`
```rust
enum SkipStrat{
SkipAll,
SkippIndex(Vec<usize>),
}
```
- [X] Maybe disable the template usage for now
- [ ] Make `Cmd` to be used internally as it needs reference to the `Program<APP>`
- [ ] Use `Task` for returning from `Application` init and `update`.
- The `Recurring Task` is actually just a Sub in elm
- Issue with recurring task, how to store the closures which has different multiple types for the in arguments
- Store the closures with `Closure<dyn Fn(IN)->MSG>`
- Then task becomes `Task<IN,MSG>`
- The `SingleTask` is a Cmd in sauron
- Rename `Cmd` to `Command` alternative: `Action`, `Operation`, `Instruction`, `Effects`, `Dispatch`
- This is effects in elm
- Sauron just consilidate them into one enum struct for simplicity

## Features
- [X] Storage service (May not be needed since the user can directly use web-sys)
Expand Down Expand Up @@ -296,6 +322,10 @@
- Right now, it is triggered when the virtual Node is created into a real Node.
- [X] Maybe rename `#[web_component]` macro to `#[custom_element]`
- Also `WebComponent` to `CustomElementWrapper`
- [ ] Implement the `StatefulComponent`
- [ ] attributes and attribute value (key)
- [ ] removing children and setting attributes
- [ ] Make the fancy-ui example work


## Performance
Expand Down
10 changes: 6 additions & 4 deletions crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ edition = "2021"
maintenance = { status = "actively-developed" }

[features]
default = ["with-dom", "use-cached-elements","ensure-check", "ensure-attr-set"]
default = ["with-dom", "ensure-check", "ensure-attr-set"]
with-dom = ["wasm-bindgen", "js-sys", "web-sys", "wasm-bindgen-futures"] # for client-side usage
with-lookup = [] #enumerates html tags and attributes
with-measure = [] # log traces for measurements in various parts of the system where performance matters.
Expand All @@ -23,11 +23,12 @@ log-patches = [] # use in combination to with-debug to log the debug patches
with-ric = [] # use of request_idle_callback in javascript
with-raf = [] # use of request_animation_frame in javascript
with-interning = [] # use caching of strings when crossing rust to js, for faster transfer
use-cached-elements = [] # use caching of common elements
custom_element = [] # use of register_custom_element, adding this will add the js snippets
ensure-check = [] #do checking if pending msgs, patches, cmds, has been processed accordingly to ensure proper order and synchronized dom state
ensure-attr-set = [] #ensure attributes is reflected into the element by explicitly calling the element corresponding methods aside fro just setting its attribute by name
test-fixtures = [] #include the test-fixtures for updating the program with the supplied vdom
use-template = [] #use the templated view and building before hand
use-skipdiff = [] #use skipdiff to selectively skip attributes that can not change

[dependencies]
js-sys = { version = "0.3", optional = true }
Expand Down Expand Up @@ -59,6 +60,7 @@ optional = true
features = [
"AnimationEvent",
"Attr",
"CharacterData",
"Comment",
"ClipboardEvent",
"console",
Expand Down Expand Up @@ -108,13 +110,13 @@ features = [
"NamedNodeMap",
"Node",
"NodeList",
"Performance",
"PopStateEvent",
"Text",
"TransitionEvent",
"Touch",
"TouchEvent",
"TouchList",
"CharacterData",
"Performance",
"Window",
"History",
"Response",
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/dom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ mod task;
use cfg_if::cfg_if;

cfg_if! {if #[cfg(feature = "with-dom")] {
pub use application::{Application, Measurements, SkipDiff, skip_if, skip_diff};
pub use application::{Application, Measurements, SkipDiff, skip_if, skip_diff, SkipPath};
#[cfg(feature = "custom_element")]
pub use component::{register_web_component, WebComponent, WebComponentWrapper};
pub use component::{component, stateful_component, StatefulComponent, StatefulModel, StatelessModel};
Expand Down Expand Up @@ -50,7 +50,7 @@ cfg_if! {if #[cfg(feature = "with-dom")] {


/// Map the Event to DomEvent, which are browser events
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone)]
pub enum Event {
/// native dome events web_sys::Events
WebEvent(web_sys::Event),
Expand Down
13 changes: 1 addition & 12 deletions crates/core/src/dom/application.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::dom::Cmd;
use crate::vdom::Node;
pub use skip_diff::{skip_if, SkipDiff};
pub use skip_diff::{skip_if, SkipDiff, SkipPath};

///
pub mod skip_diff;
Expand All @@ -26,17 +26,6 @@ pub trait Application: Sized + 'static {
/// Returns a node on how the component is presented.
fn view(&self) -> Node<Self::MSG>;

/// optional logical code when to skip diffing some particular node
/// by comparing field values of app and its old values
fn skip_diff(&self) -> Option<SkipDiff> {
None
}

///
fn template(&self) -> Option<Node<Self::MSG>> {
None
}

/// The css style for the application, will be mounted automatically by the program
fn stylesheet() -> Vec<String> {
vec![]
Expand Down
100 changes: 64 additions & 36 deletions crates/core/src/dom/application/skip_diff.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,55 @@
use crate::vdom::TreePath;

///
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Marker {
/// anything else in the valid block
Block,
/// specifies how attributes will be skipped
#[derive(Debug, PartialEq, Clone)]
pub enum SkipAttrs {
/// all attributes are skipped
All,
/// skip only the listed indices
Indices(Vec<usize>),
}

impl SkipAttrs {
/// dont skip anything
pub fn none() -> Self {
Self::Indices(vec![])
}
}

/// if the expression evaluates to true,
/// diffing at this node will be skipped entirely
#[derive(Debug, PartialEq, Clone)]
pub struct SkipDiff {
/// shall skip or not
pub shall: bool,
/// marker for template blocks
pub marker: Option<Marker>,
pub skip_attrs: SkipAttrs,
/// children skip diff
pub children: Vec<SkipDiff>,
}

impl SkipDiff {
/// new
pub fn new(shall: bool, children: impl IntoIterator<Item = Self>) -> Self {
Self {
shall,
marker: None,
children: children.into_iter().collect(),
}
}

/// the skip diff is a block
pub fn block() -> Self {
Self {
shall: false,
marker: Some(Marker::Block),
skip_attrs: SkipAttrs::none(),
children: vec![],
}
}


/// return SkipDiff in this path location
pub fn in_path(&self, path: &TreePath) -> Option<&Self> {
let mut path = path.clone();
if path.is_empty(){
if path.is_empty() {
Some(&self)
}else{
} else {
let idx = path.remove_first();
if let Some(child) = self.children.get(idx){
if let Some(child) = self.children.get(idx) {
child.in_path(&path)
}else{
} else {
None
}
}
}


/// get the skip diff at this child index
pub fn traverse(&self, idx: usize) -> Option<&Self> {
self.children.get(idx)
Expand All @@ -63,31 +58,28 @@ impl SkipDiff {
/// check if shall skip diffing attributes at this path
/// if the path does not coincide in this skip diff, then by default it is skipped
pub fn shall_skip_attributes(&self) -> bool {
self.shall
self.skip_attrs == SkipAttrs::All
}


/// return true if this skip diff and its children can be skipped
pub fn is_skippable_recursive(&self) -> bool {
self.shall && self.children.iter().all(Self::is_skippable_recursive)
self.shall_skip_attributes() && self.children.iter().all(Self::is_skippable_recursive)
}

///
///
pub fn shall_skip_node(&self) -> bool {
self.shall && self.children.is_empty()
self.shall_skip_attributes() && self.children.is_empty()
}

/// collapse into 1 skip_if if all the children is skippable
pub fn collapse_children(self) -> Self {
let Self {
shall,
skip_attrs,
children,
marker,
} = self;
let can_skip_children = children.iter().all(Self::is_skippable_recursive);
Self {
shall,
marker,
skip_attrs,
children: if can_skip_children {
vec![]
} else {
Expand All @@ -100,10 +92,46 @@ impl SkipDiff {
/// skip diffing the node is the val is true
pub fn skip_if(shall: bool, children: impl IntoIterator<Item = SkipDiff>) -> SkipDiff {
SkipDiff {
shall,
marker: None,
skip_attrs: if shall {
SkipAttrs::All
} else {
SkipAttrs::none()
},
children: children.into_iter().collect(),
}
}

/// combination of TreePath and SkipDiff
#[derive(Debug)]
pub struct SkipPath {
pub(crate) path: TreePath,
pub(crate) skip_diff: Option<SkipDiff>,
}

impl SkipPath {
pub(crate) fn new(path: TreePath, skip_diff: SkipDiff) -> Self {
Self {
path,
skip_diff: Some(skip_diff),
}
}

pub(crate) fn traverse(&self, idx: usize) -> Self {
Self {
path: self.path.traverse(idx),
skip_diff: if let Some(skip_diff) = self.skip_diff.as_ref() {
skip_diff.traverse(idx).cloned()
} else {
None
},
}
}

pub(crate) fn backtrack(&self) -> Self {
Self {
path: self.path.backtrack(),
//TODO: here the skip_diff can not back track as we lose that info already
skip_diff: None,
}
}
}
Loading

0 comments on commit 5dbf299

Please sign in to comment.