Skip to content
This repository has been archived by the owner on Feb 28, 2022. It is now read-only.

VDOM Util #53

Merged
merged 23 commits into from
Oct 1, 2018
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 125 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,30 @@ Following main properties exist:
- `type`: the content type of the document
- `image`: the URL of the first image in the document
- `htast`: the HTML AST
- `sections[]`: The main sections of the document, as an enhanced MDAST
- `document`: a DOM-compatible [`Document`](https://developer.mozilla.org/en-US/docs/Web/API/Document) representation of the (HTML) document ([see below](#contentdocument-in-detail))
- `sections[]`: The main sections of the document, as an enhanced MDAST ([see below](#contentsections-in-detail))
- `html`: a string of the content rendered as HTML
- `children`: an array of top-level elements of the HTML-rendered content

### `content.document` in Detail

For developers that prefer using the rendered HTML over the input Markdown AST, `content.document` provides a representation of the rendered HTML that is API-compatible to the `window.document` object you would find in a browser.

The most common way of using it is probably calling `content.document.innerHTML`, which gives the full HTML of the page, but other functions like

- `content.document.getElementsByClassName`
- `content.document.querySelector`
- `content.document.querySelectorAll`

are also available. Please note that some functions like

- `content.document.getElementsByClassName`
- `content.document.getElementByID`

are less useful because the HTML generated by the default pipeline does not inject class name or ID attributes.

The tooling for generating (Virtual) DOM nodes from Markdown AST is made available as a utility class, so that it can be used in custom `pre.js` scripts, and [described below](#generate-a-virtual-dom-with-utilsvdom).

### `content.sections` in Detail

The default pipeline extracts sections from a Markdown document, using both "thematic breaks" like `***` or `---` and embedded YAML blocks as section markers. If no sections can be found in the document, the entire `content.mdast` will be identically to `content.sections[0]`.
Expand Down Expand Up @@ -195,3 +215,107 @@ Alternatively, steps can attempt to handle the `error` object, for instance by g
The only known property in `error` is

- `message`: the error message

## Utilities

### Generate a Virtual DOM with `utils.vdom`

`VDOM` is a helper class that transforms [MDAST](https://github.com/syntax-tree/mdast) Markdown into DOM nodes using customizable matcher functions or expressions.

It can be used in scenarios where:

- you need to represent only a `section` of the document in HTML
- you have made changes to `content.mdast` and want them reflected in HTML
- you want to customize the HTML output for certain Markdown elements

#### Getting Started

Load the `VDOM` helper through:

```javascript
const VDOM = require('@adobe/hypermedia-pipeline').utils.vdom;
```

#### Simple Transformations

```javascript
content.document = new VDOM(content.mdast).getDocument();
```

This replaces `content.document` with a re-rendered representation of the Markdown AST. It can be used when changes to `content.mdast` have been made.

```javascript
content.document = new VDOM(content.sections[0].getDocument());
```

This uses only the content of the first section to render the document.

#### Matching Nodes

Nodes in the Markdown AST can be matched in two ways: either using a [select](https://www.npmjs.com/package/unist-util-select)-statement or using a predicate function.

```javascript
const vdom = new VDOM(content.mdast);
vdom.match('heading', () => '<h1>This text replaces your heading</h1>');
content.document = vdom.getDocument();
```

Every node with the type `heading` will be rendered as `<h1>This text replaces your heading</h1>`;

```javascript
const vdom = new VDOM(content.mdast);
vdom.match(function test(node) {
return node.type === 'heading';
}, () => '<h1>This text replaces your heading</h1>');
content.document = vdom.getDocument();
```

Instead of the select-statement, you can also provide a function that returns `true` or `false`. The two examples above will have the same behavior.

#### Creating DOM Nodes

The second argument to `match` is a node-generating function that should return one of the following three options:

1. an [HAST](https://github.com/syntax-tree/hast) (Hypertext Abstract Syntax Tree) node
2. a DOM [Node](https://developer.mozilla.org/en-US/docs/Web/API/Node)
3. a `String` containing HTML tags.

```javascript
vdom.match('link', (_, node) => {
return {
type: 'element',
tagName: 'a',
properties: {
href: node.url,
rel: 'nofollow'
},
children: [
{
type: 'text',
value: node.children.map(({ value }) => value)
}
]
}
}
```

Above: injecting `rel="nofollow"` using HTAST.

```javascript
const h = require('hyperscript');

vdom.match('link', (_, node) => h(
'a',
{ href: node.url, rel: 'nofollow' },
node.children.map(({ value }) => value),
);
```

Above: doing the same using [Hyperscript](https://github.com/hyperhype/hyperscript) (which creates DOM elements) is notably shorter.

```javascript
vdom.match('link', (_, node) =>
`<a href="${node.url}" rel="nofollow">$(node.children.map(({ value }) => value)).join('')</a>`;
```

Above: Plain `String`s can be constructed using String Templates in ES6 for the same result.
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

const defaults = require('./src/defaults/default.js');
const Pipeline = require('./src/pipeline.js');
const utils = require('./src/utils');

module.exports = {
Pipeline,
defaults,
utils,
};
Loading