瀏覽代碼

Finished static web server tour

Toby Chui 8 月之前
父節點
當前提交
209b4f3138
共有 7 個文件被更改,包括 213 次插入119 次删除
  1. 9 0
      mod/acme/acmewizard/acmewizard.go
  2. 1 71
      web/components/quickstart.html
  3. 4 2
      web/components/status.html
  4. 27 26
      web/components/webserv.html
  5. 2 2
      web/index.html
  6. 2 1
      web/main.css
  7. 168 17
      web/script/quicksetup.js

+ 9 - 0
mod/acme/acmewizard/acmewizard.go

@@ -75,6 +75,15 @@ func HandleGuidedStepCheck(w http.ResponseWriter, r *http.Request) {
 		httpServerReachable := isHTTPServerAvailable(domain)
 		js, _ := json.Marshal(httpServerReachable)
 		utils.SendJSONResponse(w, string(js))
+	} else if stepNo == 10 {
+		//Resolve public Ip address for tour
+		publicIp, err := getPublicIPAddress()
+		if err != nil {
+			utils.SendErrorResponse(w, err.Error())
+			return
+		}
+		js, _ := json.Marshal(publicIp)
+		utils.SendJSONResponse(w, string(js))
 	} else {
 		utils.SendErrorResponse(w, "invalid step number")
 	}

+ 1 - 71
web/components/quickstart.html

@@ -72,76 +72,6 @@
         let tourType = $(this).attr("name");
         currentQuickSetupClass = tourType;
     });
-
-    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 .tourStepButtonPrevious").addClass("disabled");
-    }
-
-    function updateTourStepCount(){
-        let tourlistLength = tourSteps[currentQuickSetupClass]==undefined?1:tourSteps[currentQuickSetupClass].length;
-        $("#tourModal .tourStepCounter").text((currentQuickSetupTourStep + 1) + " / " + tourlistLength);
-    }
-
-    function nextStep(){
-        //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 .tourStepButtonPrevious").removeClass("disabled");
-        }
-    }
-
-    //End tour
-    function endTourFocus(){
-        $(".tourFocusObject").removeClass("tourFocusObject");
-        $(".serviceOption.active").removeClass("active");
-        currentQuickSetupClass = "";
-        currentQuickSetupTourStep = 0;
-        $("#tourModal").hide();
-        $("#tourModal .nextStepAvaible").show();
-        $("#tourModal .nextStepFinish").hide();
-        $("#tourModalOverlay").hide();
-    }
-
+   
 </script>
 <script src="script/quicksetup.js"></script>

+ 4 - 2
web/components/status.html

@@ -53,8 +53,10 @@
 </div>
 <div class="standardContainer" style="padding-bottom: 0 !important;">
     <!-- Power Buttons-->
-    <button id="startbtn" class="ui basic button" onclick="startService();"><i class="ui green arrow alternate circle up icon"></i> Start Service</button>
-    <button id="stopbtn" class="ui basic notloopbackOnly disabled button" onclick="stopService();"><i class="ui red minus circle icon"></i> Stop Service</button>
+    <div class="poweroptions" style="display:inline-block;">
+        <button id="startbtn" class="ui basic button" onclick="startService();"><i class="ui green arrow alternate circle up icon"></i> Start Service</button>
+        <button id="stopbtn" class="ui basic notloopbackOnly disabled button" onclick="stopService();"><i class="ui red minus circle icon"></i> Stop Service</button>
+    </div>
     <div class="ui divider"></div>
     <h4>Network Status</h4>
     <p>Overall Network I/O in Current Host Server</p>

+ 27 - 26
web/components/webserv.html

@@ -13,34 +13,35 @@
             </div>
         </h4>
     </div>
-    
-    <h3>Web Server Settings</h3>
-    <div class="ui form">
-        <div class="inline field">
-            <div class="ui toggle checkbox webservRootDisabled">
-                <input id="webserv_enable" type="checkbox" class="hidden">
-                <label>Enable Static Web Server</label>
+    <div>
+        <h3>Web Server Settings</h3>
+        <div class="ui form">
+            <div class="inline field">
+                <div class="ui toggle checkbox webservRootDisabled">
+                    <input id="webserv_enable" type="checkbox" class="hidden">
+                    <label>Enable Static Web Server</label>
+                </div>
             </div>
