Compare commits
25 Commits
dc741e8c0b
...
web
Author | SHA1 | Date | |
---|---|---|---|
858bfef1bb | |||
deb5f29cee | |||
9aa26b82c6 | |||
726bafe580 | |||
80c1abd5fe | |||
5ce6dc6d3e | |||
bf2e281c40 | |||
98733d1ad5 | |||
0859bffc23 | |||
9be833dd2c | |||
0e9a6d1a15 | |||
3e902cba95 | |||
77b034f845 | |||
f3ed276ca9 | |||
7b57cbe97a | |||
ee0a3f9255 | |||
a19cb99b9d | |||
6119432875 | |||
84685e3bd4 | |||
d7f73f04d8 | |||
50b4843d76 | |||
b978a3abb0 | |||
4ec5b370e9 | |||
50099ee4ef | |||
df520fcce6 |
4
Web/.editorconfig
Normal file
4
Web/.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
root = true
|
||||
[*]
|
||||
end_of_line = lf
|
2606
Web/Resources/edustrings.en.json
Normal file
2606
Web/Resources/edustrings.en.json
Normal file
File diff suppressed because it is too large
Load Diff
2396
Web/Resources/edustrings.fr.json
Normal file
2396
Web/Resources/edustrings.fr.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Web/img/thumb.png
Normal file
BIN
Web/img/thumb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
@ -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
3995
Web/language.js
Normal file
File diff suppressed because it is too large
Load Diff
200
Web/network.js
200
Web/network.js
@ -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;
|
||||
}
|
40
Web/scripts/BuildLanguage.pl
Normal file
40
Web/scripts/BuildLanguage.pl
Normal 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);
|
||||
|
25
Web/scripts/ConvertResx2Json.sh
Normal file
25
Web/scripts/ConvertResx2Json.sh
Normal 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
|
@ -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 }) {
|
||||
|
@ -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);
|
||||
}
|
Reference in New Issue
Block a user