citojs

by joelrich

joelrich / citojs
416 Stars 26 Forks Last release: Not found Mozilla Public License 2.0 69 Commits 3 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

The development of this library has stopped because of personal reasons. Please only use it for uncritical experiments. If you are interested to take ownership of it, you can send me an email to [email protected]

cito.js

cito.js is a JavaScript framework for building fast, scalable and modularized web applications. The core consists of a virtual DOM library inspired by React/Mithril. On top of that, it will provide a component framework which will make it easy to build well-encapsulated components.

Motivation

You might be wondering why I am trying to build another fancy web framework. Although there has been a lot of change in this area recently, the situation is still not satisfying: Some frameworks look very developer-friendly at first glance, but do not scale well. Others perform and scale rather well, but for example require mingling templates with JavaScript code.

It seems to me that all of the concepts needed to build the next great web framework are already out there, but have just not been combined correctly. The challenge is to choose and combine existing concepts without having to forgo any of their benefits - and that is what this project is all about!

Priorities

Performance: At the time of writing,

cito.vdom
is already one of the fastest virtual DOM library according to the vdom-benchmark - and this will not change!

Scalability: Performance without scalability is delusive. This is why there are several features in the pipeline, which will guarantee great performance even with tens of thousands of DOM nodes.

Developer-friendliness: While the

cito.vdom
API is kept simple, it still requires some extra work compared to traditional templates. This is unnecessary and this is where the (not yet revealed) component framework will step in.

Encapsulation: The component framework will encourage encapsulating all your components which makes your project easier to comprehend, better testable and more scalable.

Compatibility: IE8 is supported and as long as there is no large disadvantage, I will make sure that even in IE6 all tests pass.

Documentation

Please note that everything in this documentation is subject to change until the first version is released.

Example Application

Let's start with a simple example application which has a button and a list and whenever you click the button, it doubles the list items.

First, we initialize an array with one list item node:

var items = [
    {tag: 'li', children: 'text'}
];

Then we define a root function which returns a div container with a button and a list with the previously defined items.

function root() {
    return {
        tag: 'div', children: [
            {tag: 'button', children: 'double'},
            {tag: 'ul', children: items}
        ]
    };
}

In order to render this root function, we can either use the

cito.vdom.append
or
cito.vdom.create
function. We choose the

append
function which does not only create the DOM nodes, but also immediately appends them to a parent node:
var rootNode = cito.vdom.append(document.body, root);

Next, we want the list to double when you click the button. For that, we have to add a

click
event handler which modifies the
items
variable and updates the DOM:
function doubleList() {
    items = items.concat(items);
    cito.vdom.update(rootNode, root);
}

function root() { return { tag: 'div', children: [ {tag: 'button', children: 'double', events: {click: doubleList}, {tag: 'ul', children: items} ] }; }

Last but not least, we move the button into its own button function and add a tooltip. Here the complete source code:

var items = [
    {tag: 'li', children: 'text'}
];

function doubleList() { items = items.concat(items); cito.vdom.update(rootNode, root); }

function button() { return { tag: 'button', attrs: {title: 'double the list'}, events: {click: doubleList}, children: 'double' } }

function root() { return { tag: 'div', children: [ button, {tag: 'ul', children: items} ] }; }

var rootNode = cito.vdom.append(document.body, root);

cito.vdom API

The

cito.vdom
API provides all necessary functions to create, update and remove virtual DOM nodes to/from the real DOM.

cito.vdom.create(node) and cito.vdom.append(domParent, node): Creates a DOM node for the given virtual node. The virtual node can be of the node types, a callback function or a promise. In case of

append
the DOM node is appended at the end of the given DOM parent element. The created DOM node can be accessed through
.dom
on the returned normalized node.

update(oldNode, node): Updates the DOM of the previously created

oldNode
to the state of the given
node
. The rules which are described above for create/append apply here for the new
node
as well.

updateChildren(element, children): Updates the DOM child nodes of

element
to the state of of the given
node
. The
children
argument can either be a node or an array of nodes.

remove(node): Removes a previously created node from the DOM.

Nodes

cito.js supports five different virtual node types which are eventually all translated to one, none or multiple regular DOM nodes.

Element Node

The element node is the most basic node type. Examples:

// Empty element with attributes
{tag: 'img', attrs: {src: 'http://...', alt: 'Image ...'}}

// Element with one child {tag: 'ul', children: [{tag: 'li', ...}]} // or without array {tag: 'ul', children: {tag: 'li', ...}}

// Element with multiple children {tag: 'ul', children: [ {tag: 'li', ...}, {tag: 'li', ...} ]}

// Element with text content {tag: 'span', children: 'Text ...'}

Attributes

Element attributes can be set with the

attrs
property. The attribute name is always the same as in HTML. If you provide a boolean for the attribute value, the attribute will be added with an empty string if it is
true
and removed otherwise.
// Element with an id and class
{tag: 'input', attrs: {id: 'name-field', 'class': 'important-field'}}

// Input element which is required {tag: 'input', attrs: {required: true}}

Inline Style

To style an element, you can either use a CSS string or an object with CSS properties. The object will update only changed properties while the string will simply overwrite the style attribute. The style property name is in both cases the same name as you would use for inline styles.

// Element with style string
{tag: 'input', attrs: {style: 'border-bottom: 1px solid black; color: gray;'}}

// Element with style object {tag: 'input', attrs: {style: {'border-bottom': '1px solid black', color: 'gray'}}}

Input Elements

While most attributes update DOM element attributes, the attributes

value
,
checked
,
selected
and
selectedIndex
are compared with and update DOM element properties instead. This is because these properties can be influenced by the user directly through browser input fields. If they were only compared with the previous attribute values, the current attribute values would not be enforced.

Moreover, there are a few other noteworthy exceptions:

The content of

textarea
elements must be provided with the
value
attribute instead of the
children
property:
{tag: 'textarea', attrs: {value: 'Text ...'}}

To define the current option of a

select
element you can either set the
value
or
selectedIndex
attribute or set the
selected
attribute of an
option
directly:
// Select option by setting the value
{tag: 'select', attrs: {value: 'val1'}, children: [
    {tag: 'option', attrs: {value: 'val1'}, ...}
]}

// Select option by setting the selectedIndex {tag: 'select', attrs: {selectedIndex: 0}, children: [ {tag: 'option', attrs: {value: 'val1'}, ...} ]}

// Select option by setting selected on the option {tag: 'select', attrs: children: [ {tag: 'option', attrs: {selected: true}, ...} ]}

Text Node

Usually, you will use text nodes like this:

// Span element with text node
{tag: 'span', children: 'Text ...'}
// Span element with text node and b element
{tag: 'span', children: [
    'Text ...',
    {tag: 'b', children: '...'}
]}

But there is also a more advanced form for keyed nodes:

// Text node as object with optional key
{tag: '#', key: '1', children: 'text'}

The

#
tag name comes from
#text
which is the DOM name of a text node.
Comment Node
{tag: '!', children: 'Comment ...'}

The

!
tag name comes from

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.