ApplicationPrototype

An event-driven modular JavaScript framework for the browser and Node.js: every method you bind gets before / on / after hooks, modules load on demand with a built-in loader, and templating, HTTP, storage, graphics and password hashing come along -- zero dependencies, no build step.

Open the documentation →
Getting started · Architecture · Example gallery · GitHub · npm
Zero dependenciesBrowser + Node.jsES5, no bundlerDocsify docsCC BY-NC 4.0

What is it?

ApplicationPrototype is a tiny primitive: an object whose methods are observable. ApplicationBuilder adds a module system on top -- files in constructors/ are fetched lazily (XHR in the browser, fs in Node.js), evaluated with module / Application / Promise in scope and cached by name. Everything else in the repository is such a module: templating with two-way binding, custom elements, an HTTP client, IndexedDB storage, image processing, parsers, and bcrypt / Argon2 password hashing that interoperates with PHP.

Observable by default

app.bind('save', fn) creates beforeSave, onSave and afterSave; a before handler that returns false vetoes the call. Reactive property() values emit __onSet / __onGet.

Modules by name

App.require('request') resolves against modulePath(); aliases ('req :: request'), arrays, callbacks or Promises -- and the same code runs in Node.js.

Nothing to install

Two <script> tags from the SGApps CDN or npm install application-prototype; plain ES5 modules, no transpiler, no bundler, no runtime dependency.

Verified documentation

Every page was audited against the source; the live examples below are browser-tested demos of each module, and the hashing modules are checked against PHP 8.3 and the official test vectors.

Modules

The core plus eleven module groups, each with its documentation page and a live example.

ApplicationPrototype

ApplicationPrototype.js

The event-driven object: bind, on, once, off, emit, property and the before / on / after lifecycle.

ApplicationBuilder

ApplicationBuilder.js

Module loader with caching, debugging console, Promise polyfill and Node.js interface; App.require(), modulePath(), moduleRegister().

async

async

Sequential flow, parallel waterfall with a concurrency limit, map, filter, forEach -- with results collected in order.

js-template & components

js-template, js-template-component

{{ }} two-way data binding, *if / *for / [(model)] directives and reusable components with lifecycle hooks.

custom-elements

custom-elements

Upgrade your own tags with lazily loaded behaviour: __onInit, __onContentChange, __onAttrChange.

request

request, request/http-track-progress, request/params-parser

Chainable HTTP client with upload / download progress events, a global progress bar and a route / query-string parameter parser.

browser-session

browser-session

Promise-based key-value store on IndexedDB with a localStorage fallback -- hundreds of megabytes of client-side data.

uri-load

uri-load

Inject scripts and stylesheets into any document (an iframe included) and get a callback once they are loaded.

graphic & canvas-draw

graphic, canvas-draw

Pure JavaScript image filters (blur, contrast, saturation, sepia, ...), edge detection, ImageData / Blob conversions and a path-based canvas animation loop.

devices/webcam

devices/webcam, devices/getUserMedia

Camera capture with a getUserMedia polyfill: video preview and snapshots.

parsers

parsers/string/csv, parsers/string/markdown

CSV parse / encode with quoted fields and a lightweight Markdown to HTML converter.

extensions/prototype

extensions/prototype

50+ helpers on String, Array, Blob, Function: SHA-1 / SHA-256 / MD5, AES, Base64, hex, escaping, random ids, polyfills.

extensions/hashing

extensions/hashing/{password, bcrypt, argon2, blake2b, phc}

PHP-compatible password_hash() / password_verify(): bcrypt ($2y$), Argon2i / Argon2id (RFC 9106) and BLAKE2b in pure JavaScript, time-sliced so the UI stays responsive.

Live examples

The demo pages of the documentation, embedded here. Served from the repository root (npm start) they run on your working copy of the framework; on the published site they load it from the SGApps CDN (https://cdn.sgapps.io/components/application-prototype). Each frame can also be opened on its own.

ApplicationPrototype events & lifecycle hooks

Call a bound method and watch beforeGreet / onGreet / afterGreet fire in the log, block a call from a before hook, try once() / off(), emit a custom event to several listeners and type into an input bound to a reactive property(). Docs · Open in a new tab

async flow / waterfall / map / filter

Randomly timed operations run through async.flow, async.waterfall (with a parallel limit), async.map and async.filter, drawn on a timeline so sequential vs. overlapping execution is obvious. Docs · Open in a new tab

js-template data-driven rendering

Type a name and watch the {{ }} expressions re-render. Docs · Open in a new tab

js-template-component reusable components

Two independent <todo-list> components built from one template: add tasks, toggle them, delete them -- *for, {{ }}, [(model)], *if and *class bindings at work. Docs · Open in a new tab

custom-elements lazy-loaded custom tags

A <mycustomelement> tag upgraded by a module that is loaded when the tag is first seen; content and attribute changes are reported below it. Docs · Open in a new tab

request HTTP client, progress tracking, params parser

Fetch JSON with status and headers, download a 300 KB file with progress events and the http-track-progress global bar, and parse route patterns / query strings with params-parser. Docs · Open in a new tab

browser-session IndexedDB / localStorage key-value store

A tiny notes app on the store: Set / Get / Delete / List / Clear, the active strategy and the setItem::key / removeItem::key events -- values survive a reload. Docs · Open in a new tab

uri-load inject scripts and stylesheets

Inject a stylesheet and a script into the inner frame with the two buttons and watch it change. Docs · Open in a new tab

graphic image filters, conversions, edge detection

A mini image editor on a canvas-drawn picture: ten filters with a strength slider, edge detection, ImageData / Blob conversions -- no external image needed. Docs · Open in a new tab

canvas-draw path based canvas animation

An orbit scene (sun, planets with trails, a bouncing square, a HUD) driven by the canvas-draw animation loop: Start / Stop / step one frame / add a planet / change the speed. Docs · Open in a new tab

devices/webcam camera capture

Asks for the camera only when you click Start camera, shows the live preview, takes snapshots to a canvas and reports permission errors in the page. Docs · Open in a new tab

parsers CSV and Markdown

A CSV textarea (quoted fields, commas and newlines inside quotes) parsed into a table and written back with a round-trip check, and a Markdown editor rendered live to HTML. Docs · Open in a new tab

extensions/prototype string, array & encryption helpers

Type in the boxes to see sha1(), sha256(), md5(), Base64 / hex, HTML and URL escaping, AES / TEA encrypt-decrypt round trips and the array helpers recomputed live. Docs · Open in a new tab

extensions/hashing bcrypt, Argon2, BLAKE2b

PHP-compatible password_hash() / password_verify() in pure JavaScript, plus a self-test against the official test vectors. Docs · Open in a new tab

Getting started

Browser

  1. Load ApplicationPrototype.js and ApplicationBuilder.js from the SGApps CDN (or your own copy).
  2. Point modulePath() at the constructors/ directory.
  3. Require modules by name.
<script src="https://cdn.sgapps.io/components/application-prototype/ApplicationPrototype.js"></script>
<script src="https://cdn.sgapps.io/components/application-prototype/ApplicationBuilder.js"></script>
<script>
var App = new ApplicationBuilder({
    onready: function () {
        var App = this;
        App.modulePath('https://cdn.sgapps.io/components/application-prototype/constructors');
        App.require(['extensions/prototype', 'lib'], function (libs) {
            libs.lib();                               // register every module by name
            App.require('extensions/hashing/password').then(function (password) {
                return password.password_hash('secret');
            }).then(function (hash) {
                console.log(hash);                    // '$2y$10$...' -- valid for PHP's password_verify()
            });
        });
    }
});
</script>

Node.js

  1. npm install application-prototype
  2. Create an event-driven object, or a builder for the modules.
  3. Same modules, same API.
var appPrototype = require('application-prototype');

// the event-driven primitive
var app = new appPrototype.application();
app.bind('greet', function (name) { return 'Hello, ' + name + '!'; });
app.on('afterGreet', function (name) { console.log('greeted', name); });
app.greet('World');

// the module loader
var App = new appPrototype.builder();
App.modulePath('@constructors://');
App.require('async', function (asyncModule) {
    var async = asyncModule();
    async.flow([[function (next) { next('done'); }]], function () {
        console.log(this.responses(true)); // ['done']
    });
});

The Getting Started page explains every step and the module resolution rules; the Architecture page shows how the pieces fit together.

npm start                     # this page + the docs at http://localhost:3000/ and /docs/
npm run docs-site-published   # serve docs/ alone; the examples then load the framework from cdn.sgapps.io
npm run docs-lint             # lint the documentation (links, sidebar, samples, example pages, this page)
sgapps.io