From b2e8f46a3bebed71c2f4603d14048ff95e72bb11 Mon Sep 17 00:00:00 2001 From: Ehevi Date: Sun, 7 Sep 2025 16:13:46 +0200 Subject: [PATCH] Add full server project and mithril workaround Docs refresh --- Framework/README.md | 2 +- Framework/docs/demo/README.md | 51 ++++++ Framework/docs/demo/frontend.html | 2 +- Framework/docs/demo/project/README.md | 35 +++++ Framework/docs/demo/project/config.js | 30 ++++ Framework/docs/demo/project/index.js | 35 +++++ .../docs/demo/project/public/chart/index.html | 10 ++ .../docs/demo/project/public/chart/main.js | 78 ++++++++++ .../demo/project/public/frontend/index.html | 10 ++ .../docs/demo/project/public/frontend/main.js | 146 ++++++++++++++++++ Framework/docs/demo/project/public/index.html | 13 ++ Framework/docs/demo/project/public/index.js | 54 +++++++ .../project/public/notification/index.html | 10 ++ .../demo/project/public/notification/main.js | 31 ++++ Framework/docs/demo/project/public/session.js | 17 ++ .../demo/project/public/template-1/index.html | 10 ++ .../demo/project/public/template-1/main.js | 22 +++ .../demo/project/public/template-2/index.html | 10 ++ .../demo/project/public/template-2/main.js | 60 +++++++ Framework/docs/demo/template-2.html | 2 +- Framework/docs/tutorial/public/index.html | 2 +- 21 files changed, 626 insertions(+), 4 deletions(-) create mode 100644 Framework/docs/demo/README.md create mode 100644 Framework/docs/demo/project/README.md create mode 100644 Framework/docs/demo/project/config.js create mode 100644 Framework/docs/demo/project/index.js create mode 100644 Framework/docs/demo/project/public/chart/index.html create mode 100644 Framework/docs/demo/project/public/chart/main.js create mode 100644 Framework/docs/demo/project/public/frontend/index.html create mode 100644 Framework/docs/demo/project/public/frontend/main.js create mode 100644 Framework/docs/demo/project/public/index.html create mode 100644 Framework/docs/demo/project/public/index.js create mode 100644 Framework/docs/demo/project/public/notification/index.html create mode 100644 Framework/docs/demo/project/public/notification/main.js create mode 100644 Framework/docs/demo/project/public/session.js create mode 100644 Framework/docs/demo/project/public/template-1/index.html create mode 100644 Framework/docs/demo/project/public/template-1/main.js create mode 100644 Framework/docs/demo/project/public/template-2/index.html create mode 100644 Framework/docs/demo/project/public/template-2/main.js diff --git a/Framework/README.md b/Framework/README.md index 2a0d46ed9..14df3366d 100644 --- a/Framework/README.md +++ b/Framework/README.md @@ -61,7 +61,7 @@ npm install --save @aliceo2/web-ui ### Getting started * [Step-by-step tutorial: Time server using Ajax and WebSockets](./docs/tutorial/time-server.md) -* [Advanced frontend demo](https://aliceo2group.github.io/WebUi/Framework/docs/demo/frontend.html) +* [Advanced frontend demo](./docs/demo/README.md) ### Backend guide * [REST API](./docs/guide/http-server.md) - Serves custom REST API, supports TLS diff --git a/Framework/docs/demo/README.md b/Framework/docs/demo/README.md new file mode 100644 index 000000000..dca9fcb5e --- /dev/null +++ b/Framework/docs/demo/README.md @@ -0,0 +1,51 @@ +# WebUi Demos + +This folder contains example demos showcasing the WebUi framework. + +> Mithril is the JavaScript frontend framework that WebUi builds on. It provides the virtual DOM engine and rendering API `m()` that all WebUi components depend on. The WebUi framework's [renderer.js](../../Frontend/js/src/renderer.js#L26) explicitly imports Mithril via an absolute path. Without Mithril loaded globally, none of the demos can render. + +There are two ways to run the demos: +1. [Full server approach](#1-full-server-approach-recommended) _(recommended)_ – run a backend that serves Mithril and all demos with clean routes. +2. [Manual workaround](#2-manual-workaround-quick--dirty) _(quick & dirty)_ – serve Mithril with a static server. + +## 1. Full server approach (recommended) + +See the [project README](./project/README.md) for setup instructions. + +This uses a proper backend that serves Mithril and all demos with clean routes. In the HTTP server's [constructor](./project/index.js#L27) a [`specifyRoutes`](https://github.com/AliceO2Group/WebUi/blob/dev/Framework/Backend/http/server.js#L172) logic is invoked to wire up all required routes. + +## 2. Manual workaround (quick & dirty) + +Serve docs statically and manually provide Mithril. + +Copy Mithril to the expected `mithril/mithril.min.js` path: + +```bash +cd WebUi/Framework +npm ci +mkdir -p mithril +cp node_modules/mithril/mithril.min.js mithril/mithril.min.js +``` + +If you don't want to install everything, you can also create the file manually. +```bash +cd WebUi/Framework +mkdir mithril +touch mithril/mithril.min.js +``` +Then copy the contents of the `mithril/mithril.min.js` file in there (available for example in the [unpkg.com](https://unpkg.com/mithril@2.3.7/mithril.min.js)). + +This is more error-prone than the local copy from `node_modules`. + +### Serve the Framework directory + +```bash +python3 -m http.server 8080 +``` + +Navigate through available demos: +- [chart](http://localhost:8080/docs/demo/chart.html) +- [frontend](http://localhost:8080/docs/demo/frontend.html) +- [notification](http://localhost:8080/docs/demo/notification.html) +- [template-1](http://localhost:8080/docs/demo/template-1.html) +- [template-2](http://localhost:8080/docs/demo/template-2.html). diff --git a/Framework/docs/demo/frontend.html b/Framework/docs/demo/frontend.html index b0d0b9a91..e2e90c52b 100644 --- a/Framework/docs/demo/frontend.html +++ b/Framework/docs/demo/frontend.html @@ -136,6 +136,6 @@ // Mount will listen to model changes and draw inside body the view mount(document.body, view, model, debug); -// Expose model to interract with it the browser's console +// Expose model to interact with it the browser's console window.model = model; diff --git a/Framework/docs/demo/project/README.md b/Framework/docs/demo/project/README.md new file mode 100644 index 000000000..721bff668 --- /dev/null +++ b/Framework/docs/demo/project/README.md @@ -0,0 +1,35 @@ +# Full server approach + +For the setup, we're basically going to repeat the steps from the tutorial. + +### 1. Fetch project template + +```bash +mkdir project +git clone https://github.com/AliceO2Group/WebUi.git +cp -R WebUi/Framework/docs/demo/project/* ./project +cd project +``` + +### 2. Add the framework to dependency list + +```bash +npm init +npm install --save @aliceo2/web-ui +``` + +### 3. Launch the application + +Start the server +```bash +node index.js +``` + +Then, open your browser and navigate to [http://localhost:8080](http://localhost:8080). This is the main demo page. + +Navigate through available demos: +- [chart](http://localhost:8080/chart) +- [frontend](http://localhost:8080/frontend/) +- [notification](http://localhost:8080/notification/) +- [template-1](http://localhost:8080/template-1/) +- [template-2](http://localhost:8080/template-2/). diff --git a/Framework/docs/demo/project/config.js b/Framework/docs/demo/project/config.js new file mode 100644 index 000000000..0be99471a --- /dev/null +++ b/Framework/docs/demo/project/config.js @@ -0,0 +1,30 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +/* + * This is quick start configuration + * See the Backend documentation for more details + * + */ +module.exports = { + jwt: { + secret: 'supersecret', + expiration: '10m', + }, + http: { + port: 8080, + hostname: 'localhost', + tls: false, + }, +}; diff --git a/Framework/docs/demo/project/index.js b/Framework/docs/demo/project/index.js new file mode 100644 index 000000000..4804f44b8 --- /dev/null +++ b/Framework/docs/demo/project/index.js @@ -0,0 +1,35 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +// Import the backend classes +const { HttpServer } = require('@aliceo2/web-ui'); + +// Define configuration for JWT tokens and HTTP server +const config = require('./config.js'); + +/* + * HTTP server + * ----------- + * + * Instantiate the HTTP server + */ +const httpServer = new HttpServer(config.http, config.jwt); + +// Server static content in public directory +httpServer.addStaticPath('./public'); +httpServer.addStaticPath('./public/chart', '/chart'); +httpServer.addStaticPath('./public/frontend', '/frontend'); +httpServer.addStaticPath('./public/notification', '/notification'); +httpServer.addStaticPath('./public/template-1', '/template-1'); +httpServer.addStaticPath('./public/template-2', '/template-2'); diff --git a/Framework/docs/demo/project/public/chart/index.html b/Framework/docs/demo/project/public/chart/index.html new file mode 100644 index 000000000..3c08b224b --- /dev/null +++ b/Framework/docs/demo/project/public/chart/index.html @@ -0,0 +1,10 @@ + +Chart Demo + + + +Loading... + + + + diff --git a/Framework/docs/demo/project/public/chart/main.js b/Framework/docs/demo/project/public/chart/main.js new file mode 100644 index 000000000..bb73459b8 --- /dev/null +++ b/Framework/docs/demo/project/public/chart/main.js @@ -0,0 +1,78 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +import {mount, h, Observable, chartTimeSeries} from '/js/src/index.js'; + +// Example of chart integration with template engine +const view = (model) => [ + h('div.m4', [ + chartTimeSeries({ + series: model.series1, + title: 'Sinus', + colorPrimary: 'red', + width: '800', + }), + ]), + h('div.m4', [ + chartTimeSeries({ + series: model.series1, + title: 'Sinus', + colorPrimary: 'red', + width: '800', + timeWindow: 100, + }), + ]), + h('div.m4', [ + chartTimeSeries({ + series: model.series2, + title: 'Random', + colorPrimary: 'blue', + width: '800', + }), + ]), + h('div.m4', [ + chartTimeSeries({ + series: model.series3, + title: 'Sinus rounded', + colorPrimary: 'green', + width: '800', + }), + ]), +]; + +// Create some basic model +const model = new Observable(); +model.series1 = []; +model.series2 = []; +model.series3 = []; +model.notify(); + +// Add points at 30 FPS but keep only first 800 points for memory leak +let i = 0; +setInterval(() => { + i++; + model.series1.push({value: Math.cos(i / 10), timestamp: Date.now()}); + model.series2.push({value: Math.random() * 10, timestamp: Date.now()}); + model.series3.push({value: Math.round(Math.cos(i / 10)), timestamp: Date.now()}); + + model.series1.splice(0, model.series1.length - 800); + model.series2.splice(0, model.series2.length - 800); + model.series3.splice(0, model.series3.length - 800); + + model.notify(); +}, 33); + +mount(document.body, view, model, true); + +window.model = model; diff --git a/Framework/docs/demo/project/public/frontend/index.html b/Framework/docs/demo/project/public/frontend/index.html new file mode 100644 index 000000000..ae7087bda --- /dev/null +++ b/Framework/docs/demo/project/public/frontend/index.html @@ -0,0 +1,10 @@ + +Advanced Frontend Demo + + + +Loading... + + + + diff --git a/Framework/docs/demo/project/public/frontend/main.js b/Framework/docs/demo/project/public/frontend/main.js new file mode 100644 index 000000000..59eb9abd2 --- /dev/null +++ b/Framework/docs/demo/project/public/frontend/main.js @@ -0,0 +1,146 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +// Import Framework tools +import {mount, h, Observable, iconDashboard, iconGridTwoUp, iconGridThreeUp, iconGridFourUp, iconCog} from '/js/src/index.js'; + +// This is our model, each time it is modified, it calls notify() and view is updated thanks to controller mount(). +class Model extends Observable { + constructor() { + super(); + this.form = {name: '', online: false}; + this.filter = ''; + this.list = [ + {name: 'TCP', online: true}, + {name: 'MUON', online: true}, + {name: 'TOF', online: false}, + {name: 'EMCAL', online: true}, + {name: 'PHOS', online: false}, + ]; + } + + setName(name) { + this.form.name = name; + this.notify(); + } + + setStatus(online) { + this.form.online = online; + this.notify(); + } + + setFilter(filter) { + this.filter = filter; + this.notify(); + } + + add() { + this.list.push(this.form); + this.form = {name: '', online: false}; + this.notify(); + } +} + +// View uses a vnode tree, CSS classes and some handlers to change model +const view = (model) => h('.flex-column absolute-fill', [ + header(model), + h('.flex-grow flex-row', [ + h('.sidebar', [ + h('.sidebar-content relative', [ + sidebar(model) + ]) + ]), + h('.flex-grow.relative', [ + content(model) + ]) + ]), +]); + +const header = (model) => h('.bg-white flex-row p2 shadow-level2 level2', [ + h('.flex-grow text-left', [ + h('button.btn', iconCog()), ' ', + h('span.f4 gray', 'Demo App') + ]), + h('.w-50 text-center', [ + h('h4', 'Status') + ]), + h('.flex-grow text-right', [ + h('input.form-control.form-inline', {placeholder: 'Search', oninput: (e) => model.setFilter(e.target.value)}), ' ', + ]), +]); + +const content = (model) => [ + h('.scroll-y.absolute-fill.bg-white', [ + h('p.p2.measure', 'This is an example of frontend use of WebUi Framework. You can add some elements to the table below and filter with search input.'), + + h('.measure.m2.bg-gray-lighter.p3.br4.text-no-select', [ + h('.form-group', [ + h('label', {for: 'input-name'}, 'Name'), + h('input.form-control', {id: 'input-name', oninput: (e) => model.setName(e.target.value), value: model.form.name}, 'Name'), + ]), + h('.form-check.mv2', [ + h('input.form-check-input', {id: 'input-status', onclick: (e) => model.setStatus(e.target.checked), checked: model.form.online, type: 'checkbox'}), + h('label.form-check-label', {for: 'input-status'}, 'Status online'), + ]), + h('button.btn btn-primary', {onclick: () => model.add()}, 'Add new detector'), + ]), + + h('div.m2', [ + h('table.table', [ + h('thead', [ + h('tr', [ + h('th', 'Name'), + h('th', 'Online'), + ]), + ]), + listFiltered(model).map(item => h('tr', [ + h('td', item.name), + h('td', {className: item.online ? '' : 'danger'}, item.online ? 'ON' : 'OFF') + ])) + ]) + ]), + + ]) +]; + +const listFiltered = (model) => model.list.filter(item => item.name.toLocaleLowerCase().includes(model.filter.toLocaleLowerCase())); + +const sidebar = (model) => h('.absolute-fill scroll-y', [ + h('.menu-title', 'Dashboard'), + h('a.menu-item', [ + iconDashboard(), ' Status' + ]), + + h('.menu-title', 'Listing'), + h('a.menu-item', [ + iconGridTwoUp(), ' Environments' + ]), + h('a.menu-item', [ + iconGridThreeUp(), ' Roles' + ]), + h('a.menu-item', [ + iconGridFourUp(), + ' ', + '...' + ]), +]); + +// Start application +const model = new Model(); +const debug = true; // shows when redraw is done with timing, must always be < 33ms (30 FPS) +// Mount will listen to model changes and draw inside body the view +mount(document.body, view, model, debug); + +// Expose model to interact with it the browser's console +window.model = model; diff --git a/Framework/docs/demo/project/public/index.html b/Framework/docs/demo/project/public/index.html new file mode 100644 index 000000000..6fc91475e --- /dev/null +++ b/Framework/docs/demo/project/public/index.html @@ -0,0 +1,13 @@ + +Demo + + + +Loading... + + + + + + + diff --git a/Framework/docs/demo/project/public/index.js b/Framework/docs/demo/project/public/index.js new file mode 100644 index 000000000..bd5fe377f --- /dev/null +++ b/Framework/docs/demo/project/public/index.js @@ -0,0 +1,54 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +import { h, mount, Observable } from '/js/src/index.js'; + +const DEMOS = [ + { name: 'frontend', label: 'Frontend' }, + { name: 'chart', label: 'Chart' }, + { name: 'notification', label: 'Notification' }, + { name: 'template-1', label: 'Template-1' }, + { name: 'template-2', label: 'Template-2' }, +]; + +class Model extends Observable { + constructor() { + super(); + this.demos = DEMOS; + } + } + +function view (model) { + return h('.absolute-fill.flex-column.items-center.justify-center', + h('.bg-gray-lighter.br3.p4', [ + h('h1', 'WebUi Demos'), + h('ul.list-unstyled', + model.demos.map(d => + h('li.mb-2', + h('a', { + href: `/${d.name}${location.search}`, + class: 'link-primary' + }, d.label || d.name) + ) + ) + ), + ]) + ); +} + +// Start application +const model = new Model(); +const debug = true; +mount(document.body, view, model, debug); +window.model = model; diff --git a/Framework/docs/demo/project/public/notification/index.html b/Framework/docs/demo/project/public/notification/index.html new file mode 100644 index 000000000..f9dd60b29 --- /dev/null +++ b/Framework/docs/demo/project/public/notification/index.html @@ -0,0 +1,10 @@ + +Demo + + + +Loading... + + + + diff --git a/Framework/docs/demo/project/public/notification/main.js b/Framework/docs/demo/project/public/notification/main.js new file mode 100644 index 000000000..470481817 --- /dev/null +++ b/Framework/docs/demo/project/public/notification/main.js @@ -0,0 +1,31 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +import {mount, h, Notification, notification} from '/js/src/index.js'; + +const view = (model) => [ + notification(model), + h('div.m4', [ + h('button', {onclick: () => model.show('An admin has taken lock form you.', 'primary')}, 'Show primary'), + h('button', {onclick: () => model.show('Environment has been created.', 'success')}, 'Show success'), + h('button', {onclick: () => model.show('Unable to create, please check inputs and retry.', 'warning')}, 'Show warning'), + h('button', {onclick: () => model.show('Server connection has been lost.', 'danger')}, 'Show danger'), + ]), +]; + +// Create some basic model +const model = new Notification(); + +mount(document.body, view, model, true); +window.model = model; diff --git a/Framework/docs/demo/project/public/session.js b/Framework/docs/demo/project/public/session.js new file mode 100644 index 000000000..5ed992296 --- /dev/null +++ b/Framework/docs/demo/project/public/session.js @@ -0,0 +1,17 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. +*/ + +import sessionService from '/js/src/sessionService.js'; +sessionService.loadAndHideParameters(); +window.sessionService = sessionService; diff --git a/Framework/docs/demo/project/public/template-1/index.html b/Framework/docs/demo/project/public/template-1/index.html new file mode 100644 index 000000000..a079da3df --- /dev/null +++ b/Framework/docs/demo/project/public/template-1/index.html @@ -0,0 +1,10 @@ + +Template-1 Demo + + + +Loading... + + + + diff --git a/Framework/docs/demo/project/public/template-1/main.js b/Framework/docs/demo/project/public/template-1/main.js new file mode 100644 index 000000000..e05af03fe --- /dev/null +++ b/Framework/docs/demo/project/public/template-1/main.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +// Import Framework tools +import {mount, h, Observable} from '/js/src/index.js'; + +const model = new Observable(); +const view = (model) => h('h1.title', `hello ${model.name}`); +mount(document.body, view, model); +model.name = 'Alice'; +model.notify(); diff --git a/Framework/docs/demo/project/public/template-2/index.html b/Framework/docs/demo/project/public/template-2/index.html new file mode 100644 index 000000000..3c08b224b --- /dev/null +++ b/Framework/docs/demo/project/public/template-2/index.html @@ -0,0 +1,10 @@ + +Chart Demo + + + +Loading... + + + + diff --git a/Framework/docs/demo/project/public/template-2/main.js b/Framework/docs/demo/project/public/template-2/main.js new file mode 100644 index 000000000..b9915178e --- /dev/null +++ b/Framework/docs/demo/project/public/template-2/main.js @@ -0,0 +1,60 @@ +/** + * @license + * Copyright 2019-2020 CERN and copyright holders of ALICE O2. + * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders. + * All rights not expressly granted are reserved. + * + * This software is distributed under the terms of the GNU General Public + * License v3 (GPL Version 3), copied verbatim in the file "COPYING". + * + * In applying this license CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization + * or submit itself to any jurisdiction. + */ + +import {mount, h, Observable} from '/js/src/index.js'; + +// This is our model, each time it is modified, it calls notify() and view is updated thanks to controller mount(). +class Model extends Observable { + constructor() { + super(); + this.count = 0; + } + + increment() { + this.count++; + this.notify(); + } + + decrement() { + this.count--; + this.notify(); + } +} + +// View uses a vnode tree, CSS classes and some handlers to change model +function view(model) { + return h('.absolute-fill.flex-column.items-center.justify-center', + h('.bg-gray-lighter.br3.p4', [ + h('h1', 'Hello World'), + h('ul', [ + // Template string is used to concatenate wording and values of the model + h('li', `Counter: ${model.count}`), + ]), + h('div', [ + // Lambda functions are used to bind to click events and ask model to change current state + h('button.btn', {onclick: e => model.increment()}, '++'), ' ', + h('button.btn', {onclick: e => model.decrement()}, '--'), ' ', + ]) + ]) + ); +} + +// Start application +const model = new Model(); +const debug = true; // shows when redraw is done with timing, must always be < 33ms (30 FPS) +// Mount will listen to model changes and draw inside body the view +mount(document.body, view, model, debug); + +// Expose model to interact with it the browser's console +window.model = model; diff --git a/Framework/docs/demo/template-2.html b/Framework/docs/demo/template-2.html index c71bd74fb..187ddb068 100644 --- a/Framework/docs/demo/template-2.html +++ b/Framework/docs/demo/template-2.html @@ -46,6 +46,6 @@ // Mount will listen to model changes and draw inside body the view mount(document.body, view, model, debug); -// Expose model to interract with it the browser's console +// Expose model to interact with it the browser's console window.model = model; diff --git a/Framework/docs/tutorial/public/index.html b/Framework/docs/tutorial/public/index.html index d8508d2c1..12b637ace 100644 --- a/Framework/docs/tutorial/public/index.html +++ b/Framework/docs/tutorial/public/index.html @@ -21,6 +21,6 @@ const debug = true; // shows when redraw is done mount(document.body, view, model, debug); -// Expose model to interract with it the browser's console +// Expose model to interact with it the browser's console window.model = model;