unclean SPARC
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<style>
|
||||
.chalkboard > header { background: url('/app/assets/images/cards/chalkboard.jpg'); }
|
||||
.chalkboard .toolbox {
|
||||
text-align: center;
|
||||
}
|
||||
.chalkboard .board .dummy {
|
||||
display: block;
|
||||
height: 0;
|
||||
}
|
||||
.chalkboard canvas {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
cursor:default;
|
||||
}
|
||||
.chalkboard canvas.drawing {
|
||||
cursor:crosshair;
|
||||
}
|
||||
.chalkboard .toolbox .color-sample {
|
||||
display: inline-grid;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid black !important;
|
||||
margin: 1px !important;
|
||||
}
|
||||
.chalkboard .toolbox .pen-sample {
|
||||
display: inline-grid;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
border: 1px solid black !important;
|
||||
margin: 1px !important;
|
||||
}
|
||||
.chalkboard .toolbox span.selected {
|
||||
border-color: var(--eicui-base-color-accessible-focus) !important;
|
||||
box-shadow: inset 0 0 0 1px var(--eicui-base-color-accessible-focus),inset 0 0 0 2px var(--eicui-base-color-grey-5);
|
||||
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||
}
|
||||
.chalkboard .board .users {
|
||||
width: fit-content;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
<article eiccard media class="chalkboard">
|
||||
<header>
|
||||
<h1>Magic Chalkboard</h1>
|
||||
<h2>Collaborative artworks</h2>
|
||||
</header>
|
||||
<section>
|
||||
<div class="cols-2 left top">
|
||||
<div class="toolbox">
|
||||
<input eicinput type="hidden" name="color" value="white" />
|
||||
<input eicinput type="hidden" name="width" value="2" />
|
||||
|
||||
<div class="colors">
|
||||
<span class="color-sample selected" data-id="white" data-value="rgba(255,255,255,1)" style="background:rgba(255,255,255,1)"></span>
|
||||
<span class="color-sample" data-id="blue" data-value="rgba(0, 42, 255, 1)" style="background:rgba(0, 42, 255, 1)"></span>
|
||||
<span class="color-sample" data-id="red" data-value="rgba(255, 0, 0, 1)" style="background:rgba(255, 0, 0, 1)"></span>
|
||||
<span class="color-sample" data-id="yellow" data-value="rgba(255, 247, 6, 1)" style="background:rgba(255, 247, 6, 1)"></span>
|
||||
<span class="color-sample" data-id="green" data-value="rgba(54, 255, 8, 1)" style="background:rgba(54, 255, 8, 1)"></span>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="pens">
|
||||
<span class="pen-sample icon-big-bullet selected" xxsmall data-value="2"></span>
|
||||
<span class="pen-sample icon-big-bullet" xsmall data-value="4"></span>
|
||||
<span class="pen-sample icon-big-bullet" small data-value="6"></span>
|
||||
</div>
|
||||
<hr/>
|
||||
<button class="clear-board" eicbutton icon="icon-bin" xsmall danger></button>
|
||||
<button class="dl-board" eicbutton icon="icon-download" xsmall info></button>
|
||||
</div>
|
||||
<div class="board">
|
||||
<span class="dummy">*</span>
|
||||
<canvas></canvas>
|
||||
<div class="users"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
@@ -0,0 +1,318 @@
|
||||
/**
|
||||
* Magic Chalkboard demo app
|
||||
*
|
||||
* A simple app to share an editable canvas between bus users.
|
||||
* Demonstrates :
|
||||
* - subscription to a custom channel
|
||||
* - burst event send/receive of custom event types
|
||||
* - lightspeed response time of events broadcasting
|
||||
* - accuracy and reliability of event queuing
|
||||
* - implementation of app design with bus connected/disconnected.
|
||||
*
|
||||
* @author Michael Fallise
|
||||
* @version 1.0
|
||||
*/
|
||||
class ChalkboardView extends EICDomContent {
|
||||
|
||||
options = {
|
||||
background: 'rgba(0,0,0,1)',
|
||||
busChannel: 'collaborative:chalkboard'
|
||||
}
|
||||
|
||||
DOMContentLoaded() {
|
||||
|
||||
let components = ui.eicfy(this.el);
|
||||
|
||||
this.useBus = false;
|
||||
this.busUsers = [];
|
||||
|
||||
this.toolbox = new Form(this.find('.toolbox'));
|
||||
|
||||
let colors = this.findAll('.color-sample');
|
||||
for(let color of colors) color.addEventListener('click', this.onColorChange.bind(this));
|
||||
|
||||
let pens = this.findAll('.pen-sample');
|
||||
for(let pen of pens) pen.addEventListener('click', this.onPenChange.bind(this));
|
||||
|
||||
let dl = components.find(item => item.el.classList.contains('dl-board'));
|
||||
dl.addEventListener('click', this.onBoardDownload.bind(this));
|
||||
|
||||
let clear = components.find(item => item.el.classList.contains('clear-board'));
|
||||
clear.addEventListener('click', this.onBoardClear.bind(this));
|
||||
|
||||
this.board = this.find('canvas');
|
||||
this.board.style.background = this.options.background;
|
||||
this.ctx = this.board.getContext("2d");
|
||||
this.ctx.lineCap = 'round';
|
||||
|
||||
this.drawing = this.eraser = false;
|
||||
this.mouseCurrent = { x: 0, y: 0 };
|
||||
this.mousePrev = { x: 0, y: 0 };
|
||||
|
||||
// referencing computed event handlers
|
||||
this.mouseDownHandler = this.onChalkStart.bind(this);
|
||||
this.mouseMoveHandler = this.onChalkMove.bind(this);
|
||||
this.mouseUpHandler = this.onChalkEnd.bind(this);
|
||||
this.busDrawHandler = this.onBusDraw.bind(this);
|
||||
this.busClearHandler = this.onBusClear.bind(this);
|
||||
this.busPingHandler = this.onBusPing.bind(this);
|
||||
this.busJoinHandler = this.onBusJoin.bind(this);
|
||||
this.busLeaveHandler = this.onBusLeave.bind(this);
|
||||
|
||||
this.setBrush();
|
||||
this.setBoardSize();
|
||||
this.clear();
|
||||
this.initListeners();
|
||||
}
|
||||
|
||||
DOMContentRemoved() { this.closeListeners(); }
|
||||
|
||||
DOMContentResized() {
|
||||
let data = this.board.toDataURL('image/png');
|
||||
this.setBoardSize();
|
||||
let img = new Image;
|
||||
let self = this
|
||||
img.onload = function() { self.ctx.drawImage(img, 0, 0); };
|
||||
img.src = data;
|
||||
|
||||
}
|
||||
|
||||
setBoardSize() {
|
||||
let rect = this.board.getBoundingClientRect()
|
||||
this.board.width = rect.width;
|
||||
this.board.height = rect.height;
|
||||
}
|
||||
|
||||
/* Nike to Mike : As planned, made higher-level addBusListener & removeBusListener
|
||||
* Changes : Includes channel filtering (important to avoid chan injections by script-kiddies)
|
||||
*
|
||||
* You can replace old-style :
|
||||
* app.events.addEvent('MessageBus.XXX', handler, scope)
|
||||
* app.events.removeEvent('MessageBus.XXX', handler, scope)
|
||||
* => handler receives pure JS event, and probably uses e.detail.payload
|
||||
*
|
||||
* by new-style:
|
||||
* app.MessageBus.addBusListener('XXX', [this.busChannel], handler, scope)
|
||||
* app.MessageBus.removeBusListener('XXX', handler, scope)
|
||||
* => handler receives (realChan, payload, sender)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
initListeners() {
|
||||
this.board.addEventListener('mousedown', this.mouseDownHandler);
|
||||
this.board.addEventListener('mousemove', this.mouseMoveHandler);
|
||||
this.board.addEventListener('mouseup', this.mouseUpHandler);
|
||||
// disabling context menu on canvas in order to use right button for eraser
|
||||
this.board.oncontextmenu = function() { return false;}
|
||||
|
||||
if(app.MessageBus.connected) {
|
||||
console.log("USING BUS")
|
||||
app.MessageBus.subscribe([this.options.busChannel])
|
||||
.then( payload => {
|
||||
app.MessageBus.addBusListener('board_draw', ['collaborative:chalkboard'], this.busDrawHandler, 'chalkboard');
|
||||
app.MessageBus.addBusListener('board_clear', ['collaborative:chalkboard'], this.busClearHandler, 'chalkboard');
|
||||
app.MessageBus.addBusListener('board_ping', ['collaborative:chalkboard'], this.busPingHandler, 'chalkboard');
|
||||
app.MessageBus.addBusListener('board_join', ['collaborative:chalkboard'], this.busJoinHandler, 'chalkboard');
|
||||
app.MessageBus.addBusListener('board_leave', ['collaborative:chalkboard'], this.busLeaveHandler, 'chalkboard');
|
||||
this.useBus = true;
|
||||
this.pingUsers();
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
closeListeners() {
|
||||
if(this.useBus) {
|
||||
app.MessageBus.removeBusListener('board_draw', this.busDrawHandler, 'chalkboard');
|
||||
app.MessageBus.removeBusListener('board_clear', this.busClearHandler, 'chalkboard');
|
||||
app.MessageBus.removeBusListener('board_join', this.busJoinHandler, 'chalkboard');
|
||||
app.MessageBus.removeBusListener('board_ping', this.busPingHandler, 'chalkboard');
|
||||
app.MessageBus.removeBusListener('board_leave', this.busLeaveHandler, 'chalkboard');
|
||||
this.leaveApp();
|
||||
this.useBus = false;
|
||||
}
|
||||
}
|
||||
|
||||
setBrush() { this.brush = this.toolbox.value; }
|
||||
|
||||
draw(brush, from, to) {
|
||||
this.ctx.fillStyle = brush.color;
|
||||
this.ctx.strokeStyle = brush.color;
|
||||
this.ctx.lineWidth = brush.width;
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(from.x, from.y);
|
||||
this.ctx.lineTo(to.x, to.y);
|
||||
this.ctx.stroke();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.ctx.fillStyle = this.options.background;
|
||||
this.ctx.fillRect(0, 0, this.board.width, this.board.height);
|
||||
this.ctx.fillStyle = this.brush.color;
|
||||
}
|
||||
|
||||
onChalkStart(event) {
|
||||
this.drawing = true;
|
||||
this.eraser = event.button == 2,
|
||||
|
||||
this.mousePrev.x = this.mouseCurrent.x;
|
||||
this.mousePrev.y = this.mouseCurrent.y;
|
||||
|
||||
this.setBrush();
|
||||
}
|
||||
|
||||
onChalkMove(event) {
|
||||
|
||||
let rect = event.target.getBoundingClientRect();
|
||||
|
||||
this.mouseCurrent.x = event.pageX - rect.left;
|
||||
this.mouseCurrent.y = event.pageY - rect.top;
|
||||
|
||||
if(this.drawing) {
|
||||
|
||||
this.board.classList.add('drawing');
|
||||
|
||||
let brush = this.eraser ? { color: this.options.background, width: 20 }: this.brush;
|
||||
|
||||
if(this.useBus) {
|
||||
app.MessageBus.sendEvent(this.options.busChannel,'board_draw', {
|
||||
uid: app.User.identity.uuid,
|
||||
brush: brush,
|
||||
from: this.mousePrev,
|
||||
to: this.mouseCurrent,
|
||||
});
|
||||
} else {
|
||||
this.draw(brush, this.mousePrev, this.mouseCurrent);
|
||||
}
|
||||
|
||||
this.mousePrev.x = this.mouseCurrent.x;
|
||||
this.mousePrev.y = this.mouseCurrent.y;
|
||||
}
|
||||
}
|
||||
|
||||
onChalkEnd(event) {
|
||||
this.drawing = this.eraser = false;
|
||||
this.board.classList.remove('drawing');
|
||||
}
|
||||
|
||||
onColorChange(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.find('.color-sample.selected').classList.remove('selected');
|
||||
|
||||
let color = event.currentTarget;
|
||||
color.classList.add('selected');
|
||||
this.find('input[name="color"]').value = color.dataset.value;
|
||||
}
|
||||
|
||||
onPenChange(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.find('.pen-sample.selected').classList.remove('selected');
|
||||
|
||||
let pen = event.currentTarget;
|
||||
pen.classList.add('selected');
|
||||
this.find('input[name="width"]').value = pen.dataset.value;
|
||||
}
|
||||
|
||||
onBusPing(event) {
|
||||
let payload = {
|
||||
uid: app.User.identity.uuid,
|
||||
name: app.User.identity.firstname + ' ' + app.User.identity.lastname
|
||||
}
|
||||
|
||||
app.MessageBus.sendEvent(this.options.busChannel,'board_join', payload);
|
||||
}
|
||||
|
||||
joinApp() {
|
||||
let payload = {
|
||||
uid: app.User.identity.uuid,
|
||||
name: app.User.identity.firstname + ' ' + app.User.identity.lastname
|
||||
}
|
||||
|
||||
app.MessageBus.sendEvent(this.options.busChannel,'board_join', payload);
|
||||
}
|
||||
|
||||
leaveApp() { app.MessageBus.sendEvent(this.options.busChannel,'board_leave'); }
|
||||
|
||||
pingUsers() {
|
||||
this.busUsers = [];
|
||||
|
||||
let container = this.find('.users');
|
||||
container.innerHTML = '';
|
||||
|
||||
app.MessageBus.sendEvent(this.options.busChannel,'board_ping');
|
||||
}
|
||||
|
||||
refreshUsers() {
|
||||
let container = this.find('.users');
|
||||
console.log('', this.busUsers)
|
||||
for(let user of this.busUsers) {
|
||||
if(!user.tag) {
|
||||
let tag = new Chip(null, {
|
||||
label: user.name,
|
||||
icon: 'icon-edit',
|
||||
size: 'small',
|
||||
severity: 'secondary'
|
||||
});
|
||||
container.append(tag.el)
|
||||
user.tag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBusDraw(chan, payload, sender) {
|
||||
|
||||
/*
|
||||
for(let item of this.busUsers) {
|
||||
item.tag.severity = 'secondary';
|
||||
}
|
||||
|
||||
let user = this.busUsers.find(item => item.uid == payload.uid);
|
||||
user.tag.severity = 'primary';
|
||||
*/
|
||||
this.draw(payload.brush, payload.from, payload.to);
|
||||
}
|
||||
|
||||
onBusClear(chan, payload, sender) { this.clear(); }
|
||||
|
||||
onBusJoin(chan, payload, sender) {
|
||||
let user = payload;
|
||||
let index = this.busUsers.findIndex(item => item.uid == user.uid);
|
||||
console.log('index', index, this.busUsers)
|
||||
console.log('user', user)
|
||||
if(index == -1) {
|
||||
this.busUsers.push(user);
|
||||
this.refreshUsers();
|
||||
}
|
||||
}
|
||||
|
||||
onBusLeave(chan, payload, sender) { this.pingUsers(); }
|
||||
|
||||
onBoardDownload(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
let data = this.board.toDataURL('image/png');
|
||||
|
||||
let link = document.createElement('a');
|
||||
link.download = 'chalkboard.png';
|
||||
link.href = data;
|
||||
link.click();
|
||||
}
|
||||
|
||||
onBoardClear(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
if(this.useBus) {
|
||||
app.MessageBus.sendEvent(this.options.busChannel,'board_clear', {});
|
||||
} else {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.registerClass('ChalkboardView',ChalkboardView);
|
||||
@@ -0,0 +1,73 @@
|
||||
<style>
|
||||
|
||||
|
||||
.component-lab [eicstatechart] {
|
||||
height: 320px;
|
||||
}
|
||||
|
||||
.component-lab { }
|
||||
.component-lab textarea {
|
||||
height: 240px;
|
||||
font-family: monospace;
|
||||
}
|
||||
.component-lab { }
|
||||
</style>
|
||||
<article eiccard class="component-lab">
|
||||
<header>
|
||||
<h1>Components Forge</h1>
|
||||
<h2>Current: Relation Map</h2>
|
||||
</header>
|
||||
<section>
|
||||
<div eicstatechart class="relation-map"></div>
|
||||
<div class="cols-2">
|
||||
<div>
|
||||
<label xsmall>config</label>
|
||||
<textarea eictextarea name="config">
|
||||
{
|
||||
"orientation": "linear",
|
||||
"resizable": true,
|
||||
"allowDrag": true,
|
||||
"entity": {
|
||||
"width": 180,
|
||||
"height": 80,
|
||||
"gap": 40
|
||||
}
|
||||
}
|
||||
</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label xsmall>data</label>
|
||||
<textarea eictextarea name="data">
|
||||
{
|
||||
"entities": [
|
||||
{
|
||||
"title": "Entity 1",
|
||||
"severity": "info"
|
||||
},
|
||||
{
|
||||
"title": "Entity 2",
|
||||
"subtitle": "has an id value of 2",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"test": "some value"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Entity 3",
|
||||
"subtitle": "has an id value of 3",
|
||||
"badge": 42,
|
||||
"data": {
|
||||
"id": 3,
|
||||
"test": "some value"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cols-1 right">
|
||||
<button eicbutton xsmall primary class="button-update">update</button>
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
@@ -0,0 +1,37 @@
|
||||
class ComponentLabView extends EICDomContent {
|
||||
|
||||
|
||||
|
||||
DOMContentLoaded() {
|
||||
this.components = ui.eicfy(this.el);
|
||||
|
||||
this.tConfig = this.components.find(c => c.el.name == 'config');
|
||||
this.tData = this.components.find(c => c.el.name == 'data');
|
||||
this.btReset = this.components.find(c => c.el.classList.contains('button-update'));
|
||||
|
||||
this.reset(JSON.parse(this.tConfig.value), JSON.parse(this.tData.value));
|
||||
|
||||
this.btReset.addEventListener('click', this.onReset.bind(this));
|
||||
}
|
||||
|
||||
onReset(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
this.reset(JSON.parse(this.tConfig.value), JSON.parse(this.tData.value));
|
||||
}
|
||||
|
||||
reset(config, data) {
|
||||
this.map = new StateChart(this.find('.relation-map'), config)
|
||||
|
||||
this.map.data = data;
|
||||
this.map.click = this.testBadge.bind(this)
|
||||
}
|
||||
|
||||
testBadge(entity) {
|
||||
entity.badge = 23
|
||||
}
|
||||
}
|
||||
|
||||
app.registerClass('ComponentLabView',ComponentLabView);
|
||||
|
||||
Executable
+212
@@ -0,0 +1,212 @@
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Fugaz+One&display=swap');
|
||||
:root {
|
||||
--smp-global-background: #dcd4bc;
|
||||
--smp-global-color: #503333;
|
||||
}
|
||||
.sampler-app > header { background: url('/app/assets/images/cards/lab-sampler.jpg'); }
|
||||
.sampler-app section {
|
||||
border: none;
|
||||
background: var(--smp-global-background);
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.sampler-app .speaker {
|
||||
color: black;
|
||||
height: 340px;
|
||||
min-width: 340px;
|
||||
width: 340px;
|
||||
border: 7px solid rgb(0 0 0 / 5%);
|
||||
padding: 20px;
|
||||
display: grid;
|
||||
margin: 0 40px 0 0;
|
||||
border-radius: 18px;
|
||||
}
|
||||
[device="tablet"] .sampler-app .speaker,
|
||||
[device="mobile"] .sampler-app .speaker {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sampler-app .speaker .hole {
|
||||
background-color: black;
|
||||
border-radius: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.sampler-app .speaker .stripes {
|
||||
color: black;
|
||||
background-image: linear-gradient(0deg, var(--smp-global-background) 60%, black 1%, black 10%, #0000003b 25%);
|
||||
background-size: 1px 23px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
.sampler-app .pads {
|
||||
display: flex;
|
||||
grid-gap: var(--eicui-base-spacing-l);
|
||||
flex-flow: wrap;
|
||||
}
|
||||
.sampler-app .pads .pad {
|
||||
display: grid;
|
||||
grid-template-rows: auto min-content;
|
||||
grid-template-columns: min-content auto;
|
||||
grid-gap: 4px;
|
||||
flex: 1;
|
||||
min-width: 100px;
|
||||
max-width: 140px;
|
||||
}
|
||||
.sampler-app .pads .pad kbd {
|
||||
align-self: flex-end;
|
||||
justify-self: center;
|
||||
color: white;
|
||||
background: var(--smp-global-color);
|
||||
padding: 6px 11px;
|
||||
border-radius: 5px;
|
||||
font-size: 0.95rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.sampler-app .pads .pad button {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 2px solid black;
|
||||
grid-column: 1 / 3;
|
||||
border-radius: 6px;
|
||||
padding: 0;
|
||||
box-shadow: 1px 4px 4px #0000007d;
|
||||
min-height: 40px;
|
||||
}
|
||||
.sampler-app .pads .pad button.assigned:hover span {
|
||||
border-color: orange !important;
|
||||
}
|
||||
.sampler-app .pads .pad button span {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #404040;
|
||||
border: 8px solid #59402c;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.sampler-app .pads .pad button.assigned span { border: 3px solid #b77c4c; }
|
||||
.sampler-app .pads .pad button.playing span { border: 3px solid #93f795; }
|
||||
.sampler-app .pads .pad label {
|
||||
color: #ffffffc4;
|
||||
background: var(--smp-global-color);
|
||||
padding: 8px 3px 8px 10px;
|
||||
margin: 3px 0 0 0;
|
||||
text-transform: uppercase;
|
||||
font-family: 'Fugaz One', cursive;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 0.75rem;
|
||||
align-content: center;
|
||||
}
|
||||
.sampler-app footer {
|
||||
background-color: rgba(0, 0, 0, 0.168);
|
||||
grid-area: footer;
|
||||
border-top: 4px solid #ffffff61;
|
||||
}
|
||||
</style>
|
||||
<article eiccard media class="sampler-app">
|
||||
<header>
|
||||
<h1>CARMELOMATIC<sup>®</sup></h1>
|
||||
<h2>SAMPLER 3000</h2>
|
||||
</header>
|
||||
<section>
|
||||
|
||||
<div class="speaker">
|
||||
<div class="hole"></div>
|
||||
<div class="stripes"></div>
|
||||
</div>
|
||||
<!---->
|
||||
<div class="pads">
|
||||
<div class="pad">
|
||||
<button accesskey="e"><span></span></button>
|
||||
<kbd>e</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="r"><span></span></button>
|
||||
<kbd>r</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="t"><span></span></button>
|
||||
<kbd>t</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="y"><span></span></button>
|
||||
<kbd>y</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="d"><span></span></button>
|
||||
<kbd>d</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="f"><span></span></button>
|
||||
<kbd>f</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="g"><span></span></button>
|
||||
<kbd>g</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="h"><span></span></button>
|
||||
<kbd>h</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="c"><span></span></button>
|
||||
<kbd>c</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="v"><span></span></button>
|
||||
<kbd>v</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="b"><span></span></button>
|
||||
<kbd>b</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="n"><span></span></button>
|
||||
<kbd>n</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="u"><span></span></button>
|
||||
<kbd>u</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="i"><span></span></button>
|
||||
<kbd>i</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="o"><span></span></button>
|
||||
<kbd>o</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="p"><span></span></button>
|
||||
<kbd>p</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="j"><span></span></button>
|
||||
<kbd>j</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="k"><span></span></button>
|
||||
<kbd>k</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="l"><span></span></button>
|
||||
<kbd>l</kbd><label for="button"></label>
|
||||
</div>
|
||||
<div class="pad">
|
||||
<button accesskey="m"><span></span></button>
|
||||
<kbd>m</kbd><label for="button"></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</article>
|
||||
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
class SamplerView extends EICDomContent {
|
||||
// all mpeg preloading not in dependency anymore,
|
||||
// but here, when you're really about to use then
|
||||
|
||||
sounds = [
|
||||
{"name": "98.mp3","path": "/app/assets/sfx/sampler/", 'label': '98'},
|
||||
{"name": "quenouilles.mp3","path": "/app/assets/sfx/sampler/", 'label': 'As-tu vu?'},
|
||||
{"name": "celebrate.mp3","path": "/app/assets/sfx/sampler/", 'label': 'party'},
|
||||
{"name": "paillettes.mp3","path": "/app/assets/sfx/sampler/", 'label': 'paillettes'},
|
||||
{"name": "manu.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Manu'},
|
||||
{"name": "projet.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Projet'},
|
||||
{"name": "judgenot.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Judge not!'},
|
||||
{"name": "metaphore.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Metaphore'},
|
||||
{"name": "gamin.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Gamin!'},
|
||||
{"name": "jcvd.mp3","path": "/app/assets/sfx/sampler/", 'label': '1+1=11'},
|
||||
{"name": "balladur.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Arretez!'},
|
||||
{"name": "guingamp.mp3","path": "/app/assets/sfx/sampler/", 'label': 'En avant !'},
|
||||
{"name": "phrases.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Phrases...'},
|
||||
{"name": "bourpif.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Raoul'},
|
||||
{"name": "fairplay.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Fairplay'},
|
||||
{"name": "neanderthal.mp3","path": "/app/assets/sfx/sampler/", 'label': 'Neanderthal'},
|
||||
{"name": "hassancehef.mp3","path": "/app/assets/sfx/sampler/", 'label': 'C\'est possible !'}
|
||||
];
|
||||
|
||||
mixer = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
DOMContentLoaded() {
|
||||
this.pads = this.findAll('.pad');
|
||||
this.init();
|
||||
this.preloadSounds(this.sounds);
|
||||
}
|
||||
|
||||
DOMContentRemoved() { window.removeEventListener('keyup',this.keyHandler); }
|
||||
|
||||
init() {
|
||||
for(let i = 0; i < this.sounds.length; i++) {
|
||||
let data = this.sounds[i];
|
||||
this.pads[i].name = data.name;
|
||||
this.pads[i].querySelector('label').innerText = data.label;
|
||||
let button = this.pads[i].querySelector('button');
|
||||
button.addEventListener('click', this.play.bind(this, data.name));
|
||||
}
|
||||
this.keyHandler = this.onKeyPressed.bind(this);
|
||||
window.addEventListener('keyup', this.keyHandler);
|
||||
}
|
||||
|
||||
preloadSounds(sndList){
|
||||
for(let snd of sndList){
|
||||
app.Assets.loadSound({
|
||||
'id': snd.name,
|
||||
'name': snd.name,
|
||||
'path': snd.path
|
||||
}).then(audioEl => {
|
||||
audioEl.addEventListener("play", this.playBoy.bind(this));
|
||||
audioEl.addEventListener("pause", this.pauseBoy.bind(this));
|
||||
let pad, idx;
|
||||
for([idx, pad] of this.pads.entries()){
|
||||
if(pad.name==audioEl.getAttribute('aid')) {
|
||||
pad.querySelector('button').classList.add('assigned');
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
playBoy(event){
|
||||
let aid = event.target.getAttribute('aid');
|
||||
let pad, idx;
|
||||
for([idx, pad] of this.pads.entries()){
|
||||
if(pad.name==aid) {
|
||||
pad.querySelector('button').classList.remove('assigned')
|
||||
pad.querySelector('button').classList.add('playing');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pauseBoy(event){
|
||||
let aid = event.target.getAttribute('aid');
|
||||
let pad, idx;
|
||||
for([idx, pad] of this.pads.entries()){
|
||||
if(pad.name==aid) {
|
||||
pad.querySelector('button').classList.remove('playing')
|
||||
pad.querySelector('button').classList.add('assigned');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
play(audioid, event) {
|
||||
event.stopPropagation();
|
||||
|
||||
if(this.mixer) {
|
||||
this.mixer.pause();
|
||||
this.mixer.currentTime = 0;
|
||||
}
|
||||
this.mixer = app.Assets.Store.sfx[audioid];
|
||||
this.mixer.play();
|
||||
}
|
||||
|
||||
stop() {}
|
||||
|
||||
onKeyPressed(event) {
|
||||
let btn = document.querySelector('button[accessKey="'+event.key.toLowerCase()+'"]');
|
||||
if(btn) btn.click();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.registerClass('SamplerView',SamplerView);
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
<article eiccard>
|
||||
<header>
|
||||
<h1>Form test</h1>
|
||||
</header>
|
||||
<section class="form">
|
||||
<input type="hidden" data-path="pathAnd" name="name" value="done" />
|
||||
<input type="hidden" name="nameOnly" value="done" />
|
||||
<input type="hidden" data-path="pathonly" value="done" />
|
||||
<input type="hidden" data-path="ignoredField" class="ignore" value="Mutafuka! your snooping to much" />
|
||||
<input type="hidden" data-path="basearray[0]" value="a" />
|
||||
<input type="hidden" data-path="basearray[1]" value="b" />
|
||||
<input type="hidden" data-path="arrayOfObjects[0].value" data-type="number" value="100" />
|
||||
<input type="hidden" data-path="arrayOfObjects[0].label" value="aa" />
|
||||
<input type="hidden" data-path="arrayOfObjects[1].value" data-type="number" value="200.45" />
|
||||
<input type="hidden" data-path="arrayOfObjects[1].label" value="bb" />
|
||||
<input type="hidden" data-path="arrayOfObjects[2].value" data-type="number" value="300" />
|
||||
<input type="hidden" data-path="arrayOfObjects[2].label" value="cc" />
|
||||
<input type="hidden" data-path="boolean" data-type="boolean" value="true" />
|
||||
|
||||
<textarea data-path="justification.description" eictextarea maxlen="200"
|
||||
hint="No more than 200 characters please."
|
||||
placeholder="Please type some words..."></textarea>
|
||||
|
||||
<label>pick some values</label>
|
||||
<select eicselect multiple data-path="justification.programme" placeholder="Please select a programme...">
|
||||
<option value=""></option>
|
||||
<option value="1">PRG1</option>
|
||||
<option value="2">PRG2</option>
|
||||
<option value="3">PRG3</option>
|
||||
</select>
|
||||
|
||||
<input eiccheckbox type="checkbox" data-path="justification.independentExpert" label="You confirm that you have relied on independent external experts to perform the project review" value="yes" />
|
||||
<input eiccheckbox type="checkbox" class="ignore" data-path="justification.compliance" label="You confirm that you have complied with all the conditions and requirements set out for Fast Track scheme" />
|
||||
|
||||
</section>
|
||||
<section primary>
|
||||
<label>JSON output</label>
|
||||
<textarea eictextarea class="output"></textarea>
|
||||
</section>
|
||||
<footer>
|
||||
<div class="cols-2 right">
|
||||
<div></div>
|
||||
<button eicbutton primary class="generate">output form</button>
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
class TestView extends EICDomContent {
|
||||
|
||||
constructor() { super(); }
|
||||
|
||||
DOMContentLoaded() {
|
||||
ui.eicfy(this.el)
|
||||
|
||||
let form = new Form(this.find('.form'));
|
||||
let output = this.find('.output')
|
||||
this.find('.generate').addEventListener('click', event => { output.value = JSON.stringify(form.value) });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.registerClass('TestView',TestView);
|
||||
Reference in New Issue
Block a user