Compare commits

25 Commits

Author SHA1 Message Date
858bfef1bb Change how the text menu works. It is somewhat behind in that it does
not have all the same old functionality, but it uses menuitems now.
This will allow us to much-better utilize the textwindows.
2024-06-14 16:01:41 -05:00
deb5f29cee Changed some spaces to tabs. Happened automatically. 2024-06-11 09:22:13 -05:00
9aa26b82c6 make drawshape work better 2024-06-06 14:16:01 -07:00
726bafe580 Change drawshape to be drawhighlight as we pass it a highlight. 2024-06-06 13:59:59 -07:00
80c1abd5fe Trying to add a .editorconfig file for the Visual Studio editor. Visual
Studio keeps messing up the crlf.  Since I will mainly host this from a
Linux server, I want it to be just lf.
2024-06-03 15:41:16 -07:00
5ce6dc6d3e Moved actionStruct to be a class. Better that way 2024-05-31 17:12:00 -07:00
bf2e281c40 Use the translated version of the puzzle description. 2024-05-17 16:06:03 -06:00
98733d1ad5 Get basic problem translations. Ping only for now 2024-05-17 15:37:31 -06:00
0859bffc23 Put a selection-box around an item if we clicked on something 2024-05-17 10:33:33 -06:00
9be833dd2c Brought over the language strings from edunetworkbuilder and functions
for making language translation work.
2024-05-17 10:06:07 -06:00
0e9a6d1a15 Fixed a bug where clicking on a line would change how things were
viewed.  It turned out to be a rather bizarre bug based off of !== null
not working properly.
2024-05-16 12:13:41 -06:00
3e902cba95 Devices with problems properly have red background 2024-05-15 17:06:48 -06:00
77b034f845 Highlight items that have problems. 2024-05-10 15:03:52 -06:00
f3ed276ca9 Fixed not clearing the old highlights when we moused-off something. 2024-05-10 11:23:10 -06:00
7b57cbe97a Changing the highlight system to something that works for more cases.
We will highlight devices with problems and other things.
2024-05-10 11:00:42 -06:00
ee0a3f9255 Visual Studio complained about some of my tags in the index.html. So I
cleaned up what it was complaining about.
2024-05-10 09:22:50 -06:00
a19cb99b9d Getting it so we can click on devices. Mainly figuring stuff out.
Committing now because I am about to drive off and I want to have the
code-base up to date before I travel.
2024-04-30 17:38:31 -05:00
6119432875 Added lines to separate out portions of the screen. Also, I think ui.js
updated its crlfs.
2024-04-30 11:14:23 -05:00
84685e3bd4 Added a thumbs-up image to be used in a bit. Saw the visual studio
editor was madly messing up crlf and whatnot.  Changed it to be lf since
that is what we had started with.
2024-04-30 10:58:44 -05:00
d7f73f04d8 Most of the mouse-over highlighting is working properly 2024-04-27 13:39:36 -05:00
50b4843d76 Get highlights working (mostly) 2024-04-25 14:47:54 -05:00
b978a3abb0 Make the start of an action click system 2024-04-24 16:52:27 -05:00
4ec5b370e9 Able to click on the eye and toggle the view 2024-04-22 15:37:28 -05:00
50099ee4ef Properly showing device names and IPs. 2024-04-22 15:32:10 -05:00
df520fcce6 Get the name to display under the network devices 2024-04-22 13:09:44 -05:00
12 changed files with 10277 additions and 270 deletions

4
Web/.editorconfig Normal file
View File

@ -0,0 +1,4 @@
root = true
[*]
end_of_line = lf

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
Web/img/thumb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@ -25,12 +25,13 @@
</form>
-->
<canvas id='MainCanvas' width='700 ' height='400' style="border:1px solid #000000;">
<canvas id='MainCanvas' width='700 ' height='400' style="border:1px solid #000000;"></canvas>
<script src="allpuzzles.js"></script>
<script src="selectmenu.js"></script>
<script src="network.js"></script>
<script src="textwindow.js"></script>
<script src="language.js"></script>
<script src="ui.js"></script>
</body>
</html>

