mirror of
https://github.com/Qortal/qortal.git
synced 2025-02-14 19:25:48 +00:00
pulled alpha's recent changes for hopefully final release candidate
This commit is contained in:
parent
fd5ba48611
commit
38fd0c55a0
@ -1,5 +1,57 @@
|
|||||||
console.log("Gateway mode");
|
console.log("Gateway mode");
|
||||||
|
|
||||||
|
function sendRequestToExtension(
|
||||||
|
requestType,
|
||||||
|
payload,
|
||||||
|
timeout = 750
|
||||||
|
) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const requestId = Math.random().toString(36).substring(2, 15); // Generate a unique ID for the request
|
||||||
|
const detail = {
|
||||||
|
type: requestType,
|
||||||
|
payload,
|
||||||
|
requestId,
|
||||||
|
timeout: timeout / 1000,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Store the timeout ID so it can be cleared later
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
document.removeEventListener("qortalExtensionResponses", handleResponse);
|
||||||
|
reject(new Error("Request timed out"));
|
||||||
|
}, timeout); // Adjust timeout as necessary
|
||||||
|
|
||||||
|
function handleResponse(event) {
|
||||||
|
const { requestId: responseId, data } = event.detail;
|
||||||
|
if (requestId === responseId) {
|
||||||
|
// Match the response with the request
|
||||||
|
document.removeEventListener("qortalExtensionResponses", handleResponse);
|
||||||
|
clearTimeout(timeoutId); // Clear the timeout upon successful response
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("qortalExtensionResponses", handleResponse);
|
||||||
|
document.dispatchEvent(
|
||||||
|
new CustomEvent("qortalExtensionRequests", { detail })
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const isExtensionInstalledFunc = async () => {
|
||||||
|
try {
|
||||||
|
const response = await sendRequestToExtension(
|
||||||
|
"REQUEST_IS_INSTALLED",
|
||||||
|
{},
|
||||||
|
750
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
// not installed
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function qdnGatewayShowModal(message) {
|
function qdnGatewayShowModal(message) {
|
||||||
const modalElementId = "qdnGatewayModal";
|
const modalElementId = "qdnGatewayModal";
|
||||||
|
|
||||||
@ -32,7 +84,7 @@ function qdnGatewayShowModal(message) {
|
|||||||
document.body.appendChild(modalElement);
|
document.body.appendChild(modalElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("message", (event) => {
|
window.addEventListener("message", async (event) => {
|
||||||
if (event == null || event.data == null || event.data.length == 0) {
|
if (event == null || event.data == null || event.data.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -59,6 +111,8 @@ window.addEventListener("message", (event) => {
|
|||||||
case "GET_LIST_ITEMS":
|
case "GET_LIST_ITEMS":
|
||||||
case "ADD_LIST_ITEMS":
|
case "ADD_LIST_ITEMS":
|
||||||
case "DELETE_LIST_ITEM":
|
case "DELETE_LIST_ITEM":
|
||||||
|
const isExtInstalledRes = await isExtensionInstalledFunc()
|
||||||
|
if(isExtInstalledRes?.version) return;
|
||||||
const errorString = "Interactive features were requested, but these are not yet supported when viewing via a gateway. To use interactive features, please access using the Qortal UI desktop app. More info at: https://qortal.org";
|
const errorString = "Interactive features were requested, but these are not yet supported when viewing via a gateway. To use interactive features, please access using the Qortal UI desktop app. More info at: https://qortal.org";
|
||||||
response = "{\"error\": \"" + errorString + "\"}"
|
response = "{\"error\": \"" + errorString + "\"}"
|
||||||
|
|
||||||
|
@ -1,3 +1,118 @@
|
|||||||
|
let customQDNHistoryPaths = []; // Array to track visited paths
|
||||||
|
let currentIndex = -1; // Index to track the current position in the history
|
||||||
|
let isManualNavigation = true; // Flag to control when to add new paths. set to false when navigating through a back/forward call
|
||||||
|
|
||||||
|
|
||||||
|
function resetVariables(){
|
||||||
|
let customQDNHistoryPaths = [];
|
||||||
|
let currentIndex = -1;
|
||||||
|
let isManualNavigation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNameAfterService(url) {
|
||||||
|
try {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
const pathParts = parsedUrl.pathname.split('/');
|
||||||
|
|
||||||
|
// Find the index of "WEBSITE" or "APP" and get the next part
|
||||||
|
const serviceIndex = pathParts.findIndex(part => part === 'WEBSITE' || part === 'APP');
|
||||||
|
|
||||||
|
if (serviceIndex !== -1 && pathParts[serviceIndex + 1]) {
|
||||||
|
return pathParts[serviceIndex + 1];
|
||||||
|
} else {
|
||||||
|
return null; // Return null if "WEBSITE" or "APP" is not found or has no following part
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Invalid URL provided:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function parseUrl(url) {
|
||||||
|
try {
|
||||||
|
const parsedUrl = new URL(url);
|
||||||
|
|
||||||
|
// Check if isManualNavigation query exists and is set to "false"
|
||||||
|
const isManual = parsedUrl.searchParams.get("isManualNavigation");
|
||||||
|
|
||||||
|
if (isManual !== null && isManual == "false") {
|
||||||
|
isManualNavigation = false
|
||||||
|
// Optional: handle this condition if needed (e.g., return or adjust the response)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove theme, identifier, and time queries if they exist
|
||||||
|
parsedUrl.searchParams.delete("theme");
|
||||||
|
parsedUrl.searchParams.delete("identifier");
|
||||||
|
parsedUrl.searchParams.delete("time");
|
||||||
|
parsedUrl.searchParams.delete("isManualNavigation");
|
||||||
|
// Extract the pathname and remove the prefix if it matches "render/APP" or "render/WEBSITE"
|
||||||
|
const path = parsedUrl.pathname.replace(/^\/render\/(APP|WEBSITE)\/[^/]+/, "");
|
||||||
|
|
||||||
|
// Combine the path with remaining query params (if any)
|
||||||
|
return path + parsedUrl.search;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Invalid URL provided:", error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tell the client to open a new tab. Done when an app is linking to another app
|
||||||
|
function openNewTab(data){
|
||||||
|
window.parent.postMessage({
|
||||||
|
action: 'SET_TAB',
|
||||||
|
requestedHandler:'UI',
|
||||||
|
payload: data
|
||||||
|
}, '*');
|
||||||
|
}
|
||||||
|
// sends navigation information to the client in order to manage back/forward navigation
|
||||||
|
function sendNavigationInfoToParent(isDOMContentLoaded){
|
||||||
|
window.parent.postMessage({
|
||||||
|
action: 'NAVIGATION_HISTORY',
|
||||||
|
requestedHandler:'UI',
|
||||||
|
payload: {
|
||||||
|
customQDNHistoryPaths,
|
||||||
|
currentIndex,
|
||||||
|
isDOMContentLoaded: isDOMContentLoaded ? true : false
|
||||||
|
}
|
||||||
|
}, '*');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleQDNResourceDisplayed(pathurl, isDOMContentLoaded) {
|
||||||
|
// make sure that an empty string the root path
|
||||||
|
const path = pathurl || '/'
|
||||||
|
if (!isManualNavigation) {
|
||||||
|
isManualNavigation = true
|
||||||
|
// If the navigation is automatic (back/forward), do not add new entries
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If it's a new path, add it to the history array and adjust the index
|
||||||
|
if (customQDNHistoryPaths[currentIndex] !== path) {
|
||||||
|
|
||||||
|
customQDNHistoryPaths = customQDNHistoryPaths.slice(0, currentIndex + 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add the new path and move the index to the new position
|
||||||
|
customQDNHistoryPaths.push(path);
|
||||||
|
currentIndex = customQDNHistoryPaths.length - 1;
|
||||||
|
sendNavigationInfoToParent(isDOMContentLoaded)
|
||||||
|
} else {
|
||||||
|
currentIndex = customQDNHistoryPaths.length - 1
|
||||||
|
sendNavigationInfoToParent(isDOMContentLoaded)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reset isManualNavigation after handling
|
||||||
|
isManualNavigation = true;
|
||||||
|
}
|
||||||
|
|
||||||
function httpGet(url) {
|
function httpGet(url) {
|
||||||
var request = new XMLHttpRequest();
|
var request = new XMLHttpRequest();
|
||||||
request.open("GET", url, false);
|
request.open("GET", url, false);
|
||||||
@ -156,7 +271,7 @@ function convertToResourceUrl(url, isLink) {
|
|||||||
return buildResourceUrl(c.service, c.name, c.identifier, c.path, isLink);
|
return buildResourceUrl(c.service, c.name, c.identifier, c.path, isLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("message", (event) => {
|
window.addEventListener("message", async (event) => {
|
||||||
if (event == null || event.data == null || event.data.length == 0) {
|
if (event == null || event.data == null || event.data.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -201,7 +316,48 @@ window.addEventListener("message", (event) => {
|
|||||||
|
|
||||||
case "LINK_TO_QDN_RESOURCE":
|
case "LINK_TO_QDN_RESOURCE":
|
||||||
if (data.service == null) data.service = "WEBSITE"; // Default to WEBSITE
|
if (data.service == null) data.service = "WEBSITE"; // Default to WEBSITE
|
||||||
|
|
||||||
|
const nameOfCurrentApp = getNameAfterService(window.location.href);
|
||||||
|
// Check to see if the link is an external app. If it is, request that the client opens a new tab instead of manipulating the window's history stack.
|
||||||
|
if (nameOfCurrentApp !== data.name) {
|
||||||
|
// Attempt to open a new tab and wait for a response
|
||||||
|
const navigationPromise = new Promise((resolve, reject) => {
|
||||||
|
function handleMessage(event) {
|
||||||
|
if (event.data?.action === 'SET_TAB_SUCCESS' && event.data.payload?.name === data.name) {
|
||||||
|
window.removeEventListener('message', handleMessage);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('message', handleMessage);
|
||||||
|
|
||||||
|
// Send the message to the parent window
|
||||||
|
openNewTab({
|
||||||
|
name: data.name,
|
||||||
|
service: data.service,
|
||||||
|
identifier: data.identifier,
|
||||||
|
path: data.path
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set a timeout to reject the promise if no response is received within 200ms
|
||||||
|
setTimeout(() => {
|
||||||
|
window.removeEventListener('message', handleMessage);
|
||||||
|
reject(new Error("No response within 200ms"));
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle the promise, and if it times out, fall back to the else block
|
||||||
|
navigationPromise
|
||||||
|
.then(() => {
|
||||||
|
console.log('Tab opened successfully');
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.warn('No response, proceeding with window.location');
|
||||||
window.location = buildResourceUrl(data.service, data.name, data.identifier, data.path, true);
|
window.location = buildResourceUrl(data.service, data.name, data.identifier, data.path, true);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.location = buildResourceUrl(data.service, data.name, data.identifier, data.path, true);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case "LIST_QDN_RESOURCES":
|
case "LIST_QDN_RESOURCES":
|
||||||
@ -351,10 +507,18 @@ window.addEventListener("message", (event) => {
|
|||||||
if (data.inverse != null) url = url.concat("&inverse=" + data.inverse);
|
if (data.inverse != null) url = url.concat("&inverse=" + data.inverse);
|
||||||
return httpGetAsyncWithEvent(event, url);
|
return httpGetAsyncWithEvent(event, url);
|
||||||
|
|
||||||
|
|
||||||
|
case "PERFORMING_NON_MANUAL":
|
||||||
|
isManualNavigation = false
|
||||||
|
currentIndex = data.currentIndex
|
||||||
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Pass to parent (UI), in case they can fulfil this request
|
// Pass to parent (UI), in case they can fulfil this request
|
||||||
event.data.requestedHandler = "UI";
|
event.data.requestedHandler = "UI";
|
||||||
parent.postMessage(event.data, '*', [event.ports[0]]);
|
parent.postMessage(event.data, '*', [event.ports[0]]);
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +687,8 @@ const qortalRequestWithTimeout = (request, timeout) =>
|
|||||||
/**
|
/**
|
||||||
* Send current page details to UI
|
* Send current page details to UI
|
||||||
*/
|
*/
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
resetVariables()
|
||||||
qortalRequest({
|
qortalRequest({
|
||||||
action: "QDN_RESOURCE_DISPLAYED",
|
action: "QDN_RESOURCE_DISPLAYED",
|
||||||
service: _qdnService,
|
service: _qdnService,
|
||||||
@ -531,6 +696,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
identifier: _qdnIdentifier,
|
identifier: _qdnIdentifier,
|
||||||
path: _qdnPath
|
path: _qdnPath
|
||||||
});
|
});
|
||||||
|
// send to the client the first path when the app loads.
|
||||||
|
const firstPath = parseUrl(window?.location?.href || "")
|
||||||
|
handleQDNResourceDisplayed(firstPath, true);
|
||||||
|
// Increment counter when page fully loads
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -538,12 +707,20 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
*/
|
*/
|
||||||
navigation.addEventListener('navigate', (event) => {
|
navigation.addEventListener('navigate', (event) => {
|
||||||
const url = new URL(event.destination.url);
|
const url = new URL(event.destination.url);
|
||||||
|
|
||||||
let fullpath = url.pathname + url.hash;
|
let fullpath = url.pathname + url.hash;
|
||||||
|
const processedPath = (fullpath.startsWith(_qdnBase)) ? fullpath.slice(_qdnBase.length) : fullpath;
|
||||||
qortalRequest({
|
qortalRequest({
|
||||||
action: "QDN_RESOURCE_DISPLAYED",
|
action: "QDN_RESOURCE_DISPLAYED",
|
||||||
service: _qdnService,
|
service: _qdnService,
|
||||||
name: _qdnName,
|
name: _qdnName,
|
||||||
identifier: _qdnIdentifier,
|
identifier: _qdnIdentifier,
|
||||||
path: (fullpath.startsWith(_qdnBase)) ? fullpath.slice(_qdnBase.length) : fullpath
|
path: processedPath
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Put a timeout so that the DOMContentLoaded listener's logic executes before the navigate listener
|
||||||
|
setTimeout(()=> {
|
||||||
|
handleQDNResourceDisplayed(processedPath);
|
||||||
|
}, 100)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user