-        </div>
-        <div class="inline field">
-            <div class="ui toggle checkbox">
-                <input id="webserv_enableDirList" type="checkbox" class="hidden">
-                <label>Enable Directory Listing</label>
-                <small>If this folder do not contains any index files, list the directory of this folder.</small>
+            <div class="inline field">
+                <div class="ui toggle checkbox">
+                    <input id="webserv_enableDirList" type="checkbox" class="hidden">
+                    <label>Enable Directory Listing</label>
+                    <small>If this folder do not contains any index files, list the directory of this folder.</small>
+                </div>
+            </div>
+            <div class="field">
+                <label>Document Root Folder</label>
+                <input id="webserv_docRoot" type="text" readonly="true">
+                <small>
+                    The web server root folder can only be changed via startup flags of zoraxy for security reasons. 
+                    See the -webserv flag for more details.
+                </small>
+            </div>
+            <div class="field webservRootDisabled">
+                <label>Port Number</label>
+                <input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);">
+                <small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small>
             </div>
-        </div>
-        <div class="field">
-            <label>Document Root Folder</label>
-            <input id="webserv_docRoot" type="text" readonly="true">
-            <small>
-                The web server root folder can only be changed via startup flags of zoraxy for security reasons. 
-                See the -webserv flag for more details.
-            </small>
-        </div>
-        <div class="field webservRootDisabled">
-            <label>Port Number</label>
-            <input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);">
-            <small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small>
         </div>
     </div>
     <small><i class="ui blue save icon"></i> Changes are saved automatically</small>

+ 2 - 2
web/index.html

@@ -184,9 +184,9 @@
                 Use your keyboard or click the next button to get going.</p>
             <div class="ui divider"></div>
             <div class="ui equal width grid" align="center">
-                <div class="column"><button class="ui basic small disabled button tourStepButtonBack">Back</button></div>
+                <div class="column"><button onclick="previousTourStep();" class="ui basic small disabled button tourStepButtonBack">Back</button></div>
                 <div class="column"><p style="margin-top: 0.4em">Steps <span class="tourStepCounter">1 / 9</span></p></div>
-                <div class="column nextStepAvaible"><button onclick="nextStep();" class="ui basic right floated small button tourStepButtonNext">Next</button></div>
+                <div class="column nextStepAvaible"><button onclick="nextTourStep();" class="ui basic right floated small button tourStepButtonNext">Next</button></div>
                 <div class="column nextStepFinish"><button onclick="endTourFocus();" class="ui right floated small button tourStepButtonFinish">Finish</button></div>
             </div>
             <button onclick="endTourFocus();" class="ui circular small icon button tourCloseButton"><i class="ui times icon"></i></button>

+ 2 - 1
web/main.css

@@ -153,7 +153,7 @@ body{
     right: 1em;
     display:none;
     max-width: 300px;
-    z-index: 999;
+    z-index: 1000;
 }
 
 /* Confirm Box */
@@ -803,6 +803,7 @@ body{
     width: 340px;
     display:none;
     border: 1px solid rgb(230, 230, 230);
+    box-shadow: 3px 3px 11px -3px rgba(0,0,0,0.3);
 }
 
 /* Locations of tourModal */

+ 168 - 17
web/script/quicksetup.js

@@ -6,20 +6,26 @@
 */
 
 //tourStepFactory generate a function that renders the steps in tourModal
-//Keys: element, title, desc, tab, zone, callback
-//      elements -> Elements to focus on
+//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;
+    }
 
-function adjustTourModalOverlayToElement(element){
     $("#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
@@ -38,17 +44,23 @@ function tourStepFactory(config){
             $(".tourFocusObject").removeClass("tourFocusObject");
             $(config.element).addClass("tourFocusObject");
             $("#tourModal").removeClass("nofocus");
-
-            //Match the overlay to element position and size
-            $(window).off("resize").on("resize", function(){
+            $("#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);
-            })
-            adjustTourModalOverlayToElement(config.element);
-            $("#tourModalOverlay").show();
+                $("#tourModalOverlay").fadeIn();
+            }, 300);
         }
 
-       
-
         //Get the modal location of this step
         let showupZone = "center";
         if (config.pos != undefined){
@@ -62,9 +74,116 @@ function tourStepFactory(config){
         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": [
@@ -73,7 +192,7 @@ var tourSteps = {
             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 your domain's DNS to Zoraxy's IP",
+            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. <br>
             Assume your public IP is 93.184.215.14, you should have an A record like this.
             <table class="ui celled collapsing basic striped table">
@@ -93,14 +212,46 @@ var tourSteps = {
                 </tbody>
             </table>
             <br>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". <br>Otherwise, pick "Internal Static Web Server" and click "Apply Change"`,
+            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. <br>Otherwise, pick "Internal Static Web Server" and click "Apply Change"`,
             tab: "setroot",
-            element: $("#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.<br>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",
         })
     ],