Preliminary support for user input
This commit is contained in:
parent
36acc56fa2
commit
a8544dfd39
|
@ -1,9 +0,0 @@
|
||||||
## Client/UI
|
|
||||||
|
|
||||||
Voting consists of staking operations performed by software operated by owners of EOA.
|
|
||||||
|
|
||||||
This software may be referred to as "The UI". It may also be considered "a client".
|
|
||||||
|
|
||||||
It will need to be a network-connected application. It will need a certain minimum of RAM,
|
|
||||||
and for some features disk storage,
|
|
||||||
and for some features uptime .
|
|
|
@ -1,5 +1,18 @@
|
||||||
# Client Operations
|
## Client
|
||||||
|
|
||||||
Client must communicate with one or more servers.
|
Clients play a key role in an MVPR DAO.
|
||||||
|
|
||||||
Client must build a local view
|
Clients must be operated by reputation holders.
|
||||||
|
|
||||||
|
Clients are the agents that submit posts to the forum, initiate validation pools, and vote in validation pools.
|
||||||
|
|
||||||
|
We sometimes refer to the client as "the UI".
|
||||||
|
|
||||||
|
It will need to be a network-connected application. It will need a certain minimum of RAM,
|
||||||
|
and for some features disk storage,
|
||||||
|
and for some features uptime .
|
||||||
|
|
||||||
|
The behavior of the client constitutes what we refer to as the DAO's "soft protocols".
|
||||||
|
|
||||||
|
Malicious actors may freely modify their own client's behavior.
|
||||||
|
Therefore honest clients must engage in policing to preserve the integrity of the network.
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export class Client {
|
||||||
|
constructor(dao, expert) {
|
||||||
|
this.dao = dao;
|
||||||
|
this.expert = expert;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,9 @@ export class Box {
|
||||||
constructor(name, parentEl, options = {}) {
|
constructor(name, parentEl, options = {}) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.el = document.createElement('div');
|
this.el = document.createElement('div');
|
||||||
this.el.id = `box_${randomID()}`;
|
this.el.box = this;
|
||||||
|
const id = options.id ?? randomID();
|
||||||
|
this.el.id = `${parentEl.id}_box_${id}`;
|
||||||
this.el.classList.add('box');
|
this.el.classList.add('box');
|
||||||
if (name) {
|
if (name) {
|
||||||
this.el.setAttribute('box-name', name);
|
this.el.setAttribute('box-name', name);
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { Box } from './box.js';
|
||||||
|
import { Form } from './form.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @example
|
||||||
|
* ```typescript
|
||||||
|
* const doc = new Document();
|
||||||
|
* const form1 = doc.form();
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export class Document extends Box {
|
||||||
|
form() {
|
||||||
|
return this.addElement(new Form(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
remarks(text, opts) {
|
||||||
|
return this.addElement(new Box('Remark', this.el, opts).setInnerHTML(text));
|
||||||
|
}
|
||||||
|
|
||||||
|
addElement(element) {
|
||||||
|
this.elements = this.elements ?? [];
|
||||||
|
this.elements.push(element);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastElement() {
|
||||||
|
if (!this.elements?.length) return null;
|
||||||
|
return this.elements[this.elements.length - 1];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { randomID } from '../../util/helpers.js';
|
||||||
|
import { Box } from './box.js';
|
||||||
|
|
||||||
|
const updateValuesOnEventTypes = ['keyup', 'mouseup'];
|
||||||
|
|
||||||
|
export class FormElement extends Box {
|
||||||
|
constructor(name, parentEl, opts) {
|
||||||
|
super(name, parentEl, opts);
|
||||||
|
this.id = opts.id ?? name;
|
||||||
|
const { cb } = opts;
|
||||||
|
if (cb) {
|
||||||
|
updateValuesOnEventTypes.forEach((eventType) => this.el.addEventListener(eventType, () => {
|
||||||
|
cb(this);
|
||||||
|
}));
|
||||||
|
cb(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Button extends FormElement { }
|
||||||
|
|
||||||
|
export class TextField extends FormElement {
|
||||||
|
constructor(name, parentEl, opts) {
|
||||||
|
super(name, parentEl, opts);
|
||||||
|
this.input = document.createElement('input');
|
||||||
|
this.el.appendChild(this.input);
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this.input?.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TextArea extends FormElement { }
|
||||||
|
|
||||||
|
export class Form {
|
||||||
|
constructor(document, opts = {}) {
|
||||||
|
this.document = document;
|
||||||
|
this.items = [];
|
||||||
|
this.id = opts.id ?? `form_${randomID()}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
button(opts) {
|
||||||
|
this.items.push(new Button(opts.name, this.document.el, opts));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
textField(opts) {
|
||||||
|
this.items.push(new TextField(opts.name, this.document.el, opts));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
textArea(opts) {
|
||||||
|
this.items.push(new TextArea(opts.name, this.document.el, opts));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { Table } from './table.js';
|
||||||
import { Flowchart } from './flowchart.js';
|
import { Flowchart } from './flowchart.js';
|
||||||
import { Controls } from './controls.js';
|
import { Controls } from './controls.js';
|
||||||
import { Box } from './box.js';
|
import { Box } from './box.js';
|
||||||
|
import { Document } from './document.js';
|
||||||
|
|
||||||
export class Scene {
|
export class Scene {
|
||||||
constructor(name, rootBox) {
|
constructor(name, rootBox) {
|
||||||
|
@ -86,6 +87,24 @@ export class Scene {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} name
|
||||||
|
* @param {(Document): Document} cb
|
||||||
|
* @returns {Scene}
|
||||||
|
*/
|
||||||
|
withDocument(name, cb) {
|
||||||
|
this.documents = this.documents ?? [];
|
||||||
|
const doc = new Document(name, this.middleSection.el);
|
||||||
|
this.documents.push(cb ? cb(doc) : doc);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastDocument() {
|
||||||
|
if (!this.documents?.length) return null;
|
||||||
|
return this.documents[this.documents.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
registerActor(actor) {
|
registerActor(actor) {
|
||||||
this.actors.add(actor);
|
this.actors.add(actor);
|
||||||
if (actor.options.announce) {
|
if (actor.options.announce) {
|
||||||
|
|
|
@ -28,6 +28,12 @@
|
||||||
<li><a href="./tests/forum11.test.html">Multiple posts with overlapping authors</a></li>
|
<li><a href="./tests/forum11.test.html">Multiple posts with overlapping authors</a></li>
|
||||||
</ol>
|
</ol>
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<h3>Client</h3>
|
||||||
|
<ol>
|
||||||
|
<li><a href="./tests/client1.test.html">Expert can run a client</a></li>
|
||||||
|
</ol>
|
||||||
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="./tests/vm.test.html">VM</a></li>
|
<li><a href="./tests/vm.test.html">VM</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -38,6 +44,7 @@
|
||||||
<li><a href="./tests/debounce.test.html">Debounce</a></li>
|
<li><a href="./tests/debounce.test.html">Debounce</a></li>
|
||||||
<li><a href="./tests/flowchart.test.html">Flowchart</a></li>
|
<li><a href="./tests/flowchart.test.html">Flowchart</a></li>
|
||||||
<li><a href="./tests/mocha.test.html">Mocha</a></li>
|
<li><a href="./tests/mocha.test.html">Mocha</a></li>
|
||||||
|
<li><a href="./tests/input.test.html">Input</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<h4><a href="./tests/all.test.html">All</a></h4>
|
<h4><a href="./tests/all.test.html">All</a></h4>
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
<script type="module" src="./scripts/forum/forum9.test.js"></script>
|
<script type="module" src="./scripts/forum/forum9.test.js"></script>
|
||||||
<script type="module" src="./scripts/forum/forum10.test.js"></script>
|
<script type="module" src="./scripts/forum/forum10.test.js"></script>
|
||||||
<script type="module" src="./scripts/forum/forum11.test.js"></script>
|
<script type="module" src="./scripts/forum/forum11.test.js"></script>
|
||||||
|
<script type="module" src="./scripts/input.test.js"></script>
|
||||||
<script defer class="mocha-init">
|
<script defer class="mocha-init">
|
||||||
mocha.setup({
|
mocha.setup({
|
||||||
ui: 'bdd',
|
ui: 'bdd',
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Client test 1</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
||||||
|
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h2><a href="../">DGF Tests</a></h2>
|
||||||
|
<div id="mocha"></div>
|
||||||
|
<div id="scene"></div>
|
||||||
|
</body>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
||||||
|
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
||||||
|
<script src="https://unpkg.com/chai/chai.js"></script>
|
||||||
|
<script type="module" src="./scripts/client/client1.test.js"></script>
|
||||||
|
<script defer class="mocha-init">
|
||||||
|
mocha.setup({
|
||||||
|
ui: 'bdd',
|
||||||
|
});
|
||||||
|
chai.should();
|
||||||
|
</script>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Input</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
||||||
|
<link type="text/css" rel="stylesheet" href="../index.css" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h2><a href="../">DGF Tests</a></h2>
|
||||||
|
<div id="mocha"></div>
|
||||||
|
<div id="scene"></div>
|
||||||
|
</body>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/radash/10.7.0/radash.js"
|
||||||
|
integrity="sha512-S207zKWG3iqXqe6msO7/Mr8X3DzzF4u8meFlokHjGtBPTGUhgzVo0lpcqEy0GoiMUdcoct+H+SqzoLsxXbynzg=="
|
||||||
|
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
|
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
||||||
|
<script src="https://unpkg.com/chai/chai.js"></script>
|
||||||
|
<script type="module" src="./scripts/input.test.js"></script>
|
||||||
|
<script defer class="mocha-init">
|
||||||
|
mocha.setup({
|
||||||
|
ui: 'bdd',
|
||||||
|
});
|
||||||
|
window.should = chai.should();
|
||||||
|
</script>
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
import { Client } from '../../../classes/dao/client.js';
|
||||||
|
|
||||||
|
describe('Forum', function tests() {
|
||||||
|
this.timeout(0);
|
||||||
|
|
||||||
|
const forumTest = new ForumTest({ displayAuthors: false });
|
||||||
|
let client;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
await forumTest.setup();
|
||||||
|
await forumTest.newExpert();
|
||||||
|
await forumTest.newExpert();
|
||||||
|
|
||||||
|
client = new Client(forumTest.dao, forumTest.experts[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Expert can run a client', async () => {
|
||||||
|
client.should.not.be.undefined;
|
||||||
|
client.dao.should.equal(forumTest.dao);
|
||||||
|
client.expert.should.equal(forumTest.experts[0]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
|
@ -1,9 +1,9 @@
|
||||||
import { Box } from '../../../classes/display/box.js';
|
import { Box } from '../../classes/display/box.js';
|
||||||
import { Scene } from '../../../classes/display/scene.js';
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
import { Expert } from '../../../classes/actors/expert.js';
|
import { Expert } from '../../classes/actors/expert.js';
|
||||||
import { PostContent } from '../../../classes/supporting/post-content.js';
|
import { PostContent } from '../../classes/supporting/post-content.js';
|
||||||
import { DAO } from '../../../classes/dao/dao.js';
|
import { DAO } from '../../classes/dao/dao.js';
|
||||||
import { delayOrWait } from '../../../classes/display/controls.js';
|
import { delayOrWait } from '../../classes/display/controls.js';
|
||||||
|
|
||||||
export class ForumTest {
|
export class ForumTest {
|
||||||
constructor(options) {
|
constructor(options) {
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { EPSILON } from '../../../util/constants.js';
|
import { EPSILON } from '../../../util/constants.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
|
import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { mochaRun } from '../../../util/helpers.js';
|
import { mochaRun } from '../../../util/helpers.js';
|
||||||
import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
|
import { INCINERATOR_ADDRESS } from '../../../util/constants.js';
|
||||||
import { ForumTest } from './forum.test-util.js';
|
import { ForumTest } from '../forum.test-util.js';
|
||||||
|
|
||||||
describe('Forum', function tests() {
|
describe('Forum', function tests() {
|
||||||
this.timeout(0);
|
this.timeout(0);
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { Box } from '../../classes/display/box.js';
|
||||||
|
// import { Document } from '../../classes/display/document.js';
|
||||||
|
import { Scene } from '../../classes/display/scene.js';
|
||||||
|
import { mochaRun } from '../../util/helpers.js';
|
||||||
|
|
||||||
|
const rootElement = document.getElementById('scene');
|
||||||
|
const rootBox = new Box('rootBox', rootElement).flex();
|
||||||
|
const scene = window.scene = new Scene('Input test', rootBox);
|
||||||
|
|
||||||
|
scene.withDocument();
|
||||||
|
|
||||||
|
describe('Document', () => {
|
||||||
|
it('Exists', () => {
|
||||||
|
scene.withDocument('Document', (doc) => doc.remarks('Hello'));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Input', () => {
|
||||||
|
it('Accepts input', () => {
|
||||||
|
scene.withDocument('Document', (doc) => doc.form());
|
||||||
|
const doc = scene.lastDocument;
|
||||||
|
const form1 = doc.lastElement;
|
||||||
|
const dvMap = new Map();
|
||||||
|
const updateFieldValueDisplay = ({ name, value }) => {
|
||||||
|
const dv = dvMap.get(name) ?? scene.addDisplayValue(name);
|
||||||
|
dvMap.set(name, dv);
|
||||||
|
dv.set(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
form1.textField({ id: 'input1', name: 'Input 1', cb: updateFieldValueDisplay });
|
||||||
|
doc.remarks('Hmm...!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
mochaRun();
|
Loading…
Reference in New Issue