#noframeworks, just plain JavaScript ES6 with a simple php backend.
It uses built-in ES6 webcomponents and the pubsub pattern to allow each component to subscribe and/or publish to the datastore. In 399 lines of Javascript. Including an evil boss who keeps adding pointless meetings. And a 'slow' server to demo the async-ness of it all.
I used a plain JSON file as a 'database' just to demonstrate proof-of-concept. As JSON is a data-interchange format it's obviously not the tool for reliable client/server data sync but most (all?) of these problems would be solved with a proper db backend.
This was built on
- php 7.3
- chromium 74
- Ubuntu 18.04
The only real requirements are php 7.x and avoid using non-chromium IE/Edge
To install,
- download and unzip to a folder of your choice
- start with
php -S localhost:4567
- point your browser at
localhost:4567
Objects that have something to say publish a string of NewInfo and an object of data:
let task = {
taskname: document.querySelector('#taskname').value,
message: 'client added ' + document.querySelector('#taskname').value,
changeTask: false,
deleteTask: false,
checked: false,
css: 'closed'
};
this.pubsub.publish('AddTask', task);
Objects that are interested in those news items subscribe to 'NewPerson'/'Message'/'SomeEvent' etc, state what info they want and give the callback function they want to be fired:
this.pubsub.subscribe('AddTask', 'getMeta', this.renderData);
I could have wrapped all requests in an object, so instead of
this.pubsub.subscribe('AddTask', 'getMeta', this.renderData); this.pubsub.subscribe('ChangeTask', 'getMeta', this.renderData); this.pubsub.subscribe('DeleteTask', 'getMeta', this.renderData); this.pubsub.subscribe('ServerTask', 'getMeta', this.renderData);
we would have
this.pubsub.subscribe({'AddTask', 'ChangeTask','DeleteTask','ServerTask'}, 'getMeta', this.renderData);
but then it would be more tricky to assign specific requests/callbacks to each NewInfo.
Language Files Lines Code Comments Blanks
-------------------------------------------------------------------------------
CSS 1 105 86 1 18
HTML 1 23 14 0 9
JavaScript 13 562 399 87 76
Markdown 1 115 115 0 0
PHP 6 258 145 82 31
-------------------------------------------------------------------------------
Total 22 1063 759 170 134
├── backend
│ ├── debug.log
│ ├── evilBoss.php
│ ├── receiveTask.php
│ ├── sendTasks.php
│ └── tasks.json
├── css
│ └── style.css
├── favicon.ico
├── index.html
├── js
│ ├── components
│ │ ├── app-addtask.js
│ │ ├── app-console.js
│ │ ├── app-servermessages.js
│ │ ├── app-task.js
│ │ └── app-tasks.js
│ ├── data
│ │ ├── datastore.js
│ │ ├── fetchTasks.js
│ │ ├── pubsub.js
│ │ └── sendTask.js
│ ├── helpers
│ │ ├── app-rootelement.js
│ │ ├── generateRandomTask.js
│ │ └── serverMonitor.js
│ └── main.js
└── README.md
I used James Johnson's code to autobind 'this' for methods instead of having to do it in every class. So originally I had something like:
class appAddtask extends HTMLElement {}
I now have:
class appAddtask extends RootElement {}
and RootElement extends HTMLElement.
It needed a couple of changes:
- currCls.__proto__ is deprecated in favor of Object.getPrototypeOf(currCls)
- Object.getPrototypeOf(currCls) needs to be checked for null/undefined, hence the check on line 16 in app-rootelement.js
The Vaadin clip that showed me the way is here
Use as you like, ask questions if stuck, and stars are nice (top right)...