3995
Web/language.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
//This file contains the information about the puzzle (network)
//Each puzzle is stored in the allpuzzles variable. We need to select one and use it
//We define this here, even though it is used primarily in the UI. We define its values here
var ui_helplevel = 0;
var puzzle=networkFromName("Level0-Ping");
//var puzzle=networkFromName("Level0-NeedsLink");
//var puzzle=networkFromName("Level0_NetworkLoop");
@ -26,32 +30,126 @@ function switchPuzzle(target)
function networkFromName(what)
{
let index=0;
while (index < allpuzzles.length) {
let index=0;
while (index < allpuzzles.length) {
//console.log(allpuzzles[index].EduNetworkBuilder.Network.name);
if(allpuzzles[index].EduNetworkBuilder.Network.name == what)
{
console.log("Found " + what + " at index " + index);
return structuredClone(allpuzzles[index].EduNetworkBuilder.Network);
console.log("Found " + what + " at index " + index);
return networkFromIndex(index);
}
index++;
}
}
}
function networkFromIndex(what)
{
if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){
return structuredClone(allpuzzles[what].EduNetworkBuilder.Network);
if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){
var newitem = structuredClone(allpuzzles[what].EduNetworkBuilder.Network);
console.log("It is an array:" + Array.isArray(newitem.nettest));
if (!Array.isArray(newitem.nettest)) {
var oneitem = newitem.nettest; //this is an object
newitem.nettest = [];
newitem.nettest.push(oneitem); //make it an one-item array.
}
//Set the help level to be whatever we need
if (newitem.startinghelplevel == "full") ui_helplevel = 3;
if (newitem.startinghelplevel == "hints") ui_helplevel = 2;
if (newitem.startinghelplevel == "basic") ui_helplevel = 1;
if (newitem.startinghelplevel == "none") ui_helplevel = 0;
console.log("Starting help level = " + ui_helplevel + " from " + newitem.startinghelplevel);
return newitem;
}
return null;
}
function deviceHasProblem(Device) {
var hostname = Device.hostname;
//console.log("Looking for tests on " + hostname + " and have: " + puzzle.nettest.length)
for (var index = 0; index < puzzle.nettest.length; index++) {
//console.log("Found test: " + JSON.stringify(puzzle.nettest));
if (puzzle.nettest[index].shost == hostname) {
if (puzzle.nettest[index].solved == null) {
//It has not yet been solved.
//console.log("Found problem on device: " + hostname);
return true;
}
}
}
return false;
}
function problemString(nettest) {
if (nettest == null) return "";
//The structure of a nettest
//"shost": "pc0",
//"dhost": "laptop0",
//"thetest": "SuccessfullyPings"
//if (ui_helplevel == 0) setStatus("There is a disturbance in the force. Guessing...");
//if (ui_helplevel == 1) setStatus("Service check detected a problem.");
//if (ui_helplevel == 2) setStatus("Someone submitted a trouble ticket.");
//if (ui_helplevel == 3) setStatus("Interviewed users for detailed info.");
switch (nettest.thetest) {
case "DHCPServerEnabled":
case "DeviceBlowsUpWithPower":
case "DeviceIsFrozen":
case "DeviceNeedsUPS":
case "FailedPing":
case "HelpRequest":
case "LockAll":
case "LockLocation":
case "LockNic":
case "LockVLANNames":
case "LockVLANsOnHost":
case "NeedsDefaultGW":
case "NeedsLinkToDevice":
case "NeedsLocalIPTo":
case "NeedsRouteToNet":
case "NeedsTaggedVLAN":
case "ReadContextHelp":
break;
case "SuccessfullyPings":
//level 0 is handled elsewhere
if (ui_helplevel == 2) return translator.getStr("NT_TstDiscriptPing");
if (ui_helplevel == 3) return translator.getStr("NT_TstDiscriptPing2") + nettest.dhost;
case "SuccessfullyPingsWithoutLoop":
case "SuccessfullyTraceroutes":
break;
}
return "";
}
function returnProblemStrings(Device) {
var hostname = Device.hostname;
var errors = [];
//console.log("Looking for tests on " + hostname + " and have: " + puzzle.nettest.length)
for (var index = 0; index < puzzle.nettest.length; index++) {
//console.log("Found test: " + JSON.stringify(puzzle.nettest));
if (puzzle.nettest[index].shost == hostname) {
if (puzzle.nettest[index].solved == null) {
//It has not yet been solved.
var error = problemString(puzzle.nettest[index]);
//console.log("We got a problem string:" + JSON.stringify(error));
if (error != "");
errors.push(error);
}
}
}
return errors;
}
function networkNamesMatchingText(textToMatch)
{
var list = [];
var re = new RegExp(textToMatch);
let index=0;
while (index < allpuzzles.length) {
let index=0;
while (index < allpuzzles.length) {
//console.log(allpuzzles[index].EduNetworkBuilder.Network.name);
if(re.test(allpuzzles[index].EduNetworkBuilder.Network.name))
{
@ -59,30 +157,92 @@ function networkNamesMatchingText(textToMatch)
list.push(allpuzzles[index].EduNetworkBuilder.Network.name);
}
index++;
}
}
return list;
}
function deviceFromName(what)
{
if (puzzle == null) return null; //If the puzzle has not been set, return a null
if (puzzle == null) return null; //If the puzzle has not been set, return a null
let index=0;
while (index < puzzle.device.length) {
let index=0;
while (index < puzzle.device.length) {
if (puzzle.device[index].hostname == what) return puzzle.device[index]; //return the device that matches
index++;
}
return null; //No match. return a null value
}
return null; //No match. return a null value
}
function deviceFromID(what)
{
if (puzzle == null) return null; //If the puzzle has not been set, return a null
if (puzzle == null) return null; //If the puzzle has not been set, return a null
let index=0;
while (index < puzzle.device.length) {
let index=0;
while (index < puzzle.device.length) {
if (puzzle.device[index].uniqueidentifier == what) return puzzle.device[index]; //return the device that matches
index++;
}
return null; //No match. return a null value
}
return null; //No match. return a null value
}
//return a list of all the ip addresses a device has
function ipsFromDevice(what) {
var ipaddresses = [];
for (var i = 0; i < what.nic.length; i++) {
ipaddresses = ipaddresses.concat(ipsFromNic(what.nic[i]));
}
//console.log("Adding to nics " + ipaddresses.length);
return ipaddresses;
}
function ipsFromInterface(what, nictype) {
var ipaddresses = [];
if (typeof (what.myip) === "array") {
for (var x = 0; x < what.myip.length; x++) {
var one = {
nic: what.nicname,
ip: what.myip[x].ip,
mask: what.myip[x].mask,
cidrip: what.myip[x].ip + "/" + NetmaskToCIDR(what.myip[x].mask),
nictype: nictype,
};
ipaddresses.push(one);
}
}
else if (typeof (what.myip) === "object") {
var one = {
nic: what.nicname,
ip: what.myip.ip,
mask: what.myip.mask,
cidrip: what.myip.ip + "/" + NetmaskToCIDR(what.myip.mask),
nictype: nictype,
};
ipaddresses.push(one);
//console.log("found an ip object: " + JSON.stringify(one) + " " + nictype);
}
return ipaddresses;
}
function ipsFromNic(what) {
var ipaddresses = [];
//console.log("Looking at a nic: " + JSON.stringify(what));
if (typeof (what.interface) === "array") {
for (var i = 0; i < what.interface.length; i++) {
//console.log("Trying to add a nic." + what.interface[i].nicname);
ipaddresses=ipaddresses.concat(ipsFromInterface(what.interface[i],what.nictype[0]));
}
}
else if (typeof (what.interface) === "object")
ipaddresses=ipaddresses.concat(ipsFromInterface(what.interface, what.nictype[0]));
return ipaddresses;
}
function NetmaskToCIDR(mask) {
var cidr = 0;
var maskNodes = mask.match(/(\d+)/g);
for (var i in maskNodes) {
cidr += (((maskNodes[i] >>> 0).toString(2)).match(/1/g) || []).length;
}
return cidr;
}

