Skip to content

Commit

Permalink
New UI: get values from server and generate for Live Server
Browse files Browse the repository at this point in the history
mainnav
- rename addHTML to createHTML
- store activeModuleId
- secondary menu, use querySelectorAll to set selected
- set activeModuleType: call updateSecondaryMenu
- use controller.modules.model
- add updateMainMenu and updateSecondaryMenu
- updateUI retrieve activeModuleId

module.js -> modules.js
- class Modules
- model, createHTML, addModule, walkthroughModel, generateData, findVar, varJsonToClass in class
- class Variable and subclasses

newui.js
- add this.modules
- fetchModelForLiveServer (Live Server): generate data each second
- makeWS: use this.
- add requestJson
- add receiveData
- add utility isObject
  • Loading branch information
ewoudwijma committed Aug 4, 2024
1 parent 864477f commit ffeb1a9
Show file tree
Hide file tree
Showing 9 changed files with 1,304 additions and 1,008 deletions.
89 changes: 58 additions & 31 deletions data/mainnav.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*/
class MainNav {

addHTML() {
createHTML() {
let body = document.getElementById("body");//gId("body");

body.classList += "d-flex flex-column";
Expand Down Expand Up @@ -83,6 +83,8 @@ class MainNav {

this.#activeModuleJson = moduleJson

localStorage.setItem('activeModuleId', moduleJson.id);

// Update the main navigation
document.querySelectorAll('#main-nav .menu-item').forEach(menuItem => {
if (menuItem.dataset.type == this.#activeModuleJson.type) {
Expand All @@ -92,19 +94,17 @@ class MainNav {
}
})

// Update the secondary navigation menu
const modules = controller.model.filter(moduleJson => moduleJson.type == this.#activeModuleJson.type)

const html = modules
.map(moduleJson => {
const selected = moduleJson.id == this.#activeModuleJson.id ? 'selected' : ''
return `<div onclick="controller.mainNav.activeModuleId=this.dataset.id" class="menu-item selectable ${selected} text-truncate pa-3" data-id="${moduleJson.id}">${moduleJson.id}</div>`
})
.join('')
document.getElementById('second-nav').innerHTML = html
// Update the secondary navigation
document.querySelectorAll('#second-nav .menu-item').forEach(menuItem => {
if (menuItem.dataset.id == this.#activeModuleJson.id) {
menuItem.classList.add('selected')
} else {
menuItem.classList.remove('selected')
}
})

// Update the page content
// TODO: Real code needed, for now, just dump out the JSON with a header
// TODO: Real code needed: done: this.#moduleFun
if (this.#moduleFun) {
document.getElementById('page').innerHTML =
`<div class="d-flex flex-column h-100 overflow-hidden">
Expand All @@ -120,45 +120,72 @@ class MainNav {
/**
* Set the active module to the first one in the module list whose type matches
* @param {string} moduleType - The module type
* triggered by menu onclick
*/
set activeModuleType(moduleType) {
this.activeModuleJson = controller.model.find(moduleJson => moduleJson.type == moduleType)
this.activeModuleJson = controller.modules.model.find(moduleJson => moduleJson.type == moduleType)
this.#updateSecondaryMenu();
}

/**
* Set the active module to the module specified by the id
* @param {string} id - The module id
* triggered by menu onclick
*/
set activeModuleId(id) {
this.activeModuleJson = controller.model.find(moduleJson => moduleJson.id == id)
this.activeModuleJson = controller.modules.model.find(moduleJson => moduleJson.id == id)
}

/**
* Update the UI
*/
//updateUI is made after all modules have been fetched, how to adapt to add one module?
updateUI(moduleJson, fun) {

this.#moduleFun = fun

// Get the unique list of module types
const uniqueTypes = controller.model
.filter((moduleJson, index, modules) => {
return modules.findIndex(m => m.type === moduleJson.type) === index
})
.map(moduleJson => moduleJson.type)
// Get the unique list of module types
#updateMainMenu() {
const uniqueTypes = controller.modules.model
.filter((moduleJson, index, modules) => {
return modules.findIndex(m => m.type === moduleJson.type) === index
})
.map(moduleJson => moduleJson.type)

// Each module type becomes a top level menu
const html = uniqueTypes
.map(type => {
return `<div onclick="controller.mainNav.activeModuleType=this.dataset.type" class="menu-item selectable pa-4" data-type="${type}">${type}</div>`
const selected = type == this.#activeModuleJson.type ? 'selected' : ''
return `<div onclick="controller.mainNav.activeModuleType=this.dataset.type" class="menu-item selectable ${selected} pa-4" data-type="${type}">${type}</div>`
})
.join('')
document.getElementById('main-nav').innerHTML = html
}

// Update the secondary navigation menu
#updateSecondaryMenu() {
const modules = controller.modules.model.filter(moduleJson => moduleJson.type == this.#activeModuleJson.type)

const html = modules
.map(moduleJson => {
const selected = moduleJson.id == this.#activeModuleJson.id ? 'selected' : ''
return `<div onclick="controller.mainNav.activeModuleId=this.dataset.id" class="menu-item selectable ${selected} text-truncate pa-3" data-id="${moduleJson.id}">${moduleJson.id}</div>`
})
.join('')
document.getElementById('second-nav').innerHTML = html
}

/**
* Update the UI
*/
//updateUI is made after all modules have been fetched, how to adapt to add one module?
updateUI(moduleJson, fun) {

this.#moduleFun = fun //sets the function which displays a module

this.#updateMainMenu();
this.#updateSecondaryMenu();

let activeModuleId = localStorage.getItem('activeModuleId');
if (moduleJson.id == activeModuleId) {
this.activeModuleJson = moduleJson //set triggered
}

// If there is no active module set it to the first one
if (this.#activeModuleJson == '' && controller.model.length) {
this.activeModuleJson = controller.model[0]
if (activeModuleId == null && this.#activeModuleJson == '' && controller.modules.model.length) {
this.activeModuleJson = controller.modules.model[0]
}
}

Expand Down
27 changes: 0 additions & 27 deletions data/module.js

This file was deleted.

2 changes: 1 addition & 1 deletion data/module.css → data/modules.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
@title StarBase
@file module.css
@file modules.css
@date 20240720
@repo https://github.com/ewowi/StarBase, submit changes to this file as PRs to ewowi/StarBase
@Authors https://github.com/ewowi/StarBase/commits/main
Expand Down
165 changes: 165 additions & 0 deletions data/modules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// @title StarBase
// @file modules.js
// @date 20240720
// @repo https://github.com/ewowi/StarBase, submit changes to this file as PRs to ewowi/StarBase
// @Authors https://github.com/ewowi/StarBase/commits/main
// @Copyright © 2024 Github StarBase Commit Authors
// @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
// @license For non GPL-v3 usage, commercial licenses must be purchased. Contact [email protected]

class Modules {

model = [] //model.json (as send by the server), used by FindVar

//generates html for a module
//for some strange reason, this method does not accept this.otherMethodInThisClass ???
createHTML(moduleJson) {
let code = ""
controller.modules.test("ew")
// this.test("ew") //this.otherMethodInThisClass: [Error] Unhandled Promise Rejection: TypeError: this.test is not a function. (In 'this.test("ew")', 'this.test' is undefined)
for (let variable of moduleJson.n) {

let variableClass = varJsonToClass(variable);
code += variableClass.createHTML()

if (variable.fun >= 0) { //>=0 as element in var

let command = {};
command.onUI = [variable.id];
// console.log("flushOnUICommands", command);
controller.requestJson(command);

variable.fun = -1; //requested
}
}
code += '<pre>' + JSON.stringify(moduleJson, null, 2) + '</pre>'
return code
}

//temporary to test issue above
test(name) {
console.log(name)
}

//used by fetchModel and by makeWS
addModule(moduleJson) {
this.model.push(moduleJson);

//updateUI is made after all modules have been fetched, how to adapt to add one module?
controller.mainNav.updateUI(moduleJson, this.createHTML); //moduleFun returns the html to show in the module panel of the UI
//still doesn't maker sense to call updateUI for every module ...
}

//walkthrough, if a variable is returned by fun, it stops the walkthrough with this variable
walkThroughModel(fun, parent = this.model) {
for (var variable of parent) {
let foundVar = null
foundVar = fun(variable);

if (foundVar) return foundVar;

if (variable.n) {
foundVar = this.walkThroughModel(fun, variable.n); //recursive
if (foundVar) return foundVar;
}
}
}

//loop through the model hierarchy and generateData data for each variable in the model
generateData() {
this.walkThroughModel(function(variable) {
let variableClass = varJsonToClass(variable);
variableClass.generateData();
})
}

//finds a var with id in the model, if found returns it
findVar(id) {
// console.log("findVar", id, parent, model);
return this.walkThroughModel(function(variable){
if (variable.id == id) //found variable
return variable; //this stops the walkThrough
})

}

} //class Modules

//see this.otherMethodInThisClass, should be moved in Modules class
//creates the right class based on variable.type
function varJsonToClass(variable) {
switch (variable.type) {
case "progress":
return new ProgressVariable(variable);
case "text":
return new TextVariable(variable);
case "select":
return new SelectVariable(variable);
default:
return new Variable(variable);
}
}

class Variable {

constructor(variable) {
this.variable = variable
this.node = document.getElementById(variable.id);
}

createHTML() { //base
return `<p>
<label>${this.variable.id}</label>
<input id=${this.variable.id} type=${this.variable.type} class="${this.variable.type}" value="${this.variable.value}"></input>
<p>`

}

//sets the value of the node to value of properties
receiveData(properties) { //base
if (this.node && properties.value)
this.node.value = properties.value;
}

generateData() {
controller.receiveData(JSON.parse(`{"${this.variable.id}":{"value":${Math.random() * 1000}}}`));
}

} //class Variable

class ProgressVariable extends Variable {

createHTML() { //override
return `<p>
<label>${this.variable.id}</label>
<progress max="${this.variable.max}" id="${this.variable.id}" class="progress"></progress>
<p>`
}
} //class ProgressVariable

class SelectVariable extends Variable {

createHTML() { //override
return `<p>
<label>${this.variable.id}</label>
<select max="${this.variable.max}" id="${this.variable.id}" class="select"></select>
<p>`
}

generateData() {
//add sample options
if (this.node && this.node.childNodes.length == 0)
this.node.innerHTML+='<option value=0>One</option><option value=1>Two</option><option value=2>Three</option>'

controller.receiveData(JSON.parse(`{"${this.variable.id}":{"value":${Math.random() <.33?0:Math.random() <.66?1:2}}}`));
}

} //class SelectVariable

class TextVariable extends Variable {

generateData() {
controller.receiveData(JSON.parse(`{"${this.variable.id}":{"value":"${Math.random().toString(36).slice(2)}"}}`));
}

} //class TextVariable
4 changes: 2 additions & 2 deletions data/newui.htm
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
<link rel="stylesheet" href="theme.css">
<script src="mainnav.js"></script>
<link rel="stylesheet" href="mainnav.css">
<script src="module.js"></script>
<link rel="stylesheet" href="module.css">
<script src="modules.js"></script>
<link rel="stylesheet" href="modules.css">
</head>
<body id="body" onload="controller.onLoad()"></body>
</html>
Loading

0 comments on commit ffeb1a9

Please sign in to comment.