|
|
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();
|
|
|
});
|