Security News
PyPI Introduces Digital Attestations to Strengthen Python Package Security
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Create views as components using DOM. Run the same code on the browser and on the server.
Create views as components using DOM. Run the same code on the browser and on the server.
This is a library that helps you create your html documents using plain javascript, instead of using a template language. No need to learn yet another language with new syntax. Using domv you can easily break up your page design into smaller components and reuse them in other projects.
In most templating languages reusability is hard because once the html is generated, you can no longer modify it easily. In domv, each component you create or use is a proper OOP class which can be subclassed or modified by calling methods or using setters. After you have set up all your components you can serialize them to html markup.
It should also help reduce coupling in your application. This is because the Components are more clearly separated from each other, there is less dependency between them.
Security is another benefit, user input is not parsed as HTML unless you explicitly want it to be.
This library has unit tests with 100% branch coverage. You can also run this test suite in the various browsers.
If you would like to use domv on your server using node.js or io.js you need to install domv for your project first:
npm install domv inherits --save
You will then need to obtain a DOM Document
, domv has a convenience function to create this for you using jsdom:
var domv = require('domv');
var document = domv.createHtmlDomDocument();
If you would like to use domv in a web browser, you can use one of two methods.
If you are already using browserify for your project, you can simply require domv:
var domv = require('domv');
Or you can generate an UMD bundle:
npm install domv
cd node_modules/domv
npm run bundle
This will generate a javascript file for you in build/domv.js
, here's an example on using it:
<!DOCTYPE html>
<html>
<head>
<script src="domv.js"></script>
<script>
(function(document, domv)
{
var image = domv.create(document, 'img', {src: 'foo.jpg'});
// ...
} (window.document, window.domv));
</script>
</head>
<body>
</body>
</html>
Now that you have obtained a DOM Document
and have access to the domv module, you can create new Components. When using the domv API you do not have to worry about which browser or server your code is running in.
The most important part of domv is the Component
class. This example shows how you can create one:
var domv = require('domv');
var image = domv.create(document, 'img', {src: 'foo.jpg', width: 200, height: 100});
console.log(image.stringifyAsHtml());
// <img src="foo.jpg" height="100" width="200">
Or you can use a convenient shorthand:
var domv = require('domv');
var div = domv.shorthand(document, 'div');
var img = domv.shorthand(document, 'img');
var component = div('columns',
div('left', 'This is the left column!'),
div('right',
'This is the right column...',
img({src: 'foo.jpg', width: 200, height: 100})
)
);
console.log(component.stringifyAsHtml());
// <div class="columns"><div class="left">This is the left column!</div>
// <div class="right">This is the right column...
// <img src="foo.jpg" height="100" width="200"></div></div>
Each Component
actually wraps a DOM Node
. This is useful to overcome differences between browsers and jsdom, however the real strength is that it lets you create subclasses of Component
(more on that later). Here is an example on wrapping:
var body = domv.wrap(document.body);
console.log(body !== document.body); // true
console.log(body.outerNode === document.body); // true
Note that domv.wrap
will always create a new Component
(this is by design):
var body = domv.wrap(document.body);
var body2 = domv.wrap(document.body);
console.log(body !== body2); // true
console.log(body.outerNode === body2.outerNode); // true
Subclassing Component
is what makes domv useful. A Component
wraps a DOM Node
and by doing so it gives you a stable API to modify the DOM with. When browsers introduce new features, your old Components will still use the same stable API without any clashes in attributes or method names. A lot of DOM methods are proxied with some extra flavoring (such asappendChild
, childNodes
, etc).
Here is an example:
// AuthorInfo.js
'use strict';
var domv = require('domv');
// the constructor for AuthorInfo
function AuthorInfo(node, author)
{
// call the constructor of our super class
domv.Component.call(this, node, 'div');
if (this.isCreationConstructor(node))
{
var img = this.shorthand('img');
var h2 = this.shorthand('h2');
var a = this.shorthand('a');
var p = this.shorthand('p');
var text = this.textShorthand();
this.cls('AuthorInfo');
this.attr('data-id', author.id);
this.appendChild(
this.avatar = img('avatar', { src: author.avatarUrl }),
this.name = h2('name',
this.nameLink = a(
{ href: '/author/' + encodeURIComponent(author.id) },
text(author.displayName)
)
),
this.introduction = p('introduction',
'about me: ',
text(author.introduction)
)
);
}
else // wrapping constructor
{
// assertHasClass and assertSelector are used to throw an
// Error in case invalid content is given to this constructor
this.assertHasClass('AuthorInfo');
this.avatar = this.assertSelector('> .avatar');
this.name = this.assertSelector('> .name');
this.nameLink = this.name.assertSelector('> a');
this.introduction = this.assertSelector('> .introduction');
}
// Add a DOM event listener
this.on('click', this._onclick);
}
module.exports = AuthorInfo;
// "inherits" module provides prototype chaining
require('inherits')(AuthorInfo, domv.Component);
Object.defineProperty(AuthorInfo.prototype, 'id', {
get: function()
{
return this.getAttr('data-id');
}
});
Object.defineProperty(AuthorInfo.prototype, 'displayName', {
get: function()
{
return this.nameLink.textContent;
},
set: function(val)
{
this.nameLink.textContent = val;
}
});
AuthorInfo.prototype._onclick = function(e)
{
this.toggleClass('highlighted');
};
(If you are using IntelliJ or WebStorm, there is a File Template you can import)
The constructor of a Component
subclass must always accept a node
argument as its first argument (a DOM Node
). If this argument is a Document
the Component must create new DOM elements and attributes.
As a rule of thumb, the outer element of a Component always has a class attribute that contains the name of the Component (beginning with a capital letter). Any other class name begins with a lowercase letter. This is import because it lets you easily debug where generated HTML came from, and it is also important when making sure your CSS rules only match your own Component.
var domv = require('domv');
var AuthorInfo = require('./AuthorInfo');
var body = domv.wrap(document.body);
var author = {
id: 500,
avatarUrl: 'someone.jpg',
displayName: 'Someone',
introduction: 'Hi! I am someone!!!'
};
var authorComponent = new AuthorInfo(document, author);
body.appendChild(authorComponent);
This results in the following HTML:
<div class="AuthorInfo" data-id="500">
<img src="someone.jpg" class="avatar">
<h2 class="name">
<a href="/author/500">Someone</a>
</h2>
<p class="introduction">about me: Hi! I am someone!!!</p>
</div>
If the node
argument is a different kind of Node
, usually an Element
, the Component must wrap existing content:
var domv = require('domv');
var AuthorInfo = require('./AuthorInfo');
var body = domv.wrap(document.body);
var element = body.selector('> .AuthorInfo');
var authorComponent = new AuthorInfo(element);
authorComponent.displayName = 'I just renamed myself!';
The wrapping constructor is especially useful if you would like to modify the DOM in the browser after having received HTML from the server.
Each Component
has an "outer" node and an "inner" node. You can access these nodes by using the outerNode
and innerNode
attributes. For most components innerNode
and outerNode
refer to the same Node
. But you can set them to something different anytime (usually in the constructor).
The outerNode
is used whenever you make a change to DOM attributes. Also, if a child Component is added to a parent Component, the outerNode
of the child is used.
The innerNode
is used to add any children and is also used for getters such as childNodes
, firstChild
, etc.
var domv = require('domv');
var document = domv.wrap(domv.createHtmlDomDocument());
var foo = document.create('div', 'outer');
var fooInner = document.create('div', 'inner');
foo.appendChild(fooInner);
foo.innerNode = fooInner;
foo.attr('data-example', 'This is set on the outer node!');
var bar = document.create('span', '', 'I am a span');
foo.appendChild(bar);
console.log(foo.stringifyAsHtml());
Result:
<div class="outer" data-example="This is set on the outer node!">
<div class="inner">
<span>I am a span</span>
</div>
</div>
HtmlDocument
is a Component
subclass which lets you create or wrap a html document. This includes the html, head, title and body elements, but it also provides a number of convenient methods to easily add style, script elements and JSON data. Unlike normal Components the node
argument in HtmlDocument is optional, if not given, a new Document
is constructed for you.
var domv = require('domv');
var author = {
id: 500,
avatarUrl: 'someone.jpg',
displayName: 'Someone',
introduction: 'Hi! I am someone!!!'
};
var html = new domv.HtmlDocument();
html.title = 'This is my page title';
html.baseURI = 'http://example.com/foo';
html.appendChild(html.create('p', 'myParagraph', 'This paragraph is added to the body'));
html.appendChild(new AuthorInfo(html.document, author));
html.addCSS('/my-bundle.css');
html.addJS('/my-bundle.js');
html.addJSONData('user-session', {userId: 1, name: 'root'});
console.log(html.stringifyAsHtml());
This gives you:
<!DOCTYPE html>
<html>
<head>
<base href="http://example.com/foo">
<title>This is my page title</title>
<link href="/my-bundle.css" rel="stylesheet" type="text/css">
<script async="async" src="/my-bundle.js" type="text/javascript"></script>
<script data-identifier="user-session" type="application/json">
{"userId":1,"name":"root"}
</script>
</head>
<body>
<p class="myParagraph">This paragraph is added to the body</p>
<div data-id="500" class="AuthorInfo">
<img src="someone.jpg" class="avatar">
<h2 class="name"><a href="/author/500">Someone</a></h2>
<p class="introduction">about me: Hi! I am someone!!!</p>
</div>
</body>
</html>
And this is an example with wrapping:
var domv = require('domv');
var html = new domv.HtmlDocument(document.documentElement);
html.title = 'A new title!';
var session = html.getJSONData('user-session');
console.log('My user id is', session.userId, 'And my name is', session.name);
var authorInfo = html.assertSelector('> .AuthorInfo', AuthorInfo);
console.log('display name of the author you are viewing:', authorInfo.displayName);
Because this is all just plain javascript, it is easy to publish your Component
as a node module on npm. This works especially well when you use browserify.
Most Components also need some CSS to function properly. For this purpose stylerefs is a good solution. It lets you list the CSS or LESS files your Component needs in the source code using a require call:
'use strict';
var domv = require('domv');
require('static-reference')('./AuthorInfo.less', 'optional', 'filter', 'keywords');
// the constructor for AuthorInfo
function AuthorInfo(node, author)
{
// call the constructor of our super class
domv.Component.call(this, node, 'div');
if (this.isCreationConstructor(node))
{
... SNIP ...
This works a lot like browserify. You simply point the stylerefs
command line tool to your code and it will recursively analyze all the require()
calls in your app in order to find the CSS / LESS files that you need. You can use the output of this tool to generate a single CSS bundle file. (instead of the command line tool you can also use grunt. Look at the stylerefs documentation for more details.
You can find a description of the API in the file api.md
FAQs
Create views as components using DOM. Run the same code on the browser and on the server.
The npm package domv receives a total of 8 weekly downloads. As such, domv popularity was classified as not popular.
We found that domv demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PyPI now supports digital attestations, enhancing security and trust by allowing package maintainers to verify the authenticity of Python packages.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.