Jelajahi Sumber

Added wip web downloader integration in browser

Toby Chui 2 tahun lalu
induk
melakukan
5a964ce643
2 mengubah file dengan 486 tambahan dan 448 penghapusan
  1. 14 0
      web/Browser/functions/download.js
  2. 472 448
      web/Browser/index.html

+ 14 - 0
web/Browser/functions/download.js

@@ -0,0 +1,14 @@
+/*
+    Download.js
+
+    Download a file given
+    - link
+    - filepath
+    - filename
+*/
+requirelib("http")
+
+http.download(link, filepath, filename);
+
+HTTP_HEADER = "application/json; charset=utf-8";
+sendResp('"OK"');

+ 472 - 448
web/Browser/index.html

@@ -1,449 +1,473 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="UTF-8">
-		<meta name="apple-mobile-web-app-capable" content="yes" />
-		<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
-		<meta name="theme-color" content="#4b75ff">
-		<link rel="stylesheet" href="../script/semantic/semantic.min.css">
-		<script src="../script/jquery.min.js"></script>
-		<script src="../script/ao_module.js"></script>
-		<script src="../script/semantic/semantic.min.js"></script>
-		<link rel="icon" type="image/png" href="img/module_icon.png">
-		<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
-		<title>Browser</title>
-		<style>
-			body{
-				overflow: hidden;
-			}
-			#urlbar{
-				padding-top: 0.2em;
-				padding-bottom: 0.2em;
-				padding-left: 1.2em;
-				padding-right: 0.3em;
-				line-height: 1em;
-			}
-
-			.menuitem{
-				margin-top: 0.2em;
-				padding:0.2em !important;
-				border: 0px !important;
-			}
-
-			.menuitem button{
-				background-color: white !important;
-			}
-
-			.rightMenuItem{
-				margin-top: 0.3em;
-				padding:0.1em !important;
-				border: 0px !important;
-			}
-
-			.rightMenuItem button:not(.inverted){
-				background-color: white !important;
-			}
-
-			#starBtn{
-				padding-right: 0.9em;
-				cursor: pointer !important;
-				background-color: white !important;
-			}
-
-			#starBtn:hover{
-				opacity: 0.7;
-			}
-
-			#xframe{
-				width: 100%;
-				height: calc(100% - 43px);
-				border: 0px solid transparent;
-			}
-
-			#notvdiWarning{
-				position: fixed;
-				bottom: 0px;
-				left: 0px;
-				width: 100%;
-				padding: 0.4em;
-				display: none;
-			}
-
-			#toolbar.proxy{
-				border-bottom: 2px solid #41e8e5;
-			}
-
-			#bookmarkbar{
-				position: fixed;
-				right: 0px;
-				top: 42px;
-				background-color: white;
-				height: calc(100% - 42px);
-				width: 25em;
-				padding: 1.2em;
-				border: 1px solid #dedede;
-
-				box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
-				-webkit-box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
-				-moz-box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
-
-			}
-
-		</style>
-	</head>
-	<body>
-		<div id="toolbar" class="ui top small attached menu" style="background-color: #eceef2; padding-left: 12px; padding-right: 12px;">
-			<div class="ui menuitem">
-				<button class="ui circular tiny icon button" onclick="undoPage();">
-					<i class="arrow left icon"></i>
-				</button>
-			</div>
-			<div class="ui menuitem">
-				<button class="ui circular tiny icon button" onclick="redoPage();">
-					<i class="arrow right icon"></i>
-				</button>
-			</div>
-			<div class="ui menuitem">
-				<button class="ui circular tiny icon button" onclick="refreshPage();">
-					<i class="green refresh icon"></i>
-				</button>
-			</div>
-			<div id="urlbar" class="ui tiny action fluid input">
-				<input id="urlText" type="text" value="about:blank" onkeydown="handleURLKeydown(event);">
-				<button id="starBtn" class="ui icon basic circular tiny button" onclick="addBookMark();">
-					<i class="star icon"></i>
-				</button>
-			</div>
-			<div class="right menu">
-				<div class="ui rightMenuItem">
-					<button class="ui tiny icon button" onclick="toggleBookmark();">
-						<i class="blue bookmark icon"></i>
-					</button>
-				</div>
-				<div class="ui rightMenuItem">
-					<button class="ui tiny icon button" onclick="loadWebsite('about:blank');">
-						<i class="home icon"></i>
-					</button>
-				</div>
-				<div class="ui rightMenuItem">
-					<button class="ui tiny icon button" title="Open in new Window" onclick="openInNewWindow();">
-						<i class="grey external icon"></i>
-					</button>
-				</div>
-			</div>
-		  </div>
-		  <iframe id="xframe" src="./blank.html" allow="fullscreen" referrerpolicy="no-referrer">
-
-		  </iframe>
-		  <div id="bookmarkbar" style="display:none;">
-			<div class="ui container">
-				<div id="bookmarklist" class="ui middle aligned divided list">
-					
-				</div>
-			</div>
-		  </div>
-		  <div id="notvdiWarning">
-			<div class="ui yellow message">
-				<i class="close icon"></i>
-				<div class="header">
-					<i class="remove icon"></i>Not Recommended Way of Usage
-				</div>
-				<p>Please use your native browser windows instead of this iframe browser for maximum website compatibility.</p>
-			</div>
-		  </div>
-		<script>
-			let historyStack = [];
-			let historyPopStack = [];
-			let currentURL = "about:blank";
-			let currentTitle = "";
-			let bookmarkBuffer = [];
-			let titleBuffer = {};
-
-			//Check if currently under vdi mode
-			if (ao_module_virtualDesktop == false){
-				$("#notvdiWarning").show();
-			}
-
-			$('.message .close').on('click', function() {
-				$(this).closest('.message').transition('fade');
-			});
-
-			function toggleBookmark(){
-				$("#bookmarkbar").fadeToggle('fast');
-			}
-
-			//Perform window resize element size calculation
-			$(window).on("resize", function(){
-				updateResizeElements();
-			});
-			function updateResizeElements(){
-				let buttonWidths = 0;
-				$(".menuitem").each(function(){
-					buttonWidths+= $(this).width();
-				});
-
-				let urlbarWidth = window.innerWidth - buttonWidths - 20;
-				$("#urlbar").css("width", urlbarWidth + "px");
-			}
-			updateResizeElements();
-
-
-			function handleURLKeydown(e){
-				if (e.keyCode == 13){
-					let url = $("#urlText").val();
-					loadWebsite(url);
-				}
-			}
-
-			function refreshPage(){
-				loadWebsite(currentURL);
-			}
-
-			function undoPage(){
-				//Push current page into the history pop stack
-				if (historyStack.length == 0){
-					return;
-				}
-				let currentBackupURL = currentURL;
-				historyPopStack.push(currentBackupURL);
-				let targetReturnURL = historyStack.pop();
-				loadWebsite(targetReturnURL, false);
-			}
-
-			function redoPage(){
-				if (historyPopStack.length == 0){
-					return;
-				}
-				restorePage = historyPopStack.pop();
-				historyStack.push(currentURL);
-				loadWebsite(restorePage, false);
-			}
-
-			function openInNewWindow(){
-				window.open(currentURL);
-			}
-
-			function getTitleFromURL(targetURL){
-				var title = targetURL;
-				if (targetURL.includes("//")){
-					title = targetURL.substr(targetURL.indexOf("/") + 2, targetURL.length);
-				}
-				
-				return title;
-			}
-
-			function loadWebsite(targetURL, writeRestoreRecord = true){
-				if (writeRestoreRecord && currentURL != targetURL){
-					historyPopStack = [];
-				}
-				
-				//Handle special case
-				if (targetURL == "about:blank"){
-					$("#xframe").removeAttr("srcdoc");
-					$("#xframe").attr("src", "blank.html");
-					$("#urlText").val(targetURL);
-					$("#toolbar").removeClass("proxy");
-					if (writeRestoreRecord && currentURL != targetURL){
-						historyStack.push(JSON.parse(JSON.stringify(currentURL)));
-					}
-					currentURL = targetURL;
-					return;
-				}
-
-				//Remove the tailing / if exists
-				if (targetURL.substr(targetURL.length - 1, targetURL.length) == "/"){
-					targetURL = targetURL.substr(0, targetURL.length - 1);
-				}
-
-				$("#xframe").removeAttr("srcdoc");
-				$("#xframe").attr("src", "loading.html");
-
-				//Filter the URL if required
-				if (targetURL.substr(0,4) != "http"){
-					if (location.protocol !== "https:"){
-						//This page is currently loaded in http mode. Add http:// to it
-						targetURL = "http://" + targetURL;
-					}else{
-						targetURL = "https://" + targetURL;
-					}
-				}
-
-				$("#urlText").val(targetURL);
-				if (writeRestoreRecord && currentURL != targetURL){
-					historyStack.push(JSON.parse(JSON.stringify(currentURL)));
-				}
-				currentURL = targetURL;
-				
-
-				//Check if the website allow iframe
-				checkIfAllowIframing(targetURL, function(allowIframe, redirectTarget){
-					if (allowIframe == null){
-						$("#xframe").attr("src", "notfound.html#" + targetURL);
-					}else{
-						if (allowIframe == true){
-							$("#xframe").removeAttr("srcdoc");
-							$("#xframe").attr("src", targetURL);
-							$("#toolbar").removeClass("proxy");
-							$("#xframe").on("load", function(){
-								//Get the page title
-								ao_module_agirun("Browser/functions/getTitle.js", {url: targetURL}, function(data){
-									if (data == ""){
-										let title = getTitleFromURL(targetURL);
-										ao_module_setWindowTitle(title);
-										currentTitle = title;
-									}else{
-										ao_module_setWindowTitle(data);
-										currentTitle = data;
-									}
-								});
-								$("#xframe").off("load");
-							});
-						}else{
-							proxyWebContent(targetURL, function(content){
-								$("#xframe").attr("src", "");
-								$("#xframe").attr("srcdoc", content);
-								$("#toolbar").addClass("proxy");
-
-								//Extract the title
-								var matches = content.match(/<title>(.*?)<\/title>/);
-								if (matches == null){
-									let title = getTitleFromURL(targetURL);
-									ao_module_setWindowTitle(title);
-									currentTitle = title;
-								}else{
-									var title = matches[0].replace(/(<([^>]+)>)/gi, "");
-									ao_module_setWindowTitle(title);
-									currentTitle = title;
-								}
-    							
-							});
-							//alert("Target website do not allow embedding");
-						}
-
-						if (redirectTarget != undefined && redirectTarget != ""){
-							$("#urlText").val(redirectTarget);
-						}
-					}
-				});
-
-				updateBookmarkButtonColor();
-			}
-
-			function updateBookmarkButtonColor(){
-				if (insideBookmark(currentURL)){
-					$("#starBtn").addClass("yellow");
-				}else{
-					$("#starBtn").removeClass("yellow");
-				}
-			}
-
-
-			function initbookmark(){
-				ao_module_agirun("Browser/functions/bookmark.js", {opr: "read"}, function(bookmarkData){
-					bookmarkBuffer = bookmarkData;
-					console.log("BOOKMARK DATA", bookmarkData);
-					ao_module_agirun("Browser/functions/bookmark.js", {rtype: "titles", opr: "read"}, function(data){
-						titleBuffer = data;
-						$("#bookmarklist").html("");
-						bookmarkBuffer.forEach(bookmark => {
-							let matchingTitle = titleBuffer[bookmark];
-							if (matchingTitle == undefined){
-								matchingTitle = getTitleFromURL(bookmark);
-							}
-							//Render the bookmark table
-							$("#bookmarklist").append(`
-								<div class="item">
-									<div class="right floated content">
-									<div class="ui mini icon basic blue circular button" onclick="loadWebsite('${bookmark}');"><i class="ui linkify icon"></i></div>
-									</div>
-									<div class="content">
-										${matchingTitle}
-									</div>
-							</div>`);
-						});
-
-						if (bookmarkBuffer.length == 0){
-							$("#bookmarklist").append(`<div class="item">
-								<div class="content">
-									<i class="ui bookmark icon"></i> No bookmark saved
-									</div>
-								</div>`);
-						}
-						
-					});
-				});
-
-				
-			}
-			initbookmark();
-
-			function addBookMark(){
-				if (bookmarkBuffer.includes(currentURL)){
-					//Remove bookmark
-					bookmarkBuffer = bookmarkBuffer.filter(e => e !== currentURL);
-					delete(titleBuffer[currentURL]);
-				}else{
-					//Add bookmark
-					bookmarkBuffer.push(currentURL);
-
-					//Remove array in the table
-					bookmarkBuffer = bookmarkBuffer.filter(function(item, pos, self) {
-						return self.indexOf(item) == pos;
-					});
-
-					titleBuffer[currentURL] = currentTitle;
-				}
-				
-				ao_module_agirun("Browser/functions/bookmark.js", {"opr": "write", "newBookmarkArray": JSON.stringify(bookmarkBuffer)}, function(data){
-					ao_module_agirun("Browser/functions/bookmark.js", {"rtype": "titles", "opr": "write", "newTitleArray": JSON.stringify(titleBuffer)}, function(data){
-						console.log(data);
-						updateBookmarkButtonColor();
-						initbookmark();
-					});
-				});
-			}
-
-			function insideBookmark(url){
-				return bookmarkBuffer.includes(url);
-			}
-
-
-			function proxyWebContent(url, callback){
-				ao_module_agirun("Browser/functions/proxy.js", {
-					url: url,
-				}, function(data){
-					callback(data);
-				});
-			}
-
-			//Check if a website can be directly embedded as iframe, can return true / false /null (site not exists)
-			function checkIfAllowIframing(url, callback){
-				ao_module_agirun("Browser/functions/getHeader.js", {
-					url: url
-				}, function(data){
-					let xFrameOptions = JSON.parse(data);
-					let header = "";
-					if (xFrameOptions.header == null){
-						xFrameOptions.header = "deny";
-					}else{
-						header = xFrameOptions.header.toLowerCase().trim();
-					}
-					
-					let location = xFrameOptions.location;
-					if (header == "null"){
-						//Site not exists
-						callback(null);
-					}
-					
-					if (header == "sameorigin" || header == "deny"){
-						//This webpage do not allow iframeing
-						callback(false, location);
-					}else{
-						//This webpage allow iframing. Show it
-						callback(true, location);
-					}
-				}, undefined, 5000)
-			}
-		</script>
-	</body>
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<meta name="apple-mobile-web-app-capable" content="yes" />
+		<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1"/>
+		<meta name="theme-color" content="#4b75ff">
+		<link rel="stylesheet" href="../script/semantic/semantic.min.css">
+		<script src="../script/jquery.min.js"></script>
+		<script src="../script/ao_module.js"></script>
+		<script src="../script/semantic/semantic.min.js"></script>
+		<link rel="icon" type="image/png" href="img/module_icon.png">
+		<link rel="manifest" crossorigin="use-credentials" href="manifest.json">
+		<title>Browser</title>
+		<style>
+			body{
+				overflow: hidden;
+			}
+			#urlbar{
+				padding-top: 0.2em;
+				padding-bottom: 0.2em;
+				padding-left: 1.2em;
+				padding-right: 0.3em;
+				line-height: 1em;
+			}
+
+			.menuitem{
+				margin-top: 0.2em;
+				padding:0.2em !important;
+				border: 0px !important;
+			}
+
+			.menuitem button{
+				background-color: white !important;
+			}
+
+			.rightMenuItem{
+				margin-top: 0.3em;
+				padding:0.1em !important;
+				border: 0px !important;
+			}
+
+			.rightMenuItem button:not(.inverted):not(.sidebarToggle.selected){
+				background-color: white !important;
+			}
+
+			#starBtn{
+				padding-right: 0.9em;
+				cursor: pointer !important;
+				background-color: white !important;
+			}
+
+			#starBtn:hover{
+				opacity: 0.7;
+			}
+
+			#xframe{
+				width: 100%;
+				height: calc(100% - 43px);
+				border: 0px solid transparent;
+			}
+
+			#notvdiWarning{
+				position: fixed;
+				bottom: 0px;
+				left: 0px;
+				width: 100%;
+				padding: 0.4em;
+				display: none;
+			}
+
+			#toolbar.proxy{
+				border-bottom: 2px solid #41e8e5;
+			}
+
+			.sidebar{
+				position: fixed;
+				right: 0px;
+				top: 42px;
+				background-color: white;
+				height: calc(100% - 42px);
+				width: 25em;
+				padding: 1.2em;
+				border: 1px solid #dedede;
+
+				box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
+				-webkit-box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
+				-moz-box-shadow: -10px 1px 11px -5px rgba(0,0,0,0.15);
+
+			}
+
+			.sidebarToggle.selected{
+				background-color: #e2e2e2 !important;
+			}
+
+		</style>
+	</head>
+	<body>
+		<div id="toolbar" class="ui top small attached menu" style="background-color: #eceef2; padding-left: 12px; padding-right: 12px;">
+			<div class="ui menuitem">
+				<button class="ui circular tiny icon button" onclick="undoPage();">
+					<i class="arrow left icon"></i>
+				</button>
+			</div>
+			<div class="ui menuitem">
+				<button class="ui circular tiny icon button" onclick="redoPage();">
+					<i class="arrow right icon"></i>
+				</button>
+			</div>
+			<div class="ui menuitem">
+				<button class="ui circular tiny icon button" onclick="refreshPage();">
+					<i class="green refresh icon"></i>
+				</button>
+			</div>
+			<div id="urlbar" class="ui tiny action fluid input">
+				<input id="urlText" type="text" value="about:blank" onkeydown="handleURLKeydown(event);">
+				<button id="starBtn" class="ui icon basic circular tiny button" onclick="addBookMark();">
+					<i class="star icon"></i>
+				</button>
+			</div>
+			<div class="right menu">
+				<div class="ui rightMenuItem">
+					<button class="ui tiny icon button sidebarToggle" onclick="toggleBookmark(this);">
+						<i class="blue bookmark icon"></i>
+					</button>
+				</div>
+				<div class="ui rightMenuItem">
+					<button class="ui tiny icon button" onclick="loadWebsite('about:blank');">
+						<i class="home icon"></i>
+					</button>
+				</div>
+				<div class="ui rightMenuItem">
+					<button class="ui tiny icon button" title="Open in new Window" onclick="openInNewWindow();">
+						<i class="grey external icon"></i>
+					</button>
+				</div>
+				<div class="ui rightMenuItem">
+					<button class="ui tiny icon button sidebarToggle" title="Download Manager" onclick="toggleDownloadManager(this);">
+						<i class="grey download icon"></i>
+					</button>
+				</div>
+			</div>
+		  </div>
+		  <iframe id="xframe" src="./blank.html" allow="fullscreen" referrerpolicy="no-referrer">
+
+		  </iframe>
+		  <div id="bookmarkbar" class="sidebar" style="display:none;">
+			<div class="ui container">
+				<div id="bookmarklist" class="ui middle aligned divided list">
+					
+				</div>
+			</div>
+		  </div>
+		  <div id="downloadManager" class="sidebar" style="display:none;">
+			<div class="ui container">
+				<h1>Download Manger</h1>
+			</div>
+		  </div>
+		  <div id="notvdiWarning">
+			<div class="ui yellow message">
+				<i class="close icon"></i>
+				<div class="header">
+					<i class="remove icon"></i>Not Recommended Way of Usage
+				</div>
+				<p>Please use your native browser windows instead of this iframe browser for maximum website compatibility.</p>
+			</div>
+		  </div>
+		<script>
+			let historyStack = [];
+			let historyPopStack = [];
+			let currentURL = "about:blank";
+			let currentTitle = "";
+			let bookmarkBuffer = [];
+			let titleBuffer = {};
+
+			//Check if currently under vdi mode
+			if (ao_module_virtualDesktop == false){
+				$("#notvdiWarning").show();
+			}
+
+			$('.message .close').on('click', function() {
+				$(this).closest('.message').transition('fade');
+			});
+
+			function toggleBookmark(object){
+				$(".sidebar:not(#bookmarkbar)").hide();
+				$("#bookmarkbar").fadeToggle('fast');
+				$(".sidebarToggle.selected").removeClass("selected");
+				$(object).addClass('selected');
+			}
+
+			function toggleDownloadManager(object){
+				$(".sidebar:not(#downloadManager)").hide();
+				$("#downloadManager").fadeToggle('fast');
+				$(".sidebarToggle.selected").removeClass("selected");
+				$(object).addClass('selected');
+			}
+
+			//Perform window resize element size calculation
+			$(window).on("resize", function(){
+				updateResizeElements();
+			});
+			function updateResizeElements(){
+				let buttonWidths = 0;
+				$(".menuitem").each(function(){
+					buttonWidths+= $(this).width();
+				});
+
+				let urlbarWidth = window.innerWidth - buttonWidths - 20;
+				$("#urlbar").css("width", urlbarWidth + "px");
+			}
+			updateResizeElements();
+
+
+			function handleURLKeydown(e){
+				if (e.keyCode == 13){
+					let url = $("#urlText").val();
+					loadWebsite(url);
+				}
+			}
+
+			function refreshPage(){
+				loadWebsite(currentURL);
+			}
+
+			function undoPage(){
+				//Push current page into the history pop stack
+				if (historyStack.length == 0){
+					return;
+				}
+				let currentBackupURL = currentURL;
+				historyPopStack.push(currentBackupURL);
+				let targetReturnURL = historyStack.pop();
+				loadWebsite(targetReturnURL, false);
+			}
+
+			function redoPage(){
+				if (historyPopStack.length == 0){
+					return;
+				}
+				restorePage = historyPopStack.pop();
+				historyStack.push(currentURL);
+				loadWebsite(restorePage, false);
+			}
+
+			function openInNewWindow(){
+				window.open(currentURL);
+			}
+
+			function getTitleFromURL(targetURL){
+				var title = targetURL;
+				if (targetURL.includes("//")){
+					title = targetURL.substr(targetURL.indexOf("/") + 2, targetURL.length);
+				}
+				
+				return title;
+			}
+
+			function loadWebsite(targetURL, writeRestoreRecord = true){
+				if (writeRestoreRecord && currentURL != targetURL){
+					historyPopStack = [];
+				}
+				
+				//Handle special case
+				if (targetURL == "about:blank"){
+					$("#xframe").removeAttr("srcdoc");
+					$("#xframe").attr("src", "blank.html");
+					$("#urlText").val(targetURL);
+					$("#toolbar").removeClass("proxy");
+					if (writeRestoreRecord && currentURL != targetURL){
+						historyStack.push(JSON.parse(JSON.stringify(currentURL)));
+					}
+					currentURL = targetURL;
+					return;
+				}
+
+				//Remove the tailing / if exists
+				if (targetURL.substr(targetURL.length - 1, targetURL.length) == "/"){
+					targetURL = targetURL.substr(0, targetURL.length - 1);
+				}
+
+				$("#xframe").removeAttr("srcdoc");
+				$("#xframe").attr("src", "loading.html");
+
+				//Filter the URL if required
+				if (targetURL.substr(0,4) != "http"){
+					if (location.protocol !== "https:"){
+						//This page is currently loaded in http mode. Add http:// to it
+						targetURL = "http://" + targetURL;
+					}else{
+						targetURL = "https://" + targetURL;
+					}
+				}
+
+				$("#urlText").val(targetURL);
+				if (writeRestoreRecord && currentURL != targetURL){
+					historyStack.push(JSON.parse(JSON.stringify(currentURL)));
+				}
+				currentURL = targetURL;
+				
+
+				//Check if the website allow iframe
+				checkIfAllowIframing(targetURL, function(allowIframe, redirectTarget){
+					if (allowIframe == null){
+						$("#xframe").attr("src", "notfound.html#" + targetURL);
+					}else{
+						if (allowIframe == true){
+							$("#xframe").removeAttr("srcdoc");
+							$("#xframe").attr("src", targetURL);
+							$("#toolbar").removeClass("proxy");
+							$("#xframe").on("load", function(){
+								//Get the page title
+								ao_module_agirun("Browser/functions/getTitle.js", {url: targetURL}, function(data){
+									if (data == ""){
+										let title = getTitleFromURL(targetURL);
+										ao_module_setWindowTitle(title);
+										currentTitle = title;
+									}else{
+										ao_module_setWindowTitle(data);
+										currentTitle = data;
+									}
+								});
+								$("#xframe").off("load");
+							});
+						}else{
+							proxyWebContent(targetURL, function(content){
+								$("#xframe").attr("src", "");
+								$("#xframe").attr("srcdoc", content);
+								$("#toolbar").addClass("proxy");
+
+								//Extract the title
+								var matches = content.match(/<title>(.*?)<\/title>/);
+								if (matches == null){
+									let title = getTitleFromURL(targetURL);
+									ao_module_setWindowTitle(title);
+									currentTitle = title;
+								}else{
+									var title = matches[0].replace(/(<([^>]+)>)/gi, "");
+									ao_module_setWindowTitle(title);
+									currentTitle = title;
+								}
+    							
+							});
+							//alert("Target website do not allow embedding");
+						}
+
+						if (redirectTarget != undefined && redirectTarget != ""){
+							$("#urlText").val(redirectTarget);
+						}
+					}
+				});
+
+				updateBookmarkButtonColor();
+			}
+
+			function updateBookmarkButtonColor(){
+				if (insideBookmark(currentURL)){
+					$("#starBtn").addClass("yellow");
+				}else{
+					$("#starBtn").removeClass("yellow");
+				}
+			}
+
+
+			function initbookmark(){
+				ao_module_agirun("Browser/functions/bookmark.js", {opr: "read"}, function(bookmarkData){
+					bookmarkBuffer = bookmarkData;
+					console.log("BOOKMARK DATA", bookmarkData);
+					ao_module_agirun("Browser/functions/bookmark.js", {rtype: "titles", opr: "read"}, function(data){
+						titleBuffer = data;
+						$("#bookmarklist").html("");
+						bookmarkBuffer.forEach(bookmark => {
+							let matchingTitle = titleBuffer[bookmark];
+							if (matchingTitle == undefined){
+								matchingTitle = getTitleFromURL(bookmark);
+							}
+							//Render the bookmark table
+							$("#bookmarklist").append(`
+								<div class="item">
+									<div class="right floated content">
+									<div class="ui mini icon basic blue circular button" onclick="loadWebsite('${bookmark}');"><i class="ui linkify icon"></i></div>
+									</div>
+									<div class="content">
+										${matchingTitle}
+									</div>
+							</div>`);
+						});
+
+						if (bookmarkBuffer.length == 0){
+							$("#bookmarklist").append(`<div class="item">
+								<div class="content">
+									<i class="ui bookmark icon"></i> No bookmark saved
+									</div>
+								</div>`);
+						}
+						
+					});
+				});
+
+				
+			}
+			initbookmark();
+
+			function addBookMark(){
+				if (bookmarkBuffer.includes(currentURL)){
+					//Remove bookmark
+					bookmarkBuffer = bookmarkBuffer.filter(e => e !== currentURL);
+					delete(titleBuffer[currentURL]);
+				}else{
+					//Add bookmark
+					bookmarkBuffer.push(currentURL);
+
+					//Remove array in the table
+					bookmarkBuffer = bookmarkBuffer.filter(function(item, pos, self) {
+						return self.indexOf(item) == pos;
+					});
+
+					titleBuffer[currentURL] = currentTitle;
+				}
+				
+				ao_module_agirun("Browser/functions/bookmark.js", {"opr": "write", "newBookmarkArray": JSON.stringify(bookmarkBuffer)}, function(data){
+					ao_module_agirun("Browser/functions/bookmark.js", {"rtype": "titles", "opr": "write", "newTitleArray": JSON.stringify(titleBuffer)}, function(data){
+						console.log(data);
+						updateBookmarkButtonColor();
+						initbookmark();
+					});
+				});
+			}
+
+			function insideBookmark(url){
+				return bookmarkBuffer.includes(url);
+			}
+
+
+			function proxyWebContent(url, callback){
+				ao_module_agirun("Browser/functions/proxy.js", {
+					url: url,
+				}, function(data){
+					callback(data);
+				});
+			}
+
+			//Check if a website can be directly embedded as iframe, can return true / false /null (site not exists)
+			function checkIfAllowIframing(url, callback){
+				ao_module_agirun("Browser/functions/getHeader.js", {
+					url: url
+				}, function(data){
+					let xFrameOptions = JSON.parse(data);
+					let header = "";
+					if (xFrameOptions.header == null){
+						xFrameOptions.header = "deny";
+					}else{
+						header = xFrameOptions.header.toLowerCase().trim();
+					}
+					
+					let location = xFrameOptions.location;
+					if (header == "null"){
+						//Site not exists
+						callback(null);
+					}
+					
+					if (header == "sameorigin" || header == "deny"){
+						//This webpage do not allow iframeing
+						callback(false, location);
+					}else{
+						//This webpage allow iframing. Show it
+						callback(true, location);
+					}
+				}, undefined, 5000)
+			}
+		</script>
+	</body>
 </html>