/** * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter. * * Puter is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ window.puter_gui_enabled = true; /** * Initializes and configures the GUI (Graphical User Interface) settings based on the provided options. * * The function sets global variables in the window object for various settings such as origins and domain names. * It also handles loading different resources depending on the environment (development or production). * * @param {Object} options - Configuration options to initialize the GUI. * @param {string} [options.gui_origin='https://puter.com'] - The origin URL for the GUI. * @param {string} [options.api_origin='https://api.puter.com'] - The origin URL for the API. * @param {number} [options.max_item_name_length=500] - Maximum allowed length for an item name. * @param {boolean} [options.require_email_verification_to_publish_website=true] - Flag to decide whether email verification is required to publish a website. * * @property {string} [options.app_domain] - Extracted domain name from gui_origin. It's derived automatically if not provided. * @property {string} [window.gui_env] - The environment in which the GUI is running (e.g., "dev" or "prod"). * * @returns {Promise<void>} Returns a promise that resolves when initialization and resource loading are complete. * * @example * window.gui({ * gui_origin: 'https://myapp.com', * api_origin: 'https://myapi.com', * max_item_name_length: 250 * }); */ window.gui = async function(options){ options = options ?? {}; // app_origin is deprecated, use gui_origin instead window.gui_origin = options.gui_origin ?? options.app_origin ?? `https://puter.com`; window.app_domain = options.app_domain ?? new URL(window.gui_origin).hostname; window.hosting_domain = options.hosting_domain ?? 'puter.site'; window.api_origin = options.api_origin ?? "https://api.puter.com"; window.max_item_name_length = options.max_item_name_length ?? 500; window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true; // Add Puter.JS await loadScript('https://js.puter.com/v2/'); // DEV: Load the initgui.js file if we are in development mode if(!window.gui_env || window.gui_env === "dev"){ await loadScript('/initgui.js', {isModule: true}); } // PROD: load the minified bundles if we are in production mode // note: the order of the bundles is important // note: Build script will prepend `window.gui_env="prod"` to the top of the file else if(gui_env === "prod"){ // Load the minified bundles await loadCSS('/dist/bundle.min.css'); await loadScript('/dist/bundle.min.js'); } // 🚀 Launch the GUI 🚀 initgui(); } /** * Dynamically loads an external JavaScript file. * @param {string} url The URL of the external script to load. * @param {Object} [options] Optional configuration for the script. * @param {boolean} [options.isModule] Whether the script is a module. * @param {boolean} [options.defer] Whether the script should be deferred. * @param {Object} [options.dataAttributes] An object containing data attributes to add to the script element. * @returns {Promise} A promise that resolves once the script has loaded, or rejects on error. */ window.loadScript = async function(url, options = {}) { return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = url; // Set default script loading behavior script.async = true; // Handle if it is a module if (options.isModule) { script.type = 'module'; } // Handle defer attribute if (options.defer) { script.defer = true; script.async = false; // When "defer" is true, "async" should be false as they are mutually exclusive } // Add arbitrary data attributes if (options.dataAttributes && typeof options.dataAttributes === 'object') { for (const [key, value] of Object.entries(options.dataAttributes)) { script.setAttribute(`data-${key}`, value); } } // Resolve the promise when the script is loaded script.onload = () => resolve(); // Reject the promise if there's an error during load script.onerror = (error) => reject(new Error(`Failed to load script at url: ${url}`)); // Append the script to the body document.body.appendChild(script); }); }; /** * Dynamically loads an external CSS file. * @param {string} url The URL of the external CSS to load. * @returns {Promise} A promise that resolves once the CSS has loaded, or rejects on error. */ window.loadCSS = async function(url) { return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = url; link.onload = () => { resolve(); }; link.onerror = (error) => { reject(new Error(`Failed to load CSS at url: ${url}`)); }; document.head.appendChild(link); }); }