Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Double Buffering #1442

Merged
merged 11 commits into from
Nov 9, 2023
26 changes: 0 additions & 26 deletions fastn-js/ftd.html

This file was deleted.

32 changes: 15 additions & 17 deletions fastn-js/js/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ class Node2 {
return this.#parent;
}
removeAllFaviconLinks() {
if (hydrating || rerender) {
if (doubleBuffering) {
const links = document.head.querySelectorAll('link[rel="shortcut icon"]');
links.forEach( link => {
link.parentNode.removeChild(link);
Expand All @@ -821,7 +821,7 @@ class Node2 {
}

setFavicon(url) {
if (hydrating || rerender) {
if (doubleBuffering) {
if (url instanceof fastn.recordInstanceClass) url = url.get('src');
while (true) {
if (url instanceof fastn.mutableClass) url = url.get();
Expand Down Expand Up @@ -889,7 +889,7 @@ class Node2 {
}
updatePositionForNodeById(node_id, value) {
if (!ssr) {
const target_node = document.querySelector(`[id="${node_id}"]`);
const target_node = fastnVirtual.root.querySelector(`[id="${node_id}"]`);
if (!fastn_utils.isNull(target_node))
target_node.style['position'] = value;
}
Expand All @@ -908,7 +908,7 @@ class Node2 {
}
}
updateMetaTitle(value) {
if (!ssr && (hydrating || rerender)) {
if (!ssr && doubleBuffering) {
if (!fastn_utils.isNull(value)) window.document.title = value;
}
}
Expand All @@ -917,7 +917,7 @@ class Node2 {
this.removeMetaTagByName(name);
return;
}
if (!ssr && (hydrating || rerender)) {
if (!ssr && doubleBuffering) {
const metaTag = window.document.createElement('meta');
metaTag.setAttribute('name', name);
metaTag.setAttribute('content', value);
Expand All @@ -929,15 +929,15 @@ class Node2 {
this.removeMetaTagByProperty(property);
return;
}
if (!ssr && (hydrating || rerender)) {
if (!ssr && doubleBuffering) {
const metaTag = window.document.createElement('meta');
metaTag.setAttribute('property', property);
metaTag.setAttribute('content', value);
document.head.appendChild(metaTag);
}
}
removeMetaTagByName(name) {
if (!ssr && (hydrating || rerender)) {
if (!ssr && doubleBuffering) {
const metaTags = document.getElementsByTagName('meta');
for (let i = 0; i < metaTags.length; i++) {
const metaTag = metaTags[i];
Expand All @@ -949,7 +949,7 @@ class Node2 {
}
}
removeMetaTagByProperty(property) {
if (!ssr && (hydrating || rerender)) {
if (!ssr && doubleBuffering) {
const metaTags = document.getElementsByTagName('meta');
for (let i = 0; i < metaTags.length; i++) {
const metaTag = metaTags[i];
Expand Down Expand Up @@ -978,7 +978,7 @@ class Node2 {
const obj = { property, value };

if (value === undefined) {
if (!ssr && !hydrating) {
if (!ssr) {
for (const className of this.#node.classList.values()) {
if (className.startsWith(`${propertyShort}-`)) {
this.#node.classList.remove(className);
Expand All @@ -989,7 +989,7 @@ class Node2 {
return cls;
}

if (!ssr && !hydrating) {
if (!ssr) {
if (!!className) {
if (!fastn_dom.classes[cssClass]) {
fastn_dom.classes[cssClass] = fastn_dom.classes[cssClass] || obj;
Expand Down Expand Up @@ -1328,7 +1328,7 @@ class Node2 {
}
}
attachExternalCss(css) {
if (hydrating || rerender) {
if (doubleBuffering) {
let css_tag = document.createElement('link');
css_tag.rel = 'stylesheet';
css_tag.type = 'text/css';
Expand All @@ -1342,7 +1342,7 @@ class Node2 {
}
}
attachExternalJs(js) {
if (hydrating || rerender) {
if (doubleBuffering) {
let js_tag = document.createElement('script');
js_tag.src = js;

Expand Down Expand Up @@ -2161,14 +2161,12 @@ class Node2 {
this.#rawInnerValue = staticValue;
} else if (kind === fastn_dom.PropertyKind.StringValue) {
this.#rawInnerValue = staticValue;
if (!hydrating || this.#node.innerHTML === "undefined") {
staticValue = fastn_utils.markdown_inline(fastn_utils.escapeHtmlInMarkdown(staticValue));
} else {
staticValue = this.#node.innerHTML;
}
staticValue = fastn_utils.markdown_inline(fastn_utils.escapeHtmlInMarkdown(staticValue));
staticValue = fastn_utils.process_post_markdown(this.#node, staticValue);
if(!fastn_utils.isNull(staticValue)) {
this.#node.innerHTML = staticValue;
} else {
this.#node.innerHTML = "";
}
} else {
throw ("invalid fastn_dom.PropertyKind: " + kind);
Expand Down
2 changes: 1 addition & 1 deletion fastn-js/js/ftd.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ const ftd = (function() {
},
get(key) {
key = this._get_key(key);
if(ssr && !hydrating) {
if(ssr) {
return;
}
const item = localStorage.getItem(key);
Expand Down
49 changes: 47 additions & 2 deletions fastn-js/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ let fastn_utils = {
return [node, css, attributes];
},
createStyle(cssClass, obj) {
if (rerender) {
if (doubleBuffering) {
fastn_dom.styleClasses = `${fastn_dom.styleClasses}${getClassAsString(cssClass, obj)}\n`;
} else {
let styles = document.getElementById('styles');
Expand Down Expand Up @@ -336,7 +336,7 @@ let fastn_utils = {
},
createNodeHelper(node, classes, attributes) {
let tagName = node;
let element = fastn_virtual.document.createElement(node);
let element = fastnVirtual.document.createElement(node);
for (let key in attributes) {
element.setAttribute(key, attributes[key])
}
Expand Down Expand Up @@ -525,6 +525,24 @@ let fastn_utils = {
}
return args;
},

/**
* Replaces the children of `document.body` with the children from
* newChildrenWrapper and updates the styles based on the
* `fastn_dom.styleClasses`.
*
* @param {HTMLElement} newChildrenWrapper - The wrapper element
* containing the new children.
*/
replaceBodyStyleAndChildren(newChildrenWrapper) {
// Update styles based on `fastn_dom.styleClasses`
let styles = document.getElementById("styles");
styles.innerHTML = fastn_dom.styleClasses;

// Replace the children of document.body with the children from
// newChildrenWrapper
fastn_utils.private.replaceChildren(document.body, newChildrenWrapper);
},
}


Expand Down Expand Up @@ -640,6 +658,33 @@ fastn_utils.private = {
}
return text;
},

/**
* Replaces the children of a parent element with the children from a
* new children wrapper.
*
* @param {HTMLElement} parent - The parent element whose children will
* be replaced.
* @param {HTMLElement} newChildrenWrapper - The wrapper element
* containing the new children.
* @returns {void}
*/
replaceChildren(parent, newChildrenWrapper) {
// Remove existing children of the parent
var children = parent.children;
// Loop through the direct children and remove those with tagName 'div'
for (var i = children.length - 1; i >= 0; i--) {
var child = children[i];
if (child.tagName === 'DIV') {
parent.removeChild(child);
}
}

// Cut and append the children from newChildrenWrapper to the parent
while (newChildrenWrapper.firstChild) {
parent.appendChild(newChildrenWrapper.firstChild);
}
}
}


Expand Down
66 changes: 17 additions & 49 deletions fastn-js/js/virtual.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
let fastn_virtual = {}
let fastnVirtual = {}

let id_counter = 0;
let hydrating = false;
let ssr = false;
let rerender = false;
let doubleBuffering = false;

class ClassList {
#classes = [];
Expand Down Expand Up @@ -124,28 +123,14 @@ class Document2 {
if (fastn_utils.isWrapperNode(tagName)) {
return window.document.createComment(fastn_dom.commentMessage);
}
if (hydrating) {
let node = this.getElementByDataID(id_counter);
if (fastn_utils.isCommentNode(tagName)) {
let comment= window.document.createComment(fastn_dom.commentMessage);
node.parentNode.replaceChild(comment, node);
return comment;
}
return node;
} else {
if (fastn_utils.isCommentNode(tagName)) {
return window.document.createComment(fastn_dom.commentMessage);
}
return window.document.createElement(tagName);
if (fastn_utils.isCommentNode(tagName)) {
return window.document.createComment(fastn_dom.commentMessage);
}
}

getElementByDataID(id) {
return window.document.querySelector(`[data-id=\"${id}\"]`);
return window.document.createElement(tagName);
}
}

fastn_virtual.document = new Document2();
fastnVirtual.document = new Document2();

function addClosureToBreakpointWidth() {
let closure = fastn.closureWithoutExecute(function() {
Expand All @@ -161,39 +146,22 @@ function addClosureToBreakpointWidth() {
ftd.breakpoint_width.addClosure(closure);
}

fastn_virtual.hydrate = function(main) {
fastnVirtual.doubleBuffer = function(main) {
addClosureToBreakpointWidth();
let parent = document.createElement("div");
let current_device = ftd.get_device();
let found_device = ftd.device.get();
if (current_device !== found_device) {
rerender = true
ftd.device = fastn.mutable(current_device);
let styles = document.getElementById("styles");
styles.innerText = "";
var children = document.body.children;
// Loop through the direct children and remove those with tagName 'div'
for (var i = children.length - 1; i >= 0; i--) {
var child = children[i];
if (child.tagName === 'DIV') {
document.body.removeChild(child);
}
}

main(document.body);
rerender = false;
styles.innerHTML = fastn_dom.styleClasses;
return;
}
hydrating = true;
let body = fastn_virtual.document.createElement("body");
main(body);
id_counter = 0;
hydrating = false;
ftd.device = fastn.mutable(current_device);
doubleBuffering = true;
fastnVirtual.root = parent;
main(parent);
fastn_utils.replaceBodyStyleAndChildren(parent)
doubleBuffering = false;
fastnVirtual.root = document.body;
}

fastn_virtual.ssr = function(main) {
fastnVirtual.ssr = function(main) {
ssr = true;
let body = fastn_virtual.document.createElement("body");
let body = fastnVirtual.document.createElement("body");
main(body)
ssr = false;
id_counter = 0;
Expand Down
2 changes: 1 addition & 1 deletion fastn-js/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fn js() -> &'static str {
i.done();
}

fastn_virtual.ssr(main)
fastnVirtual.ssr(main)
"#
}

Expand Down
4 changes: 2 additions & 2 deletions fastn-js/src/ssr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn ssr(ast: &[fastn_js::Ast]) -> String {
parenti0.setProperty(fastn_dom.PropertyKind.Height, fastn_dom.Resizing.FillContainer, inherited);
main(parenti0);
}};
fastn_virtual.ssr(main_wrapper);", fastn_js::to_js(ast,
fastnVirtual.ssr(main_wrapper);", fastn_js::to_js(ast,
"foo"));
ssr_str(&js)
}
Expand All @@ -44,7 +44,7 @@ pub fn ssr_with_js_string(package_name: &str, js: &str) -> String {
parenti0.setProperty(fastn_dom.PropertyKind.Height, fastn_dom.Resizing.FillContainer, inherited);
main(parenti0);
}};
fastn_virtual.ssr(main_wrapper);", package_name, js);
fastnVirtual.ssr(main_wrapper);", package_name, js);

ssr_str(&js)
}
4 changes: 2 additions & 2 deletions fastn-js/tests/01-basic.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion fastn-js/tests/02-basic-event.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions fastn-js/tests/03-event-1.html

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading