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.
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.
app.bind('save', fn) creates beforeSave, onSave and afterSave; a before handler that returns false vetoes the call. Reactive property() values emit __onSet / __onGet.
App.require('request') resolves against modulePath(); aliases ('req :: request'), arrays, callbacks or Promises -- and the same code runs in Node.js.
Two <script> tags from the SGApps CDN or npm install application-prototype; plain ES5 modules, no transpiler, no bundler, no runtime dependency.
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.
The core plus eleven module groups, each with its documentation page and a live example.
The event-driven object: bind, on, once, off, emit, property and the before / on / after lifecycle.
Module loader with caching, debugging console, Promise polyfill and Node.js interface; App.require(), modulePath(), moduleRegister().
Sequential flow, parallel waterfall with a concurrency limit, map, filter, forEach -- with results collected in order.
{{ }} two-way data binding, *if / *for / [(model)] directives and reusable components with lifecycle hooks.
Upgrade your own tags with lazily loaded behaviour: __onInit, __onContentChange, __onAttrChange.
Chainable HTTP client with upload / download progress events, a global progress bar and a route / query-string parameter parser.
Promise-based key-value store on IndexedDB with a localStorage fallback -- hundreds of megabytes of client-side data.
Inject scripts and stylesheets into any document (an iframe included) and get a callback once they are loaded.
Pure JavaScript image filters (blur, contrast, saturation, sepia, ...), edge detection, ImageData / Blob conversions and a path-based canvas animation loop.
Camera capture with a getUserMedia polyfill: video preview and snapshots.
CSV parse / encode with quoted fields and a lightweight Markdown to HTML converter.
50+ helpers on String, Array, Blob, Function: SHA-1 / SHA-256 / MD5, AES, Base64, hex, escaping, random ids, polyfills.
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.
events & lifecycle hooksCall 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
flow / waterfall / map / filterRandomly 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
data-driven renderingType a name and watch the {{ }} expressions re-render. Docs · Open in a new tab
reusable componentsTwo 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
lazy-loaded custom tagsA <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
HTTP client, progress tracking, params parserFetch 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
IndexedDB / localStorage key-value storeA 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
inject scripts and stylesheetsInject a stylesheet and a script into the inner frame with the two buttons and watch it change. Docs · Open in a new tab
image filters, conversions, edge detectionA 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
path based canvas animationAn 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
camera captureAsks 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
CSV and MarkdownA 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
string, array & encryption helpersType 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
bcrypt, Argon2, BLAKE2bPHP-compatible password_hash() / password_verify() in pure JavaScript, plus a self-test against the official test vectors. Docs · Open in a new tab
ApplicationPrototype.js and ApplicationBuilder.js from the SGApps CDN (or your own copy).modulePath() at the constructors/ directory.<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>
npm install application-prototypevar 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)