Compare commits

16 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
11 changed files with 9661 additions and 70 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

View File

@ -25,12 +25,13 @@
</form> </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="allpuzzles.js"></script>
<script src="selectmenu.js"></script> <script src="selectmenu.js"></script>
<script src="network.js"></script> <script src="network.js"></script>
<script src="textwindow.js"></script> <script src="textwindow.js"></script>
<script src="language.js"></script>
<script src="ui.js"></script> <script src="ui.js"></script>
</body> </body>
</html> </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) //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 //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-Ping");
//var puzzle=networkFromName("Level0-NeedsLink"); //var puzzle=networkFromName("Level0-NeedsLink");
//var puzzle=networkFromName("Level0_NetworkLoop"); //var puzzle=networkFromName("Level0_NetworkLoop");
@ -32,7 +36,7 @@ function networkFromName(what)
if(allpuzzles[index].EduNetworkBuilder.Network.name == what) if(allpuzzles[index].EduNetworkBuilder.Network.name == what)
{ {
console.log("Found " + what + " at index " + index); console.log("Found " + what + " at index " + index);
return structuredClone(allpuzzles[index].EduNetworkBuilder.Network); return networkFromIndex(index);
} }
index++; index++;
} }
@ -40,11 +44,105 @@ function networkFromName(what)
function networkFromIndex(what) function networkFromIndex(what)
{ {
if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){ if(typeof(what)==="number" && what >= 0 && what < allpuzzles.length){
return structuredClone(allpuzzles[what].EduNetworkBuilder.Network); 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; 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) function networkNamesMatchingText(textToMatch)
{ {
var list = []; var list = [];

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() { function InitializeSelectMenu() {
cachedSelectMenuCanvas = document.createElement('canvas'); cachedSelectMenuCanvas = document.createElement('canvas');
cachedSelectMenuCanvas.width = menuItemSize; cachedSelectMenuCanvas.width = menuItemSize;
console.log("length= " + selectMenuNames.length); //console.log("length= " + selectMenuNames.length);
cachedSelectMenuCanvas.height = menuItemSize * selectMenuNames.length; cachedSelectMenuCanvas.height = menuItemSize * selectMenuNames.length;
var cSMCctx = cachedSelectMenuCanvas.getContext('2d'); var cSMCctx = cachedSelectMenuCanvas.getContext('2d');
var starty = 0; var starty = 0;

View File

@ -208,18 +208,202 @@ function PrintPuzzleSelectMenu(level=0)
{ {
var levellist=networkNamesMatchingText("Level"+level); var levellist=networkNamesMatchingText("Level"+level);
//console.log("list is this long: " + levellist.length); //console.log("list is this long: " + levellist.length);
textMenuPrint(levellist, -1, tmLastHighlightedIndex); //textMenuPrint(levellist, -1, tmLastHighlightedIndex);
tmPuzzleSelectMenuLevel=level; //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) function textMenu_HandleMouseMove(evt)
{ {
var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight); //var highlighted_index = Math.floor(((evt.pageY - tmOutsideYMargin) - (tmTextHeight/3)) / tmTextHeight);
if(tmLastHighlightedIndex != highlighted_index) //if(tmLastHighlightedIndex != highlighted_index)
{ //{
//the index has changed // //the index has changed
console.log("index = " + highlighted_index); // console.log("index = " + highlighted_index);
tmLastHighlightedIndex = highlighted_index; // tmLastHighlightedIndex = highlighted_index;
PrintPuzzleSelectMenu(tmPuzzleSelectMenuLevel); // 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);
}

356
Web/ui.js
View File

@ -12,9 +12,12 @@ var small_button_size = 25;
var uiDeviceInfoLevel = 1; //What do we display when we look at the network var uiDeviceInfoLevel = 1; //What do we display when we look at the network
var uiActions = [];//a list of things on the screen we can click on or process. var uiActions = [];//a list of things on the screen we can click on or process.
var ui_highlightRect = null; var ui_highlightRect = null;
var ui_selectRect = null;
var ui_HadHighlight = false; var ui_HadHighlight = false;
var ui_status_height = 25; var ui_status_height = 25;
var ui_StatusText=""; var ui_StatusText = "";
var ui_HighlightArray = [];
var translator = new Language("en");
//The user interface mode. 0=network, 1=network information, 2=puzzle-selection menu //The user interface mode. 0=network, 1=network information, 2=puzzle-selection menu
var uiMode=1; var uiMode=1;
@ -44,7 +47,7 @@ const imageCollection = loadImages(
"img/VidImage.png", "img/WAP.png", "img/WBridge.png", "img/VidImage.png", "img/WAP.png", "img/WBridge.png",
"img/WRepeater.png", "img/WRouter.png", "img/X.png", "img/WRepeater.png", "img/WRouter.png", "img/X.png",
"img/info.png", "img/menu.png", "img/eye.png", "img/info.png", "img/menu.png", "img/eye.png",
"img/menu.png", "img/thumb.png", "img/queryuser.png", "img/thumb.png",
], ],
InitializeGameMenu // this is called when all images have loaded. InitializeGameMenu // this is called when all images have loaded.
); );
@ -98,7 +101,7 @@ function PrintScreen(WhatPassedIn=-1)
//Clear out any old ActionStructs. They will get filled in as we print the screen. //Clear out any old ActionStructs. They will get filled in as we print the screen.
clearActionStructs(); clearActionStructs();
console.log("PrintingScreen for mode: " + what); //console.log("PrintingScreen for mode: " + what);
var rect; var rect;
if(what == 0) if(what == 0)
@ -108,28 +111,11 @@ function PrintScreen(WhatPassedIn=-1)
MainCanvas_ctx.fillStyle = maincanvasBackground; MainCanvas_ctx.fillStyle = maincanvasBackground;
MainCanvas_ctx.fillRect(0, 0, MainCanvas.width, MainCanvas.height); MainCanvas_ctx.fillRect(0, 0, MainCanvas.width, MainCanvas.height);
//Do any highlight we need to //Check for device highlights
if (ui_highlightRect !== null) { checkDevicesForIssues();
//console.log("trying to highlight something: " + JSON.stringify(ui_highlightRect));
MainCanvas_ctx.fillStyle = "white"; //print highlights. If we have mouseover highlights, note that.
MainCanvas_ctx.globalAlpha = 0.4; //mostly transparent if (printHighlights("mouseover") > 0) ui_HadHighlight = true;
if (ui_highlightRect.shapeText == "square")
MainCanvas_ctx.fillRect(ui_highlightRect.sx, ui_highlightRect.sy, ui_highlightRect.deltax, ui_highlightRect.deltay);
else if (ui_highlightRect.shapeText == "line") {
var oldWidth = MainCanvas_ctx.lineWidth;
MainCanvas_ctx.lineWidth += 6;
MainCanvas_ctx.strokeStyle = "white";
MainCanvas_ctx.beginPath();
MainCanvas_ctx.moveTo(ui_highlightRect.sx, ui_highlightRect.sy);
MainCanvas_ctx.lineTo(ui_highlightRect.dx, ui_highlightRect.dy);
MainCanvas_ctx.stroke();
MainCanvas_ctx.lineWidth = oldWidth;
MainCanvas_ctx.strokeStyle = "black";
}
MainCanvas_ctx.globalAlpha = 1.0; //reset
MainCanvas_ctx.fillStyle = "black"; //reset
ui_HadHighlight = true;
}
else ui_HadHighlight = false; else ui_HadHighlight = false;
//Draw the puzzle-select button //Draw the puzzle-select button
@ -148,6 +134,23 @@ function PrintScreen(WhatPassedIn=-1)
MainCanvas_ctx.drawImage(imageFromName("eye"), rect.sx, rect.sy, rect.deltax, rect.deltay); MainCanvas_ctx.drawImage(imageFromName("eye"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, ui_eyeLeftClick, null, generic_mouseoverHighlight); registerActionStruct("square", rect, null, ui_eyeLeftClick, null, generic_mouseoverHighlight);
//Draw the help-level select button
rect = makeRectangle(MainCanvas.width - small_button_size, small_button_size * 3, small_button_size, small_button_size);
//Put any coloring behind the query-user image
var tmp_queryhighlight = null;
if (ui_helplevel == 0) tmp_queryhighlight = returnHighlightShape("square", rect, "red", "none", 0.3);
if (ui_helplevel == 1) tmp_queryhighlight = returnHighlightShape("square", rect, "orange", "none", 0.3);
if (ui_helplevel == 2) tmp_queryhighlight = returnHighlightShape("square", rect, "yellow", "none", 0.3);
if (ui_helplevel == 3) tmp_queryhighlight = returnHighlightShape("square", rect, "green", "none", 0.3);
if (tmp_queryhighlight == null) { }
else drawhighlight(tmp_queryhighlight);
MainCanvas_ctx.drawImage(imageFromName("queryuser"), rect.sx, rect.sy, rect.deltax, rect.deltay);
registerActionStruct("square", rect, null, ui_queryuserLeftClick, null, generic_mouseoverHighlight);
//Draw simple lines to show boundaries //Draw simple lines to show boundaries
//Select menu separation //Select menu separation
MainCanvas_ctx.lineWidth = 2; MainCanvas_ctx.lineWidth = 2;
@ -174,6 +177,13 @@ function PrintScreen(WhatPassedIn=-1)
MainCanvas_ctx.strokeStyle = "black"; MainCanvas_ctx.strokeStyle = "black";
if (ui_selectRect == null) { }
else {
//console.log("We have something selected.");
var tmp_select = returnHighlightShape("selectbox", ui_selectRect, "green", "none", 0.8);
drawhighlight(tmp_select);
}
drawSelectMenu(); drawSelectMenu();
PrintAllNetworkLinks(); PrintAllNetworkLinks();
PrintAllNetworkDevices(); PrintAllNetworkDevices();
@ -181,7 +191,8 @@ function PrintScreen(WhatPassedIn=-1)
else if(what == 1) //PuzzleDescription/Info else if(what == 1) //PuzzleDescription/Info
{ {
//Display the text about the puzzle //Display the text about the puzzle
textMenuPrint(puzzle.en_message); console.log("Using language: " + ui_language);
textMenuPrint(eval('puzzle.' + ui_language + '_message'));
} }
else if(what == 2) //PuzzleSelect else if(what == 2) //PuzzleSelect
{ {
@ -227,9 +238,10 @@ function CheckForActions(actionPoint, action) {
var checkit = false; var checkit = false;
var inside = false; var inside = false;
for (var index = 0; index < uiActions.length; index++) { for (var index = 0; index < uiActions.length; index++) {
if (action == "leftclick" && uiActions[index].funcLeftClick !== null) checkit = true; checkit = true;
if (action == "rightclick" && uiActions[index].funcRightClick !== null) checkit = true; if (action == "leftclick" && uiActions[index].funcLeftClick == null) checkit = false;
if (action == "mouseover" && uiActions[index].funcMouseover !== null) checkit = true; if (action == "rightclick" && uiActions[index].funcRightClick == null) checkit = false;
if (action == "mouseover" && uiActions[index].funcMouseover == null) checkit = false;
checklocation = uiActions[index]; checklocation = uiActions[index];
var point = newPointFromPair(actionPoint.pageX - checklocation.shapePoints.offsetx, actionPoint.pageY - checklocation.shapePoints.offsety); var point = newPointFromPair(actionPoint.pageX - checklocation.shapePoints.offsetx, actionPoint.pageY - checklocation.shapePoints.offsety);
if (checkit) { if (checkit) {
@ -257,14 +269,16 @@ function CheckForActions(actionPoint, action) {
//console.log("Is inside"); //console.log("Is inside");
switch (action) { switch (action) {
case "leftclick": case "leftclick":
if (checklocation.funcLeftClick != null) { if (checklocation.funcLeftClick == null) { }
else {
checklocation.funcLeftClick(actionPoint, checklocation); checklocation.funcLeftClick(actionPoint, checklocation);
//console.log("Successfully did a UI action"); //console.log("Successfully did a left-click UI action");
return true; return true;
} }
break; break;
case "mouseover": case "mouseover":
if (checklocation.funcMouseover != null) { if (checklocation.funcMouseover == null) { }
else {
checklocation.funcMouseover(actionPoint, checklocation); checklocation.funcMouseover(actionPoint, checklocation);
//console.log("Successfully did a UI action"); //console.log("Successfully did a UI action");
return true; return true;
@ -298,7 +312,7 @@ function distance(x1, y1, x2, y2) {
function handleMouseUp(evt) function handleMouseUp(evt)
{ {
//evt.preventDefault(); //evt.preventDefault();
mouseIsDown=false; mouseIsDown = false;
//See if we have a mouse click //See if we have a mouse click
let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX); let deltaX = Math.abs(evt.pageX - mouseDownLocation.pageX);
let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY); let deltaY = Math.abs(evt.pageY - mouseDownLocation.pageY);
@ -315,10 +329,17 @@ function handleMouseUp(evt)
if(!mouseDidMovement) if(!mouseDidMovement)
{ //If we are not dragging, it is a click { //If we are not dragging, it is a click
var myevt = copyLocation(evt); var myevt = copyLocation(evt);
var needsrefresh = true;;
if (ui_selectRect == null) needsrefresh = false;
ui_selectRect = null; //remove any previous selected marker
//console.log("evt:" + JSON.stringify(myevt)); //console.log("evt:" + JSON.stringify(myevt));
if (CheckForActions(myevt, "leftclick")) return; //If we did this, do not do anything else. if (CheckForActions(myevt, "leftclick")) return; //If we did this, do not do anything else.
if(uiMode==1) TextWindow_handleMouseUp(evt); if(uiMode==1) TextWindow_handleMouseUp(evt);
else if(uiMode==2) TextWindow_handleMouseUp(evt); else if (uiMode == 2) TextWindow_handleMouseUp(evt);
if (needsrefresh) {
if (ui_selectRect == null) setStatus(""); //we clicked on nothing
PrintScreen();
}
} }
} }
@ -340,6 +361,19 @@ function ui_eyeLeftClick(evt) {
PrintScreen(); PrintScreen();
} }
function ui_queryuserLeftClick(evt) {
console.log("Selected 'queryuser' button in action");
//It is the eye button
ui_helplevel++;
if (ui_helplevel > 3) ui_helplevel = 0;
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.");
PrintScreen();
}
function ui_InfoLeftClick(evt) { function ui_InfoLeftClick(evt) {
console.log("Selected info button in action"); console.log("Selected info button in action");
//It is the info button //It is the info button
@ -368,17 +402,17 @@ function handleMouseMove(evt)
else //Mouse is not down. Not dragging else //Mouse is not down. Not dragging
{ {
var needrefresh = false; var needrefresh = false;
var oldRect = structuredClone(ui_highlightRect); var oldRect = structuredClone(findHighlightsNamed("mouseover"));
removeHighlightsNamed("mouseover");
if (!CheckForActions(evt, "mouseover")) { if (!CheckForActions(evt, "mouseover")) {
//We did not find anything //We did not find anything
if (JSON.stringify(ui_highlightRect) === JSON.stringify(oldRect)) { if (oldRect == null) {
} }
else { else {
//console.log("Rects are not equal:" + JSON.stringify(ui_highlightRect) + " - " + JSON.stringify(oldRect) ) //We used to have a highlight, but it was removed
needrefresh = true; needrefresh = true;
} }
ui_highlightRect = null; //nothing to highlight
if (ui_HadHighlight) { needrefresh = true; } if (ui_HadHighlight) { needrefresh = true; }
if (needrefresh) { if (needrefresh) {
PrintScreen(); PrintScreen();
@ -455,6 +489,12 @@ function PrintNetworkDevice(ToPrint)
if(dname=="net_switch") dname="switch"; if(dname=="net_switch") dname="switch";
if(dname=="net_hub") dname="hub"; if(dname=="net_hub") dname="hub";
//console.log("printing device " + dname); //console.log("printing device " + dname);
if (deviceHasProblem(ToPrint)) {
var thshape = returnHighlightShape("square", actionrect, "red", "problem", 0.2);
drawhighlight(thshape);
}
MainCanvas_ctx.drawImage(imageFromName(dname), rect.spoint.x, rect.spoint.y, rect.width, rect.height); MainCanvas_ctx.drawImage(imageFromName(dname), rect.spoint.x, rect.spoint.y, rect.width, rect.height);
registerActionStruct("square", actionrect, ToPrint, device_clickOn, null, generic_mouseoverHighlight); registerActionStruct("square", actionrect, ToPrint, device_clickOn, null, generic_mouseoverHighlight);
@ -500,11 +540,34 @@ function PrintNetworkDevice(ToPrint)
} }
} }
function checkDevicesForIssues()
{
return; //Doing it a different way
if (puzzle == null) return; //If the puzzle has not been set, exit
removeHighlightsNamed("problem");
//console.log("Looking for problems in devices." + puzzle.device.length);
let index = 0;
while (index < puzzle.device.length) {
if (deviceHasProblem(puzzle.device[index])) {
console.log("Found a problem. Registering it...");
var actionrect = deviceRectangle(puzzle.device[index]);
//If the help level is bigger than 0 (guessing), show which devices have problems
if (ui_helplevel > 0) {
var answer = registerHighlightShape("square", actionrect, "red", "problem", 0.2);
console.log("registered it." + JSON.stringify(answer));
}
}
index++;
}
}
function PrintAllNetworkDevices() function PrintAllNetworkDevices()
{ {
if (puzzle == null) return; //If the puzzle has not been set, exit if (puzzle == null) return; //If the puzzle has not been set, exit
let index=0; let index = 0;
while (index < puzzle.device.length) { while (index < puzzle.device.length) {
PrintNetworkDevice(puzzle.device[index]); PrintNetworkDevice(puzzle.device[index]);
index++; index++;
@ -625,22 +688,22 @@ function makeLine(x1, y1, x2, y2, offsetx = 0, offsety = 0) {
} }
//Make a structure to hold all our data //Make a structure to hold all our data
function actionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) { class actionStruct {
var struct = { constructor(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) {
shapeText: shapeText,
shapePoints: structuredClone(shapePoints), this.shapeText= shapeText
theObject: theObject, this.shapePoints= structuredClone(shapePoints)
funcLeftClick: funcLeftClick, this.shapePoints.shapeText = shapeText;
funcRightClick: funcRightClick, this.theObject= theObject
funcMouseover: funcMouseover, this.funcLeftClick= funcLeftClick
this.funcRightClick= funcRightClick
this.funcMouseover= funcMouseover
} }
shapePoints.shapeText = shapeText;
return struct;
} }
function registerActionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) { function registerActionStruct(shapeText, shapePoints, theObject=null, funcLeftClick=null, funcRightClick=null, funcMouseover=null) {
//Make an object with all the data //Make an object with all the data
var what = actionStruct(shapeText, shapePoints, theObject, funcLeftClick, funcRightClick, funcMouseover); var what = new actionStruct(shapeText, shapePoints, theObject, funcLeftClick, funcRightClick, funcMouseover);
//console.log("Pushing an action: " + shapeText); //console.log("Pushing an action: " + shapeText);
//Push it onto the uiActions list //Push it onto the uiActions list
uiActions.unshift(what); //Put it at the beginning of the list uiActions.unshift(what); //Put it at the beginning of the list
@ -655,22 +718,145 @@ function setStatus(text) {
ui_StatusText = text; //set the text. ui_StatusText = text; //set the text.
} }
//go through all highlights and print all of them
function printHighlights(countof="mouseover") {
var count = 0;
//console.log("Printing highlights. " + ui_HighlightArray.length)
for (var index = 0; index < ui_HighlightArray.length; index++) {
var highlight = ui_HighlightArray[index];
//console.log("trying to highlight something: " + JSON.stringify(highlight));
if (highlight.shapeName == countof) count++;
drawhighlight(highlight);
}
return countof; //the count of the item we were supposed to count
}
function drawhighlight(highlight, canvas = null) {
if (canvas == null)
canvas = MainCanvas_ctx;
canvas.fillStyle = highlight.shapeColor;
canvas.globalAlpha = highlight.opaciticy; //mostly transparent
var oldWidth;
if (highlight.shapeText == "square")
canvas.fillRect(highlight.shapePoints.sx, highlight.shapePoints.sy, highlight.shapePoints.deltax, highlight.shapePoints.deltay);
else if (highlight.shapeText == "line") {
oldWidth = canvas.lineWidth;
canvas.lineWidth += 6;
canvas.strokeStyle = highlight.shapeColor;
canvas.beginPath();
canvas.moveTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.dy);
canvas.stroke();
canvas.lineWidth = oldWidth;
canvas.strokeStyle = "black";
}
else if (highlight.shapeText == "selectbox") {
//console.log("Printing a selectbox");
canvas.fillStyle = "green";
oldWidth = canvas.lineWidth;
canvas.lineWidth += 2;
canvas.strokeStyle = "green";
canvas.beginPath();
canvas.moveTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.sy);
canvas.lineTo(highlight.shapePoints.dx, highlight.shapePoints.dy);
canvas.lineTo(highlight.shapePoints.sx, highlight.shapePoints.dy);
canvas.lineTo(highlight.shapePoints.sx, highlight.shapePoints.sy);
canvas.stroke();
canvas.lineWidth = oldWidth;
canvas.strokeStyle = "black";
}
canvas.globalAlpha = 1.0; //reset
canvas.fillStyle = "black"; //reset
}
//We use drawhighlight to draw one-off shapes
function drawshape( shape, rect, color, opaciticy = 0.4, canvas = null) {
if (canvas == null)
canvas = MainCanvas_ctx;
var tmp_queryhighlight = returnHighlightShape(shape, rect, color, "none", opaciticy);
drawhighlight(tmp_queryhighlight, canvas);
}
function countHighlightsNamed(countof = "mouseover") {
var count = 0;
for (var index = 0; index < ui_HighlightArray.length; index++) {
if (ui_HighlightArray[index].shapeName == countof)
count++;
}
return countof; //the count of the item we were supposed to count
}
function returnHighlightShape(shapeText, shapePoints, shapeColor, shapeName, opaciticy = 0.4) {
//Create a highlight record with the needed info
var newhighlight = {
shapeText: shapeText,
shapePoints: structuredClone(shapePoints),
shapeColor: shapeColor,
shapeName: shapeName, //Used when we remove them later
opaciticy, opaciticy,
}
return newhighlight;
}
//There may be multiple things
function registerHighlightShape(shapeText, shapePoints, shapeColor, shapeName, opaciticy=0.4) {
//Create a highlight record with the needed info
var newhighlight = returnHighlightShape(shapeText, structuredClone(shapePoints), shapeColor, shapeName, opaciticy)
//console.log("registering a highlight: " + JSON.stringify(newhighlight));
//Add it to the list of highlights.
ui_HighlightArray.unshift(newhighlight);
return newhighlight;
}
function removeHighlightsNamed(shapeName) {
//console.log("Trying to remove " + shapeName + " in array of " + ui_HighlightArray.length);
for (var index = ui_HighlightArray.length; index >= 0; index--) {
if (ui_HighlightArray[index] == null) { }
else {
//console.log("Comparing " + shapeName + " in " + JSON.stringify(ui_HighlightArray[index]));
if (ui_HighlightArray[index].shapeName == shapeName) {
//console.log("removing " + shapeName + " at index:" + index + " " + ui_HighlightArray.length);
ui_HighlightArray.splice(index, 1); //remove it if found
}
}
}
}
function findHighlightsNamed(shapeName) {
for (var index = ui_HighlightArray.length; index >= 0; index--) {
if (ui_HighlightArray[index] == null) { }
else {
if (ui_HighlightArray[index].shapeName == shapeName)
return ui_HighlightArray[index];
}
}
return null; //null if not there
}
//This takes generic information for us to highlight the background //This takes generic information for us to highlight the background
function generic_mouseoverHighlight(point, actionrec) { function generic_mouseoverHighlight(point, actionrec) {
//console.log("Found highlight " + JSON.stringify(actionrec)); //console.log("Found highlight " + JSON.stringify(actionrec));
//The point is the place where the mouse is, but the actionrec.shapePoints is the rectangle (or shape) we want to highlight //The point is the place where the mouse is, but the actionrec.shapePoints is the rectangle (or shape) we want to highlight
var oldrec = structuredClone(ui_highlightRect); //var oldrec = structuredClone(ui_highlightRect);
var oldrec = findHighlightsNamed("mouseover");
var newrec = null;
//console.log("setting highlights to:" + JSON.stringify(actionrec));
removeHighlightsNamed("mouseover");
if (actionrec.shapeText == "square") { if (actionrec.shapeText == "square") {
ui_highlightRect = structuredClone(actionrec.shapePoints); //ui_highlightRect = structuredClone(actionrec.shapePoints);
ui_highlightRect.shapeText = "square"; //ui_highlightRect.shapeText = "square";
newrec = registerHighlightShape("square", actionrec.shapePoints, "white", "mouseover"); //opacity is default
//console.log("setting highlights to:" + JSON.stringify(ui_highlightRect)); //console.log("setting highlights to:" + JSON.stringify(ui_highlightRect));
} }
if (actionrec.shapeText == "line") { if (actionrec.shapeText == "line") {
ui_highlightRect = structuredClone(actionrec.shapePoints); //ui_highlightRect = structuredClone(actionrec.shapePoints);
ui_highlightRect.shapeText = "line"; //ui_highlightRect.shapeText = "line";
newrec = registerHighlightShape("line", actionrec.shapePoints, "white", "mouseover"); //opacity is default
//console.log("setting highlights to:" + JSON.stringify(ui_highlightRect)); //console.log("setting highlights to:" + JSON.stringify(ui_highlightRect));
} }
if (JSON.stringify(ui_highlightRect) === JSON.stringify(oldrec)) { if (JSON.stringify(newrec) === JSON.stringify(oldrec)) {
//they are the same. Nothing to do //they are the same. Nothing to do
} }
else else
@ -679,8 +865,64 @@ function generic_mouseoverHighlight(point, actionrec) {
function device_clickOn(point, actionrec) { function device_clickOn(point, actionrec) {
if (actionrec.theObject !== null && actionrec.theObject.name !== null) { if (actionrec.theObject !== null && actionrec.theObject.name !== null) {
setStatus(actionrec.theObject.hostname); ui_selectRect = structuredClone(actionrec.shapePoints);
//console.log("Setting select rect:" + JSON.stringify(ui_selectRect));
var ipaddresses = ipsFromDevice(actionrec.theObject);
var additional = "";
for (var x = 0; x < ipaddresses.length; x++) {
//Print the IP address if the type is correct.
//console.log(JSON.stringify(ipaddresses[x]));
switch (ipaddresses[x].nictype) {
case "eth":
case "management_interface":
//console.log("Found a " + ipaddresses[x].nictype)
additional += " " + ipaddresses[x].cidrip;
break;
}
}
if (deviceHasProblem(actionrec.theObject)) {
//If we know nothing, we change nothing
if (ui_helplevel > 0) {
if (ui_helplevel == 1) additional = " " + translator.getStr("NT_TstDscriptProblem");
else {
//here we get all the problem statements and combine them
errors = returnProblemStrings(actionrec.theObject);
additional = " " + errors.join(' - ');
}
}
}
setStatus(actionrec.theObject.hostname + additional);
//We probably do not want to do printecreen here, but we are doing it here now... //We probably do not want to do printecreen here, but we are doing it here now...
PrintScreen(); PrintScreen();
} }
} }
function Language(lang = null) {
var __construct = function () {
if (lang == null) {
lang = "en";
}
//console.log("Defining language:" + lang);
ui_language = lang;
return;
}()
this.getStr = function (str, defaultStr) {
var toget = 'language.' + ui_language + "." + str + ".value";
//console.log("Translating: " + toget);
var retStr = eval(toget);
if (typeof retStr != 'undefined') {
return retStr;
} else {
if (typeof defaultStr != 'undefined') {
return defaultStr;
} else {
toget = "language.en." + str;
//console.log("First translation failed, falling back to en: " + toget);
return eval(toget);
}
}
}
}