156 lines
4.7 KiB
JavaScript
156 lines
4.7 KiB
JavaScript
/*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* https://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import { ASSETS, TEMPLATE_IDS } from "./constants.js";
|
|
|
|
/** Cached remix color value */
|
|
let remixColor = null;
|
|
|
|
/**
|
|
* Get CSS variable value from document
|
|
* @param {string} name - CSS variable name
|
|
* @returns {string} Variable value
|
|
*/
|
|
function getCSSVariable(name) {
|
|
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
|
}
|
|
|
|
/**
|
|
* Get the RTX Remix primary color from CSS variables
|
|
* @returns {string} Hex color value
|
|
*/
|
|
export function getRemixColor() {
|
|
if (!remixColor) {
|
|
remixColor = getCSSVariable("--remix-color") || "#76b900";
|
|
}
|
|
return remixColor;
|
|
}
|
|
|
|
/**
|
|
* Load CSS file into the document
|
|
* @param {string} href - Path to CSS file
|
|
*/
|
|
export function loadCSS(href) {
|
|
if (!document.querySelector(`link[href="${href}"]`)) {
|
|
const link = document.createElement("link");
|
|
link.rel = "stylesheet";
|
|
link.href = href;
|
|
document.head.appendChild(link);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load HTML template file and inject into document
|
|
* @param {string} href - Path to HTML template file
|
|
* @returns {Promise<void>}
|
|
*/
|
|
export async function loadHTMLTemplate(href) {
|
|
const templateId = `template-${href.replace(/[^a-zA-Z0-9]/g, "-")}`;
|
|
|
|
// Remove existing template if present (for hot-reload during development)
|
|
const existing = document.getElementById(templateId);
|
|
if (existing) {
|
|
existing.remove();
|
|
}
|
|
|
|
try {
|
|
// Add cache-busting parameter to ensure fresh content
|
|
const cacheBuster = `?t=${Date.now()}`;
|
|
const response = await fetch(href + cacheBuster);
|
|
const html = await response.text();
|
|
|
|
const container = document.createElement("div");
|
|
container.id = templateId;
|
|
container.style.display = "none";
|
|
container.innerHTML = html;
|
|
|
|
document.body.appendChild(container);
|
|
} catch (error) {
|
|
console.error(`Failed to load template from ${href}:`, error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clone a template and return the element
|
|
* @param {string} templateId - ID of the template element
|
|
* @returns {HTMLElement|null}
|
|
*/
|
|
export function cloneTemplate(templateId) {
|
|
const template = document.getElementById(templateId);
|
|
if (!template) {
|
|
console.error(`Template not found: ${templateId}`);
|
|
return null;
|
|
}
|
|
|
|
return template.content.cloneNode(true).firstElementChild;
|
|
}
|
|
|
|
/**
|
|
* Bind data to a cloned template element
|
|
* @param {HTMLElement} element - The cloned template element
|
|
* @param {Object} data - Data object to bind
|
|
* @returns {HTMLElement} The element with bound data
|
|
*/
|
|
export function bindTemplateData(element, data) {
|
|
// Bind text content to span/div/label elements with data-bind attribute
|
|
element.querySelectorAll("span[data-bind], div[data-bind], label[data-bind]").forEach((el) => {
|
|
const key = el.getAttribute("data-bind");
|
|
if (data[key] !== undefined) {
|
|
el.textContent = data[key];
|
|
}
|
|
});
|
|
|
|
// Bind values to input elements with data-bind attribute
|
|
element.querySelectorAll("input[data-bind]").forEach((el) => {
|
|
const key = el.getAttribute("data-bind");
|
|
if (data[key] !== undefined) {
|
|
el.value = data[key];
|
|
}
|
|
});
|
|
|
|
// Bind placeholder to input elements with data-bind-placeholder attribute
|
|
element.querySelectorAll("input[data-bind-placeholder]").forEach((el) => {
|
|
const key = el.getAttribute("data-bind-placeholder");
|
|
if (data[key] !== undefined) {
|
|
el.placeholder = data[key];
|
|
}
|
|
});
|
|
|
|
// Set dataset fields on elements with data-fields attribute
|
|
element.querySelectorAll("[data-fields]").forEach((el) => {
|
|
const fields = el.getAttribute("data-fields");
|
|
if (fields) {
|
|
fields.split(",").forEach((fieldName) => {
|
|
const trimmedField = fieldName.trim();
|
|
if (trimmedField && data[trimmedField] !== undefined) {
|
|
el.dataset[trimmedField] = data[trimmedField];
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
// Bind assets to img elements with data-asset attribute
|
|
element.querySelectorAll("img[data-asset]").forEach((el) => {
|
|
const assetKey = el.getAttribute("data-asset");
|
|
if (assetKey === "remix-icon") {
|
|
el.src = ASSETS.REMIX_ICON;
|
|
}
|
|
});
|
|
|
|
return element;
|
|
}
|