View File

@ -0,0 +1,40 @@
#!/usr/bin/perl
opendir(Dir, "Resources") || die "Can't open Resources directory: $!\n";
@files = grep(/edustrings/,readdir(Dir));
closedir(Dir);
open ($outfile, '>', "language.js") or die $!;
print($outfile "language = {\n");
foreach $file (@files) {
$lang = $file;
$lang =~ s/edustrings.//;
$lang =~ s/.json//;
print($outfile " $lang : {\n");
open my $info, "Resources/$file" or die "Could not open $file: $!";
while( my $line = <$info>) {
chomp($line);
if ( $line =~ /name": "(.*)",$/)
{
print($outfile " $1 : {");
}
if ( $line =~ /value": "(.*)",$/)
{
print($outfile "$line\n");
}
if ( $line =~ /value": "(.*)"$/) #if there is no comment
{
print($outfile "$line\n },\n");
}
if ( $line =~ /comment": "(.*)"$/)
{
print($outfile " $line\n },\n");
}
}
print($outfile " },\n"); #End the language file;
}
print($outfile "];\n"); #End the language variable definition
close($outfile);

View File

@ -0,0 +1,25 @@
#!/bin/bash
#
# Convert the EduNetworkBuilder language files into json
# Run this from the web directory, and make sure to have xq installed
if which xq >/dev/null; then
if [ -d Resources -a -d EduResources/languages ]; then
for a in EduResources/languages/*.resx; do
c=$a;
if [ $a = "EduResources/languages/edustrings.resx" ]; then
c="edustrings.en.resx"
fi
b=$(basename $c | sed 's/.resx/\.json/');
#if [ ! -e Resources/languages/$b ]; then
echo $b
xq '.root.data' $a |sed 's/\@name/name/' | grep -v 'xml:space' > Resources/$b
#fi
done
else
echo "You must be in the web directory of the EduNetworkBuilder git repo for this to work"
fi
else
echo "xq must be installed. This comes with the jq program"
echo "jq is used for working with json files and xq is the counterpart"
echo "that converts xml to json."
fi

View File

@ -17,7 +17,7 @@ var menuItemSize=50;
function InitializeSelectMenu() {
cachedSelectMenuCanvas = document.createElement('canvas');
cachedSelectMenuCanvas.width = menuItemSize;
console.log("length= " + selectMenuNames.length);
//console.log("length= " + selectMenuNames.length);
cachedSelectMenuCanvas.height = menuItemSize * selectMenuNames.length;
var cSMCctx = cachedSelectMenuCanvas.getContext('2d');
var starty = 0;
@ -32,19 +32,19 @@ function InitializeSelectMenu() {
function drawSelectMenu()
{
//console.log("Printing on main canvass");
//console.log("Printing on main canvass");
MainCanvas_ctx.fillStyle = maincanvasBackground;
MainCanvas_ctx.fillRect(0, 0, menuItemSize, MainCanvas.height);
MainCanvas_ctx.fillStyle = maincanvasBackground;
MainCanvas_ctx.fillRect(0, 0, menuItemSize, MainCanvas.height);
if (selectedMenuYOffset < 0) selectedMenuYOffset = 0;
if (cachedSelectMenuCanvas == null) InitializeSelectMenu();//initialize it if not done yet
if(selectedMenuYOffset + MainCanvas.height > cachedSelectMenuCanvas.height) selectedMenuYOffset = cachedSelectMenuCanvas.height -MainCanvas.height;
MainCanvas_ctx.drawImage(cachedSelectMenuCanvas,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height);
let index = selectMenuNames.indexOf(selectedMenuItemName);
if(selectedMenuYOffset + MainCanvas.height > cachedSelectMenuCanvas.height) selectedMenuYOffset = cachedSelectMenuCanvas.height -MainCanvas.height;
MainCanvas_ctx.drawImage(cachedSelectMenuCanvas,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height);
let index = selectMenuNames.indexOf(selectedMenuItemName);
if(index > -1)
{
if(index > -1)
{
//We have a selected menu item
const cachedSelectMenuCanvasOverlay = document.createElement('canvas');
let boxwidth=3;
@ -59,60 +59,60 @@ function drawSelectMenu()
overlay.stroke();
MainCanvas_ctx.drawImage(cachedSelectMenuCanvasOverlay,0,selectedMenuYOffset,50,MainCanvas.height,0,0,50,MainCanvas.height);
//console.log("drawing select box around 0," + ty + " -> " + menuItemSize);
}
}
//Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset > (menuItemSize / 2))
{
//Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset > (menuItemSize / 2))
{
//We have one item above us. Draw the arrow
//console.log("Drawing up arrow");
MainCanvas_ctx.drawImage(imageFromName("ArrowUp"),0,0,50,25);
}
//Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset + (MainCanvas.height + 25) < cachedSelectMenuCanvas.height)
{
}
//Now, if we have more to the top or bottom, draw the arrows showing as much
if(selectedMenuYOffset + (MainCanvas.height + 25) < cachedSelectMenuCanvas.height)
{
//We have one item below us. Draw the arrow
//console.log("Drawing down arrow");
MainCanvas_ctx.drawImage(imageFromName("ArrowDown"),0,MainCanvas.height - 25,50,25);
}
}
}
function SelectMenu_handleMouseDown(evt)
{
mouseDownLocation = copyLocation(evt);
mouseIsDown=true;
mouseDownLocation = copyLocation(evt);
mouseIsDown=true;
}
function SelectMenu_handleMouseUp(evt)
{
mouseIsDown=false;
//console.log("mouseup");
//See if we have a mouse click
let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX);
let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY);
//console.log("delta " + deltaX + "," + deltaY);
if(deltaY < 3 && deltaX <3)
{
mouseIsDown=false;
//console.log("mouseup");
//See if we have a mouse click
let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX);
let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY);
//console.log("delta " + deltaX + "," + deltaY);
if(deltaY < 3 && deltaX <3)
{
//We did not move much. Assume click
if(evt.pageX <= menuItemSize && !mouseDidMovement)
{
//We are in the item select menu.
let actualMenuLocation = selectedMenuYOffset + evt.pageY;
let newitemindex = Math.floor( actualMenuLocation / menuItemSize);
console.log("clicked on item " + selectMenuNames[newitemindex]);
selectedMenuItemName = selectMenuNames[newitemindex];
drawSelectMenu();
//We are in the item select menu.
let actualMenuLocation = selectedMenuYOffset + evt.pageY;
let newitemindex = Math.floor( actualMenuLocation / menuItemSize);
console.log("clicked on item " + selectMenuNames[newitemindex]);
selectedMenuItemName = selectMenuNames[newitemindex];
drawSelectMenu();
}
}
mouseDidMovement=false; //reset it after we raise the button
}
mouseDidMovement=false; //reset it after we raise the button
}
function SelectMenu_handleMouseMove(evt)
{
if(mouseIsDown)
{
if(mouseIsDown)
{
let deltaX = evt.pageX - mouseDownLocation.pageX;
let deltaY = evt.pageY - mouseDownLocation.pageY;
if(isNaN(deltaY)) deltaY=0;
@ -123,7 +123,7 @@ function SelectMenu_handleMouseMove(evt)
mouseDownLocation = copyLocation(evt); //reset the pointer
drawSelectMenu();
mouseDidMovement=true;
}
}
}
function copyLocation({ pageX, pageY }) {

View File

@ -19,9 +19,9 @@ var cachedTextMenuCanvas = null;
//Print the textmenu
function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
{
//It would be nice to print it on top of whatever is currently there.
//But we will do that later.
PrintScreen(0); //Print the network, then we can lay over it
//It would be nice to print it on top of whatever is currently there.
//But we will do that later.
PrintScreen(0); //Print the network, then we can lay over it
if(cachedTextMenuCanvas == null)
{
@ -31,13 +31,17 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
}
//If we get here, it is already created. Get the context
var cTMCctx = cachedTextMenuCanvas.getContext('2d');
var rect;
//Fill in the background
cTMCctx.fillStyle = tmWindowBackground;
cTMCctx.fillRect(0,0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height);
cTMCctx.fillStyle = tmWindowBackground;
cTMCctx.fillRect(0,0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height);
//Put the X there so we can click on it
cTMCctx.drawImage(imageFromName("x"),cachedTextMenuCanvas.width - tmScrollBarWidth,0,tmScrollBarWidth,tmMenuBarHight);
rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, 0, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
cTMCctx.drawImage(imageFromName("x"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, textwindow_XClick);
//Put the DownArrow there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowUp"),cachedTextMenuCanvas.width - tmScrollBarWidth,tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight);
@ -45,7 +49,7 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
//Put the X there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowDown"),cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height - tmMenuBarHight,tmScrollBarWidth,tmMenuBarHight);
//Create and Draw the menu bar
//Create and Draw the menu bar
cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth,0);
cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth,cachedTextMenuCanvas.height);
@ -121,9 +125,9 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
//Write the text canvas on the main canvas. If we are scrolled up or down, do that.
cTMCctx.drawImage(cachedTextMenuTextCanvas,0,0);
//create and Draw the scroll-bar on the side
//Then make the text if we have not done so
//Finally print on top of the main canvas
//create and Draw the scroll-bar on the side
//Then make the text if we have not done so
//Finally print on top of the main canvas
MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
MainCanvas_ctx.drawImage(cachedTextMenuCanvas,tmOutsideXMargin, tmOutsideYMargin)
MainCanvas_ctx.globalAlpha = 1; //reset transparancy
@ -131,28 +135,28 @@ function textMenuPrint(TextToPrint, selectedindex = -1, highlightedindex = -1)
function fragmentTextIntoLines(ctx, text, maxWidth) {
var words = text.split(" ");
var lines = [];
var currentLine = words[0];
var words = text.split(" ");
var lines = [];
var currentLine = words[0];
for (var i = 1; i < words.length; i++) {
var word = words[i];
var width = ctx.measureText(currentLine + " " + word).width;
if (width < maxWidth) {
currentLine += " " + word;
} else {
lines.push(currentLine);
currentLine = word;
}
}
lines.push(currentLine);
return lines;
for (var i = 1; i < words.length; i++) {
var word = words[i];
var width = ctx.measureText(currentLine + " " + word).width;
if (width < maxWidth) {
currentLine += " " + word;
} else {
lines.push(currentLine);
currentLine = word;
}
}
lines.push(currentLine);
return lines;
}
function TextWindow_handleMouseUp(evt)
{
console.log("TextWindow Mouse Up");
//If we get here, it is a mouse-click event. See if we are on the X
//If we get here, it is a mouse-click event. See if we are on the X
if(mouseDownLocation.pageX + tmScrollBarWidth >= cachedTextMenuCanvas.width - tmScrollBarWidth)
{
console.log("TextWindow Mouse Up - X fits");
@ -165,15 +169,7 @@ function TextWindow_handleMouseUp(evt)
//We clicked the X
//Dispose of the text window
uiMode=0;
//dispose of temp canvas; will recreate later if needed
cachedTextMenuCanvas = null;
cachedTextMenuTextCanvas = null;
//Redraw the screen
PrintScreen();
textwindow_XClick();
}
}
else
@ -192,25 +188,222 @@ function TextWindow_handleMouseUp(evt)
}
}
}
mouseDidMovement=false; //reset it after we raise the button
mouseDidMovement=false; //reset it after we raise the button
}
function textwindow_XClick(point, object) {
//When the x is clicked, we do not care about the position or object. There is no object
//Dispose of the text window
uiMode = 0;
//dispose of temp canvas; will recreate later if needed
cachedTextMenuCanvas = null;
cachedTextMenuTextCanvas = null;
//Redraw the screen
PrintScreen();
}
function PrintPuzzleSelectMenu(level=0)
{
var levellist=networkNamesMatchingText("Level"+level);
//console.log("list is this long: " + levellist.length);
textMenuPrint(levellist, -1, tmLastHighlightedIndex);
tmPuzzleSelectMenuLevel=level;
//textMenuPrint(levellist, -1, tmLastHighlightedIndex);
//tmPuzzleSelectMenuLevel=level;
//
var local_menuitems = [];
for (var i = 1; i < levellist.length; i++) {
var item = new menuitem(null, levellist[i], levellist[i], null, null, textMenu_PuzzleClick)
local_menuitems.push(item);
}
var local_menu = new menuclass(null);
local_menu.items = local_menuitems;
menuPrint(local_menu);
}
function textMenu_PuzzleClick(text, name, source, dest) {
//If we get here, someone clicked on a puzzle name. Select it and move on
//We are in puzzle-select mode and clicked somewhere.
//if (text == null) { } //!== does not work properly
//else {
// console.log("Clicked on puzzle: " + text);
// uiMode = 1;
// switchPuzzle(text);
//}
}
function textMenu_HandleMouseMove(evt)
{
var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight);
if(tmLastHighlightedIndex != highlighted_index)
{
//the index has changed
console.log("index = " + highlighted_index);
tmLastHighlightedIndex = highlighted_index;
PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel);
//var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight);
//if(tmLastHighlightedIndex != highlighted_index)
//{
// //the index has changed
// console.log("index = " + highlighted_index);
// tmLastHighlightedIndex = highlighted_index;
// PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel);
//}
}
class menuitem {
constructor(rectangle, shownText, payloadName = null, payloadSource = null, payloadDest = null, clickFunc=null) {
this.rectangle = rectangle
this.shownText = shownText
this.payloadName = payloadName //The command, such as 'delete', 'power-on', 'ping', etc
this.payloadSource = payloadSource //The link, device, or original item.
this.payloadDest = payloadDest //The destination device, etc. Often null unless we are pinging or tracert
this.clickFunc = clickFunc
}
}
//Our menuclass will have a menu. We need to be able to have cascading menus (one on top of the other)
//so we can return to a past menu if we have moved on to a child menu.
class menuclass {
constructor(sourceItem) {
this.SourceItem = sourceItem
this.hmargin = 10 //horizontal margin on both left and right
this.vmargin = 10 //virtical margin on both top and bottom
this.backcolor = "grey" //The background color
this.font = "20px serif" //font and size
this.textcolor = "black" //Font color
this.items = [] //An array of menuitems
this.TextYGap = 3; //The gap to add to the size
}
}
function menuPrint(menu, menutop = 0, highlightedindex = -1) {
//the menu is the menuclass that holds everything
//menutop is the top=most item. If we scroll up and down, this changes.
//highlighted index is the item that has been moused-over. When this changes, re-draw the menu
PrintScreen(0); //Print the network, then we can lay over it
//This menu covers the entire place.
cachedTextMenuCanvas = document.createElement('canvas');
cachedTextMenuCanvas.width = MainCanvas.width - (tmOutsideXMargin * 2);
cachedTextMenuCanvas.height = MainCanvas.height - (tmOutsideYMargin * 2);
//Get the context
var cTMCctx = cachedTextMenuCanvas.getContext('2d');
var tw_rect;
var tw_width=0; //the width of the menu alltogether
var tw_height=0; //the height of the menu alltogether
var tw_itemHeight=0; //the height of both the font and margin spacing
var tw_rect; //the rectangle we end up using
//We need to figure out the size of the menu.
//Do we have an item to print? If so, add that at top
if (menu.SourceItem == null) {
//!== null does not work right
}
else {
tw_height = imageSize + 10;
}
var tw_startY = tw_height;
//Calculate the size of each text line
//Add spacing. If we are larger than the alloted space, add arrows at top and bottom
//Then we can fill in the area based on all of this.
cTMCctx.strokeStyle = menu.textcolor;
cTMCctx.font = menu.font;
var metrics = cTMCctx.measureText("test");
var yHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent + menu.TextYGap; //the hight of the default font and gap
var tw_TextHeight = yHeight; //store it for use
var maxWidth = 0;
//determine max width (width of longest text line)
for (var index = 0; index < menu.items.length; index++) {
var tmetrics = cTMCctx.measureText(menu.items[index].shownText);
var xWidth = tmetrics.width;
if (xWidth > maxWidth) maxWidth = xWidth;
}
maxWidth = maxWidth + 20 + menu.hmargin;
if (maxWidth > cachedTextMenuCanvas.width) maxWidth = cachedTextMenuCanvas.width;
tw_width = maxWidth;
//determine height (if we have more items than fit, figure out what will fit)
tw_height += menu.items.length * yHeight;
if(tw_height > cachedTextMenuCanvas.height) tw_height = cachedTextMenuCanvas.height;
//Now that we have the width and height, center it
var x = (cachedTextMenuCanvas.width - tw_width) / 2;
var y = (cachedTextMenuCanvas.height - tw_height) / 2;
//make a rectangle of the correct size
//Use that rectangle to place the closing X at the top
tw_rect = makeRectangle(x, y, tw_width, tw_height);
//fill in the whole thing with white and opaque
drawshape("square", makeRectangle(0, 0, cachedTextMenuCanvas.width, cachedTextMenuCanvas.height), "white", .5, cTMCctx);
//Fill in the background, nearly fully but showing a very little behind
drawshape("square", tw_rect, menu.backcolor, .9, cTMCctx);
//Put the X there so we can click on it
rect = makeRectangle(cachedTextMenuCanvas.width - tmScrollBarWidth, y, tmScrollBarWidth, tmMenuBarHight, tmOutsideXMargin, tmOutsideYMargin);
cTMCctx.drawImage(imageFromName("x"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, textwindow_XClick);
//Put the UpArrow there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowUp"), cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
//Put the DownArrow there so we can click on it
cTMCctx.drawImage(imageFromName("ArrowDown"), cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height - tmMenuBarHight, tmScrollBarWidth, tmMenuBarHight);
//Create and Draw the menu bar
cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, 0);
cTMCctx.lineTo(cachedTextMenuCanvas.width - tmScrollBarWidth, cachedTextMenuCanvas.height);
cTMCctx.strokeStyle = "white";
cTMCctx.stroke();
//horizontal line under the X
cTMCctx.beginPath();
cTMCctx.moveTo(cachedTextMenuCanvas.width - tmScrollBarWidth, tmMenuBarHight);
cTMCctx.lineTo(cachedTextMenuCanvas.width, tmMenuBarHight);
cTMCctx.strokeStyle = "white";
cTMCctx.stroke();
var oldfill = cTMCctx.fillStyle;
var oldstroke = cTMCctx.strokeStyle;
cTMCctx.font = menu.font;
cTMCctx.fillStyle = menu.textcolor;
cTMCctx.strokeStyle = menu.textcolor;
for (var index = menutop; index < menu.items.length; index++) {
var ty = tw_startY + (tw_TextHeight * (index - menutop));
//x is already defined
cTMCctx.fillText(menu.items[index].shownText, x, ty);
metrics = cTMCctx.measureText(menu.items[index].shownText);
var trect = makeRectangle(x + 20, ty, metrics.width, tw_TextHeight);
menu.items[index].rectangle = trect;
registerActionStruct("square", trect, menu.items[index], puzzle_clickOn, null, generic_mouseoverHighlight);
}
cTMCctx.fillStyle = oldfill;
cTMCctx.strokeStyle = oldstroke;
MainCanvas_ctx.globalAlpha = 0.9; //some transparancy
MainCanvas_ctx.drawImage(cachedTextMenuCanvas, tmOutsideXMargin, tmOutsideYMargin)
MainCanvas_ctx.globalAlpha = 1; //reset transparancy
}
function puzzle_clickOn(point, actionrec) {
console.log("clicking on puzzle:" + actionrec.theObject.shownText);
uiMode = 1;
switchPuzzle(actionrec.theObject.shownText);
}

915
Web/ui.js

File diff suppressed because it is too large Load Diff