diff --git a/AppSchema.json b/AppSchema.json index cd2eab20e..d71cf8078 100644 --- a/AppSchema.json +++ b/AppSchema.json @@ -14122,6 +14122,21 @@ "relatedUiObject": "Tutorial Step", "actionFunction": "payload.onMenuItemClick" }, + { + "action": "Add UI Object", + "label": "Add Tutorial Topic", + "relatedUiObject": "Tutorial Topic", + "actionFunction": "payload.onMenuItemClick" + }, + { + "action": "Reset Tutorial Progress", + "askConfirmation": true, + "confirmationLabel": "Confirm to Reset", + "label": "Reset Tutorial Progress", + "iconPathOn": "shapes-polygon-body", + "iconPathOff": "shapes-polygon-body", + "actionFunction": "payload.onMenuItemClick" + }, { "action": "Delete UI Object", "askConfirmation": true, @@ -14136,13 +14151,13 @@ "config": true }, "initialValues": { - "config": "{ \n}" + "config": "{ \n\"title\": \"\",\n \"summary\": \"\",\n \"subTitle\": \"\",\n \"image\": \"\",\n \"definition\": \"\",\n \"bulletListIntro\": \"\",\n \"bulletArray\": \n[\n [\"\", \"\"], \n[\"\", \"\"], \n[\"\", \"\"] \n],\n \"paragraph1\": \"\",\n \"callOut\": \"\",\n \"externalLink\": [\"\", \"\"],\n \"paragraph2\": \"\",\n \"note\": \"\",\n \"tip\": \"\",\n \"important\": \"\",\n \"warning\": \"\", \n \"position\": \"\",\n \"documentationURL\": \"\" \n}" }, "isTitleAllwaysVisible": true, "isHierarchyHead": true, "addLeftIcons": true, "level": 0, - "icon": "approve", + "icon": "us-dollar", "propertyNameAtParent": "tutorials", "properties": [ { @@ -14150,16 +14165,28 @@ "type": "array", "childType": "Tutorial Step", "autoAdd": false + }, + { + "name": "tutorialTopics", + "type": "array", + "childType": "Tutorial Topic", + "autoAdd": false } ] }, { - "type": "Tutorial Step", + "type": "Tutorial Topic", "menuItems": [ { - "action": "Play Tutorial Step", + "action": "Play Tutorial Topic", "label": "Play", - "relatedUiObject": "Tutorial", + "relatedUiObject": "Tutorial Topic", + "actionFunction": "payload.onMenuItemClick" + }, + { + "action": "Resume Tutorial Topic", + "label": "Resume", + "relatedUiObject": "Tutorial Topic", "actionFunction": "payload.onMenuItemClick" }, { @@ -14175,6 +14202,12 @@ "relatedUiObject": "Tutorial Step", "actionFunction": "payload.onMenuItemClick" }, + { + "action": "Add UI Object", + "label": "Add Tutorial Topic", + "relatedUiObject": "Tutorial Topic", + "actionFunction": "payload.onMenuItemClick" + }, { "action": "Delete UI Object", "askConfirmation": true, @@ -14189,22 +14222,82 @@ "config": true }, "initialValues": { - "config": "{ \n\"title\": \"\",\n \"summary\": \"\",\n \"subTitle\": \"\",\n \"image\": \"\",\n \"definition\": \"\",\n \"bulletPointIntro\": \"\",\n \"bulletArray\": \n[\n [\"\", \"\"], \n[\"\", \"\"], \n[\"\", \"\"] \n],\n \"paragraph1\": \"\",\n \"callOut\": \"\",\n \"paragraph2\": \"\",\n \"note\": \"\",\n \"tip\": \"\",\n \"important\": \"\",\n \"note\": \"\" \n}" + "config": "{ \n\"title\": \"\",\n \"summary\": \"\",\n \"image\": \"\",\n \"definition\": \"\",\n \"bulletListIntro\": \"\",\n \"bulletArray\": \n[\n [\"\", \"\"], \n[\"\", \"\"], \n[\"\", \"\"] \n],\n \"paragraph1\": \"\",\n \"callOut\": \"\",\n \"externalLink\": [\"\", \"\"],\n \"paragraph2\": \"\",\n \"note\": \"\",\n \"tip\": \"\",\n \"important\": \"\",\n \"warning\": \"\", \n \"position\": \"\",\n \"documentationURL\": \"\" \n}" }, "referenceAttachesTo": { "compatibleTypes": "->*Any Node*->" }, + "chainAttachesTo": { + "compatibleTypes": "->Tutorial->" + }, "addLeftIcons": true, "level": 1, "icon": "cardano", - "propertyNameAtParent": "tutorials", + "propertyNameAtParent": "tutorialTopics", "properties": [ { "name": "tutorialSteps", "type": "array", "childType": "Tutorial Step", "autoAdd": false + }, + { + "name": "tutorialTopics", + "type": "array", + "childType": "Tutorial Topic", + "autoAdd": false } ] + }, + { + "type": "Tutorial Step", + "menuItems": [ + { + "action": "Play Tutorial Step", + "label": "Play", + "relatedUiObject": "Tutorial", + "actionFunction": "payload.onMenuItemClick" + }, + { + "action": "Resume Tutorial Step", + "label": "Resume", + "relatedUiObject": "Tutorial", + "actionFunction": "payload.onMenuItemClick" + }, + { + "action": "Configure", + "actionFunction": "uiObject.configEditor.activate", + "label": "Configure", + "iconPathOn": "html", + "iconPathOff": "html" + }, + { + "action": "Delete UI Object", + "askConfirmation": true, + "confirmationLabel": "Confirm to Delete", + "label": "Delete", + "iconPathOn": "delete", + "iconPathOff": "delete", + "actionFunction": "payload.onMenuItemClick" + } + ], + "editors": { + "config": true + }, + "initialValues": { + "config": "{ \n \"subTitle\": \"\",\n \"image\": \"\",\n \"definition\": \"\",\n \"bulletListIntro\": \"\",\n \"bulletArray\": \n[\n [\"\", \"\"], \n[\"\", \"\"], \n[\"\", \"\"] \n],\n \"paragraph1\": \"\",\n \"callOut\": \"\",\n \"externalLink\": [\"\", \"\"],\n \"paragraph2\": \"\",\n \"note\": \"\",\n \"tip\": \"\",\n \"important\": \"\",\n \"warning\": \"\", \n \"position\": \"\",\n \"documentationURL\": \"\" \n}" + }, + "referenceAttachesTo": { + "compatibleTypes": "->*Any Node*->" + }, + "chainAttachesTo": { + "compatibleTypes": "->Tutorial->Tutorial Topic->" + }, + "addLeftIcons": true, + "level": 2, + "icon": "tron", + "propertyNameAtParent": "tutorialSteps", + "properties": [ + ] } ] \ No newline at end of file diff --git a/BackendServers/WebServer/AppLoader.js b/BackendServers/WebServer/AppLoader.js index bffa4527a..d34a37a99 100644 --- a/BackendServers/WebServer/AppLoader.js +++ b/BackendServers/WebServer/AppLoader.js @@ -90,6 +90,7 @@ function newAppLoader() { 'Spaces/DesignSpace.js', 'Spaces/SideSpace.js', 'Spaces/DocSpace.js', + 'Spaces/TutorialSpace.js', 'Files/SingleFile.js', 'Files/FileCloud.js', diff --git a/BackendServers/WebServer/index.html b/BackendServers/WebServer/index.html index f074ec0b4..30027805f 100644 --- a/BackendServers/WebServer/index.html +++ b/BackendServers/WebServer/index.html @@ -41,48 +41,30 @@
- -
+ +
 
-
- -
-

Trading Engine

-
-
-
Summary
-

Sub-Title

- +
+
+
+
+
- + - The trading engine hierarchy is t ible and exposed to others. + + +
-

You will use th purposes:

- -

The hierarchyusers.

-
callout text.
-

The hiera feedback capabilities to users.

- - - - -
+
diff --git a/BackendServers/WebServer/main.css b/BackendServers/WebServer/main.css index 74f8c34cc..fb1e63fe0 100644 --- a/BackendServers/WebServer/main.css +++ b/BackendServers/WebServer/main.css @@ -24,6 +24,12 @@ background-color: #fdfdfd; } +.tutorial-form { + padding: 15px; + margin-bottom: 20px; + width: 105%; +} + .tutorial-summary { font-size:120%; color: #808080; @@ -58,7 +64,7 @@ border-radius: 4px; margin: 20px 0; border-top-color: #a6e1ec; - width: 95%; + width: 90%; } .tutorial-alert-success { @@ -70,7 +76,7 @@ border-radius: 4px; margin: 20px 0; border-top-color: #c9e2b3; - width: 95%; + width: 90%; } .tutorial-alert-warning { @@ -82,7 +88,7 @@ border-radius: 4px; margin: 20px 0; border-top-color: #f7e1b5; - width: 95%; + width: 90%; } .tutorial-alert-danger { @@ -94,7 +100,7 @@ border-radius: 4px; margin: 20px 0; border-top-color: #e4b9c0; - width: 95%; + width: 90%; } .tutorial-callout { @@ -105,7 +111,7 @@ border-radius: 3px; border-left-color: #bcd643; font-weight: 500; - width: 92%; + width: 90%; } .tutorial-info-circle:before { @@ -165,4 +171,50 @@ text-rendering:auto; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale +} + +.tutorial-stop-button { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; + padding: 15px; + border: 1px solid transparent; + border-radius: 4px; + margin: 20px 0; + border-top-color: #e4b9c0; + width: 20%; +} + +.tutorial-skip-button { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; + padding: 15px; + border: 1px solid transparent; + border-radius: 4px; + margin: 20px 0; + border-top-color: #f7e1b5; + width: 20%; +} + +.tutorial-done-button { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; + padding: 15px; + border: 1px solid transparent; + border-radius: 4px; + margin: 20px 0; + border-top-color: #c9e2b3; + width: 20%; +} + +.tutorial-buttonsTable { + border-top-color: #a6e1ec; + padding: 15px; + margin: 20px 0; + border: solid 0px; + vertical-align: middle; + min-width: 100px; + width: 105%; } \ No newline at end of file diff --git a/CanvasApp/Canvas.js b/CanvasApp/Canvas.js index a31958ad1..367429a5e 100644 --- a/CanvasApp/Canvas.js +++ b/CanvasApp/Canvas.js @@ -33,6 +33,7 @@ function newCanvas() { topSpace: undefined, sideSpace: undefined, docSpace: undefined, + tutorialSpace: undefined, chartingSpace: undefined, floatingSpace: undefined, panelsSpace: undefined, @@ -62,6 +63,7 @@ function newCanvas() { function finalize() { try { + thisObject.tutorialSpace.finalize() thisObject.docSpace.finalize() thisObject.sideSpace.finalize() thisObject.chartingSpace.finalize() @@ -127,6 +129,9 @@ function newCanvas() { thisObject.docSpace = newDocSpace() thisObject.docSpace.initialize() + thisObject.tutorialSpace = newTutorialSpace() + thisObject.tutorialSpace.initialize() + thisObject.splashScreen = newSplashScreen() let animation = newAnimation() @@ -142,6 +147,7 @@ function newCanvas() { animation.addCallBackFunction('Panels Space Physics', thisObject.panelsSpace.physics) animation.addCallBackFunction('Side Space Physics', thisObject.sideSpace.physics) animation.addCallBackFunction('Doc Space Physics', thisObject.docSpace.physics) + animation.addCallBackFunction('Tutorial Space Physics', thisObject.tutorialSpace.physics) /* Spcaces Drawing */ animation.addCallBackFunction('Floating Space Draw', thisObject.floatingSpace.draw) @@ -152,6 +158,7 @@ function newCanvas() { animation.addCallBackFunction('Top Space Draw', thisObject.topSpace.draw) animation.addCallBackFunction('Side Space Draw', thisObject.sideSpace.draw) animation.addCallBackFunction('Doc Space Draw', thisObject.docSpace.draw) + animation.addCallBackFunction('Tutorial Space Draw', thisObject.tutorialSpace.draw) animation.addCallBackFunction('Splash Screen Draw', thisObject.splashScreen.draw) animation.start() } catch (err) { @@ -572,6 +579,20 @@ function newCanvas() { let container + /* We check if the mouse is over an element of the Doc Space / */ + container = thisObject.tutorialSpace.getContainer(point) + + if (container !== undefined && container.isDraggeable === true) { + containerBeingDragged = container + containerDragStarted = true + containerBeingDragged.eventHandler.raiseEvent('onDragStarted', point) + return + } + + if (container !== undefined && container.isDraggeable === false) { + return + } + /* We check if the mouse is over an element of the Doc Space / */ container = thisObject.docSpace.getContainer(point) @@ -715,6 +736,14 @@ function newCanvas() { let container + /* We check if the mouse is over an element of the Tutorial Space / */ + container = thisObject.tutorialSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_CLICK) + + if (container !== undefined && container.isClickeable === true) { + container.eventHandler.raiseEvent('onMouseClick', point) + return + } + /* We check if the mouse is over an element of the Doc Space / */ container = thisObject.docSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_CLICK) @@ -865,6 +894,16 @@ function newCanvas() { let container + /* We check if the mouse is over an element of the Tutorial Space / */ + if (thisObject.tutorialSpace !== undefined) { + container = thisObject.tutorialSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_OVER) + + if (container !== undefined && container.detectMouseOver === true) { + containerFound() + return + } + } + /* We check if the mouse is over an element of the Doc Space / */ if (thisObject.docSpace !== undefined) { container = thisObject.docSpace.getContainer(point, GET_CONTAINER_PURPOSE.MOUSE_OVER) @@ -983,6 +1022,14 @@ function newCanvas() { event.mousePosition = point let container + /* Doc Space */ + container = canvas.tutorialSpace.getContainer({ x: point.x, y: point.y }) + + if (container !== undefined && container.isWheelable === true) { + container.eventHandler.raiseEvent('onMouseWheel', event) + return false // This instructs the browser not to take the event and scroll the page. + } + /* Doc Space */ container = canvas.docSpace.getContainer({ x: point.x, y: point.y }) diff --git a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TutorialFunctions.js b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TutorialFunctions.js index 4281e8355..f89c89f07 100644 --- a/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TutorialFunctions.js +++ b/CanvasApp/DesignSpace/Workspace/FunctionLibraries/TutorialFunctions.js @@ -1,24 +1,5 @@ function newTutorialFunctions() { thisObject = { - play: play } - const HEIGHT = 800 - const WIDTH = 500 - const MARGIN = 300 return thisObject - - function play(node) { - let docAppDiv = document.getElementById('tutorialStepDiv') - tutorialPosition = { - x: MARGIN, - y: (browserCanvas.height - HEIGHT) / 2 - } - - docAppDiv.style = ' ' + - 'position:fixed; top:' + tutorialPosition.y + 'px; ' + - 'left:' + tutorialPosition.x + 'px; ' + - 'width: ' + WIDTH + 'px;' + - 'height: ' + HEIGHT + 'px;' + - 'z-index:1;' - } } diff --git a/CanvasApp/DesignSpace/Workspace/Workspace.js b/CanvasApp/DesignSpace/Workspace/Workspace.js index 2fb7c7976..a408c2184 100644 --- a/CanvasApp/DesignSpace/Workspace/Workspace.js +++ b/CanvasApp/DesignSpace/Workspace/Workspace.js @@ -638,7 +638,37 @@ function newWorkspace() { break case 'Play Tutorial': { - functionLibraryTutorialFunctions.play(payload.node) + canvas.tutorialSpace.playTutorial(payload.node) + } + break + case 'Play Tutorial Topic': + { + canvas.tutorialSpace.playTutorialTopic(payload.node) + } + break + case 'Play Tutorial Step': + { + canvas.tutorialSpace.playTutorialStep(payload.node) + } + break + case 'Resume Tutorial': + { + canvas.tutorialSpace.resumeTutorial(payload.node) + } + break + case 'Resume Tutorial Topic': + { + canvas.tutorialSpace.resumeTutorialTopic(payload.node) + } + break + case 'Resume Tutorial Step': + { + canvas.tutorialSpace.resumeTutorialStep(payload.node) + } + break + case 'Reset Tutorial Progress': + { + canvas.tutorialSpace.resetTutorialProgress(payload.node) } break case 'Send Webhook Test Message': diff --git a/CanvasApp/FloatingSpace/FloatingObject.js b/CanvasApp/FloatingSpace/FloatingObject.js index a89979978..76901b340 100644 --- a/CanvasApp/FloatingSpace/FloatingObject.js +++ b/CanvasApp/FloatingSpace/FloatingObject.js @@ -29,6 +29,7 @@ function newFloatingObject() { isParentCollapsed: false, frozenManually: false, collapsedManually: false, + unCollapseParent: unCollapseParent, getPinStatus: getPinStatus, getFreezeStatus: getFreezeStatus, getCollapseStatus: getCollapseStatus, @@ -151,6 +152,21 @@ function newFloatingObject() { return thisObject.isCollapsed } + function unCollapseParent() { + if (thisObject.payload !== undefined) { + if (thisObject.payload.parentNode !== undefined) { + if (thisObject.payload.parentNode.payload !== undefined) { + if (thisObject.payload.parentNode.payload.floatingObject !== undefined) { + if (thisObject.payload.parentNode.payload.floatingObject.isCollapsed === true) { + thisObject.payload.parentNode.payload.floatingObject.isCollapsed = false + thisObject.payload.parentNode.payload.floatingObject.unCollapseParent() + } + } + } + } + } + } + function getAngleToParent() { return thisObject.angleToParent } diff --git a/CanvasApp/FloatingSpace/UiObject.js b/CanvasApp/FloatingSpace/UiObject.js index 2481e1e6d..96f49cb53 100644 --- a/CanvasApp/FloatingSpace/UiObject.js +++ b/CanvasApp/FloatingSpace/UiObject.js @@ -791,7 +791,7 @@ function newUiObject() { if (thisObject.payload.parentNode.payload !== undefined) { if (thisObject.payload.parentNode.payload.floatingObject !== undefined) { if (thisObject.payload.parentNode.payload.floatingObject.isCollapsed === true || thisObject.payload.parentNode.payload.floatingObject.isParentCollapsed === true) { - if (thisObject.payload.parentNode.payload.uiObject !== true) { + if (thisObject.payload.parentNode.payload.uiObject.hasError !== true) { thisObject.payload.parentNode.payload.uiObject.setErrorMessage('Error Inside this Branch') } } diff --git a/CanvasApp/Spaces/TutorialSpace.js b/CanvasApp/Spaces/TutorialSpace.js new file mode 100644 index 000000000..a87e4b96a --- /dev/null +++ b/CanvasApp/Spaces/TutorialSpace.js @@ -0,0 +1,471 @@ +function newTutorialSpace() { + const MODULE_NAME = 'Tutorial Space' + let thisObject = { + stop: stop, + skip: skip, + done: done, + playTutorial: playTutorial, + resumeTutorial: resumeTutorial, + playTutorialTopic: playTutorialTopic, + resumeTutorialTopic: resumeTutorialTopic, + playTutorialStep: playTutorialStep, + resumeTutorialStep: resumeTutorialStep, + tutorialTopicDone: tutorialTopicDone, + tutorialStepDone: tutorialStepDone, + resetTutorialProgress: resetTutorialProgress, + container: undefined, + physics: physics, + draw: draw, + getContainer: getContainer, + initialize: initialize, + finalize: finalize + } + + let isInitialized = false + + thisObject.container = newContainer() + thisObject.container.name = MODULE_NAME + thisObject.container.initialize() + thisObject.container.isClickeable = true + thisObject.container.isDraggeable = false + thisObject.container.detectMouseOver = true + thisObject.container.status = 'hidden' + + resize() + + let browserResizedEventSubscriptionId + + let tutorialRootNode + let currentNode + let currentStatus = 'Stopped' + + let tutorialDiv = document.getElementById('tutorialDiv') + let tutorialFormDiv = document.getElementById('tutorialFormDiv') + let htmlImage = document.createElement("IMG") + let currentImageName = 'Never Set' + let newImageName = 'Never Set' + let currentConfig + let newConfig + let newDocumentationURL + let currentDocumentationURL + + return thisObject + + function initialize() { + browserResizedEventSubscriptionId = canvas.eventHandler.listenToEvent('Browser Resized', resize) + isInitialized = true + } + + function finalize() { + canvas.eventHandler.stopListening(browserResizedEventSubscriptionId) + + tutorialRootNode = undefined + currentNode = undefined + + tutorialDiv = undefined + tutorialFormDiv = undefined + image = undefined + } + + function resize() { + thisObject.container.frame.width = 0 + thisObject.container.frame.height = 0 + } + + function getContainer(point, purpose) { + let container + + if (thisObject.container.frame.isThisPointHere(point, true) === true) { + return thisObject.container + } else { + return undefined + } + } + + function physics() { + if (currentNode === undefined) { return } + + switch (currentStatus) { + case 'Stopped': { + makeInvisible() + currentNode = undefined + break + } + case 'Playing Tutorial': { + makeVsible() + break + } + case 'Playing Topic': { + makeVsible() + break + } + case 'Playing Step': { + makeVsible() + break + } + } + + checkImage() + checkDocumentation() + checkReference() + return + + function checkImage() { + let tutorialImageDiv = document.getElementById('tutorialImageDiv') + if (tutorialImageDiv !== null && tutorialImageDiv !== undefined) { + tutorialImageDiv.appendChild(htmlImage) + } + + if (currentImageName === newImageName) { return } + currentImageName = newImageName + htmlImage.src = 'Images/Icons/style-01/' + currentImageName + '.png' + htmlImage.width = "100" + htmlImage.height = "100" + } + + function checkDocumentation() { + if (currentNode === undefined) {return} + let config = JSON.parse(currentNode.config) + let newDocumentationURL = config.documentationURL + if (newDocumentationURL === undefined || newDocumentationURL === "") { + canvas.docSpace.sidePanelTab.close() + } + if (newDocumentationURL === currentDocumentationURL) { return } + + currentDocumentationURL = newDocumentationURL + canvas.docSpace.navigateTo(currentDocumentationURL) + } + + function checkReference() { + /* + If there is a reference parent defined, we will highlight it + and move the designer so that that node be at the center of the screen. + */ + + if (currentNode !== undefined) { + if (currentNode.payload !== undefined) { + if (currentNode.payload.referenceParent !== undefined) { + if (currentNode.payload.referenceParent.payload !== undefined) { + if (currentNode.payload.referenceParent.payload.uiObject !== undefined) { + canvas.floatingSpace.positionAtNode(currentNode.payload.referenceParent) + currentNode.payload.referenceParent.payload.uiObject.highlight() + } + } + } + } + } + } + + function makeInvisible() { + const HEIGHT = 0 + const WIDTH = 0 + const FORM_HEIGHT = 0 + + tutorialPosition = { + x: 100000, + y: 100000 + } + + tutorialDiv.style = ' ' + + 'position:fixed; top:' + tutorialPosition.y + 'px; ' + + 'left:' + tutorialPosition.x + 'px; ' + + 'width: ' + WIDTH + 'px;' + + 'height: ' + HEIGHT + 'px;' + + 'z-index:1;' + + tutorialFormDiv.style = ' ' + + 'position:fixed; top:' + (tutorialPosition.y) + 'px; ' + + 'left:' + tutorialPosition.x + 'px; ' + + 'width: ' + WIDTH + 'px;' + + 'height: ' + FORM_HEIGHT + 'px;' + + 'z-index:1;' + } + + function makeVsible() { + const HEIGHT = 650 + const WIDTH = 400 + const MARGIN = 300 + const FORM_HEIGHT = 80 + + let nodeConfig = JSON.parse(currentNode.config) + switch (nodeConfig.position) { + case 'Left': { + tutorialPosition = { + x: MARGIN, + y: (browserCanvas.height - HEIGHT) / 2 + } + break + } + case 'Center': { + tutorialPosition = { + x: browserCanvas.width / 2 - WIDTH / 2, + y: (browserCanvas.height - HEIGHT) / 2 + } + break + } + case 'Right': { + tutorialPosition = { + x: browserCanvas.width - WIDTH - MARGIN, + y: (browserCanvas.height - HEIGHT) / 2 + } + break + } + default: { + tutorialPosition = { + x: browserCanvas.width / 2 - WIDTH / 2, + y: (browserCanvas.height - HEIGHT) / 2 + } + break + } + } + tutorialDiv.style = ' ' + + 'position:fixed; top:' + tutorialPosition.y + 'px; ' + + 'left:' + tutorialPosition.x + 'px; ' + + 'width: ' + WIDTH + 'px;' + + 'height: ' + HEIGHT + 'px;' + + 'z-index:1;' + + buildHTML() + + tutorialFormDiv.style = ' ' + + 'position:fixed; top:' + (tutorialPosition.y + HEIGHT - FORM_HEIGHT) + 'px; ' + + 'left:' + tutorialPosition.x + 'px; ' + + 'width: ' + WIDTH + 'px;' + + 'height: ' + FORM_HEIGHT + 'px;' + + 'z-index:1;' + } + } + + function playTutorial(node) { + tutorialRootNode = node + currentNode = node + currentStatus = 'Playing Tutorial' + } + + function resumeTutorial(node) { + + } + + function stop() { + tutorialRootNode = undefined + currentStatus = 'Stopped' + } + + function skip() { + + } + + function done() { + /* If we are standing at the Tutorial Node, we do this. */ + advance() + } + + function playTutorialTopic(node) { + currentTopicNode = node + currentNode = node + currentStatus = 'Playing Topic' + findTutorialNode(node) + } + + function resumeTutorialTopic(node) { + + } + + function playTutorialStep(node) { + currentStepNode = node + currentNode = node + currentStatus = 'Playing Step' + findTutorialNode(node) + } + + function resumeTutorialStep(node) { + + } + + function tutorialTopicDone() { + + } + + function tutorialStepDone() { + + } + + function resetTutorialProgress() { + + } + + function findTutorialNode(node) { + /* + We will consider the tutorialRootNode the head of the hirierchy + */ + tutorialRootNode = node + + if (node.payload !== undefined) { + if (node.payload.parentNode !== undefined) { + findTutorialNode(node.payload.parentNode) + } + } + } + + function advance() { + let found + let advanced + + switch (currentStatus) { + case 'Playing Tutorial': { + found = true + findNextNode(tutorialRootNode) + break + } + case 'Playing Topic': { + found = false + findNextNode(tutorialRootNode) + break + } + case 'Playing Step': { + found = false + findNextNode(tutorialRootNode) + break + } + } + + /* + If we can not find a next node, then we stop the tutorial. + */ + if (advanced === undefined) { + stop() + return + } + + /* + If there is a reference parent defined, we will uncollape the brach where it belongs. + */ + if (currentNode.payload.referenceParent !== undefined) { + if (currentNode.payload.referenceParent.payload !== undefined) { + if (currentNode.payload.referenceParent.payload.floatingObject !== undefined) { + currentNode.payload.referenceParent.payload.floatingObject.unCollapseParent() + } + } + } + + function findNextNode(node) { + + for (let i = 0; i < node.tutorialSteps.length; i++) { + + let tutorialStep = node.tutorialSteps[i] + if (found === true) { + currentNode = tutorialStep + currentStatus = 'Playing Step' + advanced = true + return + } + if (tutorialStep.id === currentNode.id) { + found = true + } + } + + for (let i = 0; i < node.tutorialTopics.length; i++) { + + if (advanced === true) { + return + } + + let tutorialTopic = node.tutorialTopics[i] + if (found === true) { + currentNode = tutorialTopic + currentStatus = 'Playing Topic' + advanced = true + return + } + if (tutorialTopic.id === currentNode.id) { + found = true + } + + findNextNode(tutorialTopic, found) + } + } + } + + function buildHTML() { + + newConfig = currentNode.config + if (newConfig === currentConfig) { return } + currentConfig = newConfig + + let nodeConfig = JSON.parse(currentNode.config) + let html = '' + if (nodeConfig.title !== undefined && nodeConfig.title !== '') { + html = html + '

' + nodeConfig.title + '

' + } + html = html + '
' + if (nodeConfig.summary !== undefined && nodeConfig.summary !== '') { + html = html + '
' + nodeConfig.summary + '
' + } + if (nodeConfig.subTitle !== undefined && nodeConfig.subTitle !== '') { + html = html + '

' + nodeConfig.subTitle + '

' + } + if (nodeConfig.definition !== undefined && nodeConfig.definition !== '') { + html = html + '' + html = html + '' + html = html + '' + html = html + '' + html = html + '' + html = html + '
' + if (nodeConfig.image !== undefined && nodeConfig.image !== '') { + html = html + '
' + newImageName = nodeConfig.image + } + html = html + '
' + html = html + '' + nodeConfig.definition + '' + html = html + '
' + } + if (nodeConfig.bulletListIntro !== undefined && nodeConfig.bulletListIntro !== '') { + html = html + '

' + nodeConfig.bulletListIntro + '

' + } + if (nodeConfig.bulletArray !== undefined) { + html = html + '' + } + if (nodeConfig.paragraph1 !== undefined && nodeConfig.paragraph1 !== '') { + html = html + '

' + nodeConfig.paragraph1 + '

' + } + if (nodeConfig.callOut !== undefined && nodeConfig.callOut !== '') { + html = html + '
' + nodeConfig.callOut + '' + if (nodeConfig.externalLink !== undefined) { + html = html + '' + nodeConfig.externalLink[0] + '' + } + html = html + '
' + } + if (nodeConfig.paragraph2 !== undefined && nodeConfig.paragraph2 !== '') { + html = html + '

' + nodeConfig.paragraph2 + '

' + } + if (nodeConfig.paragraph2 !== undefined && nodeConfig.paragraph2 !== '') { + html = html + '

' + nodeConfig.paragraph2 + '

' + } + if (nodeConfig.note !== undefined && nodeConfig.note !== '') { + html = html + '' + } + if (nodeConfig.tip !== undefined && nodeConfig.tip !== '') { + html = html + '' + } + if (nodeConfig.important !== undefined && nodeConfig.important !== '') { + html = html + '' + } + if (nodeConfig.warning !== undefined && nodeConfig.warning !== '') { + html = html + '' + } + html = html + '
' + + tutorialDiv.innerHTML = html + } + + function draw() { + if (isInitialized === false) { return } + } +}