node package manager

noml

NOML

NOML (no markup language)

Let's admit it, HTML and Javascript really suck for making applications. They have separate purposes (UI and logic) with no real glue to bind them. Enter jQuery, Backbone, Ember, Angular, React, the list goes on and on. All of these improve the glue, but still rely on some complicated mapping model between the HTML and Javascript.

With NOML there is no HTML (or JSX, or Xml-ish-ness). NOML renders javascript objects into html. This technique allows for dynamic content to be rendered on the fly, modified, and bound with logic, without ever touching HTML. The entire application is written in literal, readable, unconverted Javascript. The glue is solved (chemistry pun intended).

results when noml.render() is called on the object.

ui.span('hello world!');
<span>hello world!</span>
ui.div(
    ui.span('span 1'),
    ui.span('span 2')
)
<div><span>span 1</span><span>span 2</span></div>

NOML Element classes have a prop method.

ui.span('welcome to noml').prop({id: 'mySpanId'})
<span id="mySpanId">welcome to noml</span>

since this is javascript to begin with, variables work naturally

var data = {name: 'adam'};
ui.span('my name is ' + data.name)
<span>my name is adam</span>
ui.span('a classy span').class('myClass')
<span class='myClass'>a classy span</span>

the NOML Element class handles de-duping of class names.

ui.span('a very classy span)
    .class('myClass1 myClass3')
    .class('myClass1 myClass2')
    .class('myClass3');
<span class='myClass1 myClass2 myClass3'>a very classy span</span>

NOML will wire to DOM events during render. the Element class wraps a few common events

ui.span('click here').onClick(() => alert('hi!'));

or you can use any other event name

ui.span('mouse enter here').event({mouseenter: () => alert('mouse entered!')})

Noml will render modular ui elements as components that allow for special interaction such as independent re-rendering and promise resolution. to do this, expose a getBody() method.

TODO: make example

you can give the component your own id or noml will auto-assign one so it can reference it for re-rendering, etc.

if your code maintains a reference to this object, the ui can be refreshed later by calling c.render() or c.syncProps(). this technique is best for low-level components where you want immediate response. For most cases, just re-rendering the whole page is much easier to manage. (and should still be very snappy)

to make loading, ready, and failure states, simply return a promise from getBody and expose a getLoadingBody() method. noml will re-render the ui when the promise is resolved or fails.

...
    getBody() {
        return Promise.resolve({span: 'this is a resolved promise'});
    },
    getLoadingBody() {
        return {span: 'loading'};
    }
...

'loading' will render until the promise is resolved.

<component id="_0"><span>this is a resolved promise</span></component>

To keep the abstraction away from html, the best way to read user input is by mapping it back to your javascript data objects. You can do this with the change or other similar element events. Noml will wire up native dom element events if you begin a property with $. Another option is to give the element a unique id and find it later.

TODO: make example

Noml also uses javascript to define CSS. The general format is as follows:

{
    id: {
        class: {
            property: value,
            state: {
                property: value, ...
            }, ...
        }, ...
    }, ...
}

Noml uses c.id and c.getStyle() to maintain the composite css object. Class names can be prepended with $ in place of . when desired (other selectors work in place of class name). Included examples show techniques to define and override default styles.

 
    getDefaultStyle() {
    return {
      $clickable: {
        cursor: 'pointer',
        ':hover': {
                    'text-decoration': 'underline'
        }
      }
    };
  }
 
#page .clickable {
    cursor:pointer;
}
#page .clickable:hover {
    text-decoration:underline;
}

That is the extent of the Noml library itself. This leaves a lot of room for project architecture around it. Here is a basic example of how to begin:

start with a simple html file:

<!DOCTYPE html>
<html>
<head>
    <script type="text/javascript" src="readme.js"></script> 
    <title>Noml example</title>
</head>
    <body>
    </body>
</html>

and a simple js file:

import * as noml from './Noml';
import {ui} from './Noml';
 
window.onload = bodyOnLoad();
 
function bodyOnLoad() {
    noml.renderPage(ui.span("my first Noml app"));
}

The included example shows a technique of structuring an application with ui, data, logic, and state all managed.