/* Quick Setup Tour This script file contains all the required script for quick setup tour and walkthrough */ //tourStepFactory generate a function that renders the steps in tourModal //Keys: {element, title, desc, tab, pos, scrollto, callback} // elements -> Element (selector) to focus on // tab -> Tab ID to switch pages // pos -> Where to display the tour modal, {topleft, topright, bottomleft, bottomright, center} // scrollto -> Element (selector) to scroll to, can be different from elements function adjustTourModalOverlayToElement(element){; if ($(element) == undefined || $(element).offset() == undefined){ return; } $("#tourModalOverlay").css({ "top": $(element).offset().top, "left": $(element).offset().left, "width": $(element).width(), "height": $(element).height(), }); } var tourOverlayUpdateTicker; function tourStepFactory(config){ return function(){ //Check if this step require tab swap if (config.tab != undefined && config.tab != ""){ //This tour require tab swap. call to openTabById openTabById(config.tab); } if (config.element == undefined){ //No focused element in this step. $(".tourFocusObject").removeClass("tourFocusObject"); $("#tourModal").addClass("nofocus"); $("#tourModalOverlay").hide(); }else{ //Consists of focus element in this step $(".tourFocusObject").removeClass("tourFocusObject"); $(config.element).addClass("tourFocusObject"); $("#tourModal").removeClass("nofocus"); $("#tourModalOverlay").hide(); setTimeout(function(){ //Match the overlay to element position and size $(window).off("resize").on("resize", function(){ adjustTourModalOverlayToElement(config.element); }); if (tourOverlayUpdateTicker != undefined){ clearInterval(tourOverlayUpdateTicker); } tourOverlayUpdateTicker = setInterval(function(){ adjustTourModalOverlayToElement(config.element); }, 300); adjustTourModalOverlayToElement(config.element); $("#tourModalOverlay").fadeIn(); }, 300); } //Get the modal location of this step let showupZone = "center"; if (config.pos != undefined){ showupZone = config.pos } $("#tourModal").attr("position", showupZone); $("#tourModal .tourStepTitle").html(config.title); $("#tourModal .tourStepContent").html(config.desc); if (config.callback != undefined){ config.callback(); } //If there is a target element to scroll to console.log(config.scrollto); if (config.scrollto != undefined){ $('html, body').animate({ scrollTop: $(config.scrollto).offset().top - 100 }, 500); } } } function startQuickStartTour(){ if (currentQuickSetupClass == ""){ msgbox("No selected setup service tour", false); return; } //Show the tour modal $("#tourModal").show(); //Load the tour steps if (tourSteps[currentQuickSetupClass] == undefined || tourSteps[currentQuickSetupClass].length == 0){ //This tour is not defined or empty let notFound = tourStepFactory({ title: "😭 Tour not found", desc: "Seems you are requesting a tour that has not been developed yet. Check back on later!" }); notFound(); //Enable the finish button $("#tourModal .nextStepAvaible").hide(); $("#tourModal .nextStepFinish").show(); return; }else{ tourSteps[currentQuickSetupClass][0](); } updateTourStepCount(); //Disable the previous button if (tourSteps[currentQuickSetupClass].length == 1){ //There are only 1 step in this tour $("#tourModal .nextStepAvaible").hide(); $("#tourModal .nextStepFinish").show(); }else{ $("#tourModal .nextStepAvaible").show(); $("#tourModal .nextStepFinish").hide(); } $("#tourModal .tourStepButtonBack").addClass("disabled"); //Disable body scroll and let tour steps to handle scrolling $("body").css("overflow-y","hidden"); $("#mainmenu").css("pointer-events", "none"); } function updateTourStepCount(){ let tourlistLength = tourSteps[currentQuickSetupClass]==undefined?1:tourSteps[currentQuickSetupClass].length; $("#tourModal .tourStepCounter").text((currentQuickSetupTourStep + 1) + " / " + tourlistLength); } function nextTourStep(){ //Add one to the tour steps currentQuickSetupTourStep++; if (currentQuickSetupTourStep == tourSteps[currentQuickSetupClass].length - 1){ //Already the last step $("#tourModal .nextStepAvaible").hide(); $("#tourModal .nextStepFinish").show(); } updateTourStepCount(); tourSteps[currentQuickSetupClass][currentQuickSetupTourStep](); if (currentQuickSetupTourStep > 0){ $("#tourModal .tourStepButtonBack").removeClass("disabled"); } } function previousTourStep(){ if (currentQuickSetupTourStep > 0){ currentQuickSetupTourStep--; } if (currentQuickSetupTourStep != tourSteps[currentQuickSetupClass].length - 1){ //Not at the last step $("#tourModal .nextStepAvaible").show(); $("#tourModal .nextStepFinish").hide(); } if (currentQuickSetupTourStep == 0){ //Cant go back anymore $("#tourModal .tourStepButtonBack").addClass("disabled"); } updateTourStepCount(); tourSteps[currentQuickSetupClass][currentQuickSetupTourStep](); } //End tour and reset everything function endTourFocus(){ $(".tourFocusObject").removeClass("tourFocusObject"); $(".serviceOption.active").removeClass("active"); currentQuickSetupClass = ""; currentQuickSetupTourStep = 0; $("#tourModal").hide(); $("#tourModal .nextStepAvaible").show(); $("#tourModal .nextStepFinish").hide(); $("#tourModalOverlay").hide(); if (tourOverlayUpdateTicker != undefined){ clearInterval(tourOverlayUpdateTicker); } $("body").css("overflow-y","auto"); $("#mainmenu").css("pointer-events", "auto"); } var tourSteps = { //Homepage steps "homepage": [ tourStepFactory({ title: "🎉 Congratulation on your first site!", desc: "In this tour, you will be guided through the steps required to setup a basic static website using your own domain name with Zoraxy." }), tourStepFactory({ title: "👉 Pointing domain DNS to Zoraxy's IP", desc: `Setup a DNS A Record that points your domain name to this Zoraxy instances public IP address.
Assume your public IP is 93.184.215.14, you should have an A record like this.
Name Type Value
yourdomain.com A 93.184.215.14

