You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

383 lines
10 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

function loadCSS(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
const _pfui = {
fadeOutElement: ($el, duration = 150, useHidden = false) => {
return new Promise((resolve) => {
$el.style.transition = `opacity ${duration}ms linear`;
$el.style.opacity = "0";
setTimeout(() => {
if (useHidden) {
$el.hidden = true;
} else {
$el.style.display = "none";
}
resolve();
}, duration);
});
},
fadeInElement: (
$el,
duration = 150,
useHidden = false,
display = "block"
) => {
return new Promise((resolve) => {
if (useHidden) {
$el.hidden = false;
} else {
$el.style.display = display;
}
$el.style.opacity = "0";
$el.style.transition = `opacity ${duration}ms`;
requestAnimationFrame(() => {
$el.style.opacity = "1";
});
setTimeout(() => {
resolve();
}, duration);
});
},
queryParentAll: ($el, selector = null) => {
if (!$el || !$el.parentElement) {
return [];
}
const result = [];
let currentElement = $el.parentElement;
while (currentElement) {
// 如果没有提供selector或者当前元素匹配selector
if (!selector || currentElement.matches(selector)) {
result.push(currentElement);
}
currentElement = currentElement.parentElement;
}
return result;
},
queryParent: ($el, selector) => {
if (!$el || !$el.parentElement) {
return null;
}
let currentElement = $el.parentElement;
while (currentElement) {
if (currentElement.matches(selector)) {
return currentElement;
}
currentElement = currentElement.parentElement;
}
return null;
},
compControllers: [],
init: () => {
// Initialize components if any
document.querySelectorAll(".pf-v5-c-tabs").forEach(($tabsBar) => {
if (!_pfui.compControllers.find((c) => c.$el === $tabsBar)) {
const tabs = new _pfui.Tabs($tabsBar);
_pfui.compControllers.push({ $el: $tabsBar, controller: tabs });
}
});
},
};
(function () {
class Tabs {
constructor($tabsBar) {
this.$tabsBar = $tabsBar;
this._handleTabClickEvent = this._handleTabClick.bind(this);
// Find the associated tab panel
if (this.$tabsBar && this.$tabsBar.dataset.tabPanel) {
this.$tabPanel = document.getElementById(
this.$tabsBar.dataset.tabPanel
);
if (this.$tabPanel) {
this._init();
}
}
}
_init() {
this.$tabsBar.querySelectorAll(".pf-v5-c-tabs__link").forEach(($tab) => {
$tab.addEventListener("click", this._handleTabClickEvent);
});
if (this.$tabsBar.dataset.activeTab) {
const $initialTab = this.$tabsBar.querySelector(
`.pf-v5-c-tabs__link[data-tab-target="${this.$tabsBar.dataset.activeTab}"]`
);
if ($initialTab) {
this._activateTabElement($initialTab, false);
}
}
}
destroy() {
this.$tabsBar.querySelectorAll(".pf-v5-c-tabs__link").forEach(($tab) => {
$tab.removeEventListener("click", this._handleTabClickEvent);
});
}
_handleTabClick(e) {
e.preventDefault();
const $tab = e.currentTarget;
this._activateTabElement($tab);
}
_activateTabElement($tab, animate = true, event = true) {
const targetId = $tab.dataset.tabTarget;
if (!targetId) {
return;
}
// Deactivate all tabs
this.$tabsBar.querySelectorAll(".pf-v5-c-tabs__item").forEach(($item) => {
$item.classList.remove("pf-m-current");
const $link = $item.querySelector(".pf-v5-c-tabs__link");
if ($link) {
$link.setAttribute("aria-selected", "false");
}
});
// Activate the clicked tab
const $tabItem = $tab.closest(".pf-v5-c-tabs__item");
if ($tabItem) {
$tabItem.classList.add("pf-m-current");
}
$tab.setAttribute("aria-selected", "true");
// Hide all tab panels
let promises = [];
this.$tabPanel
.querySelectorAll(".pf-v5-c-tab-content")
.forEach(($panel) => {
if (!$panel.hidden) {
if (animate) {
promises.push(_pfui.fadeOutElement($panel, 200, true));
} else {
$panel.hidden = true;
}
}
});
// Show the corresponding tab panel
Promise.all(promises).then(() => {
const $targetPanel = this.$tabPanel.querySelector(
`.pf-v5-c-tab-content[data-tab-id="${targetId}"]`
);
if ($targetPanel) {
if (animate) {
_pfui.fadeInElement($targetPanel, 200, true);
} else {
$targetPanel.hidden = false;
}
this.$tabsBar.dataset.activeTab = targetId;
}
});
if (event) {
// Send pf.tab.activate event
const activateEvent = new CustomEvent("pf.tab.activate", {
detail: {
tabId: targetId,
},
});
this.$tabsBar.dispatchEvent(activateEvent);
}
}
activeTab(tabId, animate = true, event = true) {
const $tab = this.$tabsBar.querySelector(
`.pf-v5-c-tabs__link[data-tab-target="${tabId}"]`
);
if ($tab) {
this._activateTabElement($tab, animate, event);
return true;
}
return false;
}
}
_pfui.Tabs = Tabs;
class Input {
constructor($input) {
this.$input = $input;
this.$control = _pfui.queryParent($input, ".pf-v5-c-form-control");
if (!this.$control) {
throw new Error("Input must be inside a pf-v5-c-form-control element");
}
this.$formGroup = _pfui.queryParent(
this.$control,
".pf-v5-c-form__group"
);
if (!this.$formGroup) {
throw new Error(
"pf-v5-c-form-control must be inside a pf-v5-c-form__group element"
);
}
this.$utilities = this.$control.querySelector(
".pf-v5-c-form-control__utilities"
);
if (!this.$utilities) {
this.$utilities = document.createElement("div");
this.$utilities.className = "pf-v5-c-form-control__utilities";
this.$control.appendChild(this.$utilities);
}
this.$helperTextContainer = this.$formGroup.querySelector(
".pf-v5-c-form__helper-text"
);
if (this.$helperTextContainer) {
this.originalHelp = this.$helperTextContainer.innerHTML;
} else {
this.originalHelp = null;
}
}
setHelpText(message, type = "", isHTML = false) {
if (!this.$helperTextContainer) {
this.$helperTextContainer = document.createElement("div");
this.$helperTextContainer.className = "pf-v5-c-form__helper-text";
this.$helperTextContainer.setAttribute("aria-live", "polite");
this.$formGroup.appendChild(this.$helperTextContainer);
}
let typeClass = "";
if (type === "success") {
typeClass = " pf-m-success";
} else if (type === "warning") {
typeClass = " pf-m-warning";
} else if (type === "error") {
typeClass = " pf-m-error";
}
this.$helperTextContainer.innerHTML = `<div class="pf-v5-c-helper-text">
<div class="pf-v5-c-helper-text__item${typeClass}">
<span class="pf-v5-c-helper-text__item-text"></span>
</div>
</div>`;
let $helperText = this.$helperTextContainer.querySelector(
".pf-v5-c-helper-text__item-text"
);
if (isHTML) {
$helperText.innerHTML = message;
} else {
$helperText.textContent = message;
}
}
restoreHelpText() {
if (this.originalHelp !== null) {
this.$helperTextContainer.innerHTML = this.originalHelp;
} else if (this.$helperTextContainer) {
this.$helperTextContainer.remove();
this.$helperTextContainer = null;
}
}
setError(message = null, force = false) {
if (message) {
if (!force && this.$control.classList.contains("pf-m-error")) {
return;
}
this.$control.classList.add("pf-m-error");
// Add error icon if not present
this.$utilities.innerHTML = `<span class="pf-v5-c-form-control__icon pf-m-status">
<i class="fas fa-exclamation-circle" aria-hidden="true"></i>
</span>`;
this.setHelpText(message, "error");
} else {
if (!force && !this.$control.classList.contains("pf-m-error")) {
return;
}
this.$control.classList.remove("pf-m-error");
// Remove error icon
this.$utilities.innerHTML = "";
this.restoreHelpText();
}
}
setWarning(message = null, force = false) {
if (message) {
if (!force && this.$control.classList.contains("pf-m-warning")) {
return;
}
this.$control.classList.add("pf-m-warning");
// Add warning icon if not present
this.$utilities.innerHTML = `<span class="pf-v5-c-form-control__icon pf-m-status">
<i class="fas fa-exclamation-triangle" aria-hidden="true"></i>
</span>`;
this.setHelpText(message, "warning");
} else {
if (!force && !this.$control.classList.contains("pf-m-warning")) {
return;
}
this.$control.classList.remove("pf-m-warning");
// Remove warning icon
this.$utilities.innerHTML = "";
this.restoreHelpText();
}
}
setSuccess(message = null, force = false) {
if (typeof message === "string" || message === true) {
if (!force && this.$control.classList.contains("pf-m-success")) {
return;
}
this.$control.classList.add("pf-m-success");
// Add success icon if not present
this.$utilities.innerHTML = `<span class="pf-v5-c-form-control__icon pf-m-status">
<i class="fas fa-check-circle" aria-hidden="true"></i>
</span>`;
if (message) {
this.setHelpText(message, "success");
} else {
this.restoreHelpText();
}
} else {
if (!force && !this.$control.classList.contains("pf-m-success")) {
return;
}
this.$control.classList.remove("pf-m-success");
// Remove success icon
this.$utilities.innerHTML = "";
this.restoreHelpText();
}
}
}
_pfui.Input = Input;
})();
document.addEventListener("DOMContentLoaded", () => {
_pfui.init();
});