site-tree

A View engine

Usage no npm install needed!

<script type="module">
  import siteTree from 'https://cdn.skypack.dev/site-tree';
</script>

README

site-tree

A DOM based view engine

Allows to configure a website view tree, which allows automated switching between different pages (tree nodes)

Basic example:

Let's say we have following HTML files:

head.html

<link rel="icon" href="/favicon.png" />
<link rel="stylesheet" href="/style.css" />

body.html

<header>
  <nav><ul>
    <li><a href="/">Main page</a></li>
  </ul></nav>
</header>
<main>
  <!-- To be filled by extension views -->
</main>
<footer><p>© footer example</p></footer>

homepage.html

<h1>Homepage of SiteTree demo</h1>
<p>Homepage content ...</p>

subpage.html

<h1>Subpage of SiteTree demo</h1>
<p>Subpage content ...</p>

SiteTree configuration for them may look as:

var SiteTree = require('site-tree');

// Initialize SiteTree instance:
var siteTree = new SiteTree(document);

// Configure view nodes:
// Root node
var baseView = {
  title: "SiteTree test page",
    head: function () {
        return htmlToDOM('./head.html');
    },
    body: function () {
        return htmlToDOM('./body.html');
    },
};

// Homepage node
var homepageView = {
    _parent: baseView,
  main: function () {
    return htmlToDOM('./homepage.html');
  }
};

// Subpage node
var subpageView = {
    _parent: baseView,
  main: function () {
    return htmlToDOM('./subpage.html');
  }
};

// Switch between views in document:
// Present homepage
siteTree.load(homepageView);

// Switch to subpage
siteTree.load(subpageView);

// Switch back to homepage
siteTree.load(homepageView)

SiteTree expects view functions to return instances of DocumentFragment, but its agnostic in how fragments are resolved, it's why above example doesn't expose logic for htmlToDOM function.

There are ready solutions that adapt some template formats:

Above configuration example exposes very basic case, and does not unleash all possibilities of SiteTree, follow below documentation, for all the details

Installation

$ npm install site-tree

API

new SiteTree(document)

var SiteTree = require('site-tree');

var siteTree = new SiteTree();

On initialization HTMLDocument istance needs to be provided.

There's no need to provide any view nodes at this step, instead they should be added to tree on demand (via siteTree.load method) at point when we want to show them in document.

SiteTree constructor properties:

SiteTree.ensureView(conf)

Validates provided view configuration. Used also internally on view load. Can be overriden by extensions

SiteTree.ensureTemplate(template)

Validates provided template. Used also internally on view load. Can be overriden by extensions

Properties of siteTree instance:

siteTree.current

Currently loaded node.

siteTree.load(view[, context])

Loads provided view configuration into document. context is optional (if not provided, plain object is created internally) it's a context in which view functions will be called. It should be used to transport necessary data to the views.

If given view was already loaded in a past (taking also into account eventual match setting), then previously generated DOM is reused.

siteTree._resolveTemplate(templates, context)

Resolves provided template with provided context. Should not be used externally. Listed in documentation, only to indicate that this method should be overriden by extension when some specific template format is to be used.

siteTree._resetElement(element)

Invokes reset operation on elements which were just exposed in a document due to view change. Should not be used externally. Listed in documentation, only to indicate that this method may be overriden for custom needs.

Configuration of view nodes

View node is a typical key/value hash map, which says where in a tree node is placed and instructs which and how elements should be altered when view is loaded

View map keys

All keys that start with _ are treated as special instructions:

  • _parent - A parent view configuration. Mandatory if given view is not a root one.
  • _match - Matching instruction: Typically view is resolved once, and generated DOM is reused. However there are cases when we want to generate different view per each entity, e.g. imagine page which lists properties of some object, for each object we may want to use same view configuration, but we don't want to reuse DOM generated for object A, when we want to show data for object B.
    With match we indicate which property of a context (passed to siteTree.load) will identify entity for which view is generated. e.g. if match is set to 'name', then two different views will be generated for following contexts { name: 'Mark' } and { name: 'Paul' }. However previously generated view will be reused if again we provide context as { name: 'Mark' }. Matching value in a context doesn't have to be a string, it can be any JavaScript value, it's uniqueness is compared with SameValueZero algorithm

Any other instruction key in core implementation will be ignored (but can be used by extensions).

All other keys are expected to be valid ident values which address specific DOM elements.

Following core elements can be addressed by name:

  • html (configuration may contain only attributes setting)
  • head
  • title
  • body
  • main

Any other HTML elements need to be addressed by id.

Aside of html, head, title and body elements, it is expected that referenced elements exist in a document tree when parent of given node view is loaded, otherwise load of a view will crash with exception.

View map values

Each value for a key that addresses element is an update instruction

Configuration value can be directly a function that returns DocumentFragment instance, in such case it's treated as a replace content instruction, then on a view load, content of given element is replaced with one returned by function.

If it's not a function, then it's assumed it's object configuration which can contain following instructions:

  • class - Map of class changes to element, e.g. { visible: true, hidden: false } instructs that visible class should be added and hidden removed
  • attributes - Map of attribute changes to element, e.g. { 'data-foo': 'lorem', 'data-bar': null } instructs to set value of data-foo to 'lorem', and to remove data-bar attribute
  • content - Function that generates a new content (DocumentFragment) for the element. Should not be used together with prepend or append.
  • prepend - Function that generates an extra content (DocumentFragment) for the element, which will be prepended before element's first child. Should not be used together with content
  • append - Function that generates an extra content (DocumentFragment) for the element, which will be appended after element's last child. Should not be used together with content

Tests Build Status

$ npm test