If the IP of Zoraxy start from 192.168, you might want to use your router's public IP address and setup port forward for both port 80 and 443 as well.`, callback: function(){ $.get("/api/acme/wizard?step=10", function(data){ if (data.error == undefined){ //Should return the public IP address from acme wizard //Overwrite the sample IP address let originalText = $("#tourModal .tourStepContent").html(); originalText = originalText.split("93.184.215.14").join(data); $("#tourModal .tourStepContent").html(originalText); } }) } }), tourStepFactory({ title: "🏠 Setup Default Site", desc: `If you already have an apache or nginx web server running, use "Reverse Proxy Target" and enter your current web server IP address.
Otherwise, pick "Internal Static Web Server" and click "Apply Change"`, tab: "setroot", element: "#setroot", pos: "bottomright" }), tourStepFactory({ title: "🌐 Enable Static Web Server", desc: `Enable the static web server if it is not already enabled. Skip this step if you are using external web servers like Apache or Nginx.`, tab: "webserv", element: "#webserv", pos: "bottomright" }), tourStepFactory({ title: "📤 Upload Static Website", desc: `Upload your static website files (e.g. HTML files) to the web directory. If remote access is not avaible, you can also upload it with the web server file manager here.`, tab: "webserv", element: "#webserv", pos: "bottomright", scrollto: "#webserv_dirManager" }), tourStepFactory({ title: "💡 Start Zoraxy HTTP listener", desc: `Start Zoraxy (if it is not already running) by pressing the "Start Service" button.
You should now be able to visit your domain and see the static web server contents show up in your browser.`, tab: "status", element: $("#status .poweroptions"), pos: "bottomright", }) ], //Subdomains tour steps "subdomain":[ ], //TLS and ACME tour steps "tls":[ ], }