專案

一般

配置概況

工作單 #238 » custom.js

marlboro chu, 2025-06-30 02:54

 
$(function () {
const urlParams = new URLSearchParams(window.location.search);
if (sessionStorage.getItem('token') !== null) {
if(!window.grafanaBootData.user.login){
sessionStorage.setItem('isLoggedOut', '1');
}
}
sessionStorage.setItem('current_dashboard', '');
if (urlParams.has('auth_token')) {
const token = urlParams.get('auth_token');
if ( token && sessionStorage.getItem('isLoggedOut') == '1' &&
sessionStorage.getItem('token') !== null && token === sessionStorage.getItem('token')) {
// 清除 URL
//sessionStorage.removeItem('token');
window.history.replaceState({}, document.title, window.location.pathname);
window.location.href = '/logout';
}else{
// 儲存到 sessionStorage
sessionStorage.removeItem('isLoggedOut');
sessionStorage.setItem('token', token);
//console.log('auth_token 已儲存至 sessionStorage');
}
}
//console.log(window.grafanaBootData);

if( 'admin' != window.grafanaBootData.user.login ){
resizeDashboard();
}

//for (const [key, value] of urlParams.entries()) {
//console.log(`${key} = ${value}`);
//}
/*
if (urlParams.has('kiosk') ) {
setTimeout(function () {
applyKioskLayout();
}, 100);
}
if('admin' != window.grafanaBootData.user.login ){
setTimeout(function () {
hideAdminOnlyUI();
}, 100);
}
*/
/*
observer.observe(target, {
childList: true,
subtree: true,
//attributeFilter: ['class']
});
*/

setTimeout(() => {
//console.log('begin load custom js');
const target = document.body;
//const target = document.querySelector('.react-grid-layout');
//console.log(target);
const observer = new MutationObserver((mutationsList, observer) => {
//console.log('👀 mutation triggered!');
//console.log(mutationsList);
//const navToolbar = $('div[data-testid="data-testid Nav toolbar"]');
//const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
//for (const [key, value] of urlParams.entries()) {
// console.log(`${key} = ${value}`);
//}
for (const mutation of mutationsList) {
if (mutation.target.closest && (
mutation.target.closest('.react-grid-layout') ||
mutation.target.closest('header')
)
) {
//console.log('mutation triggered:' + $(mutation.target));
if (urlParams.has('kiosk') ) {
applyKioskLayout();
}else {
if('admin' != window.grafanaBootData.user.login ){
hideAdminOnlyUI();
}
}
const currentPath = new URL(window.location.href).pathname;
const storedPath = sessionStorage.getItem('current_dashboard');
if (currentPath !== storedPath){
if( 'admin' != window.grafanaBootData.user.login ){
reloadDashboard();
}
}
sessionStorage.setItem('current_dashboard', currentPath);
updateLocaleSettings();
/*
if( 'admin' != window.grafanaBootData.user.login ){
console.log('reload dashboard');
reloadDashboard();
}
*/
}
//$('ul[aria-label="Navigation"]').hide();
//
//$('button[title="Menu"]').hide();
//$('button[data-testid="data-testid Toggle menu"]').hide();
//$('button[data-testid="data-testid Share dashboard"]').hide();
//$('button[aria-label="New"]').hide();
}
});
if (!target) {
console.warn('#reactRoot 不存在');
return;
}
//console.log("🚀 observer will now attach");
observer.observe(target, {
childList: true,
subtree: true,
attributeFilter: ['class']
});
//console.log(observer);
}, 100);
});

function createToolbarLogout(){
const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
if (toolbar.is(':visible') && toolbar.find('a[href="/logout"]').length === 0 ) {
if($('header').find('button[aria-label="Help"]').length > 0){
$('button[title="Toggle top search bar"]').trigger('click');
}
}
toolbar.append(
$('<a>', {
href: '/logout',
text: 'Logout',
target: '_self',
css: {
'text-decoration': 'none',
'padding': '2px 8px',
'margin-left': 'auto',
'border-radius': '4px',
//'background': '#f9f9f9',
'border': '1px solid #ccc',
'cursor': 'pointer'
}
})
);
}

function createControlsLogout(){
const controls = $('div[data-testid="data-testid dashboard controls"]');
if(controls && controls.is(':visible') && controls.find('a[href="/logout"]').length === 0){
controls.append(
$('<a>', {
href: '/logout',
text: 'Logout',
target: '_self',
css: {
'text-decoration': 'none',
'padding': '2px 8px',
'margin-left': 'auto',
'border-radius': '4px',
//'background': '#f9f9f9',
'border': '1px solid #ccc',
'cursor': 'pointer'
}
})
);
}
}

let resizeTimer;

function reloadDashboard(){
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () {
rearrangePanel();
}, 1*500);
}

function resizeDashboard(){
$(window).on('resize', function() {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () {
rearrangePanel();
}, 1*500);
});
}

function applyKioskLayout(){
const navToolbar = $('div[data-testid="data-testid Nav toolbar"]');
const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
navToolbar.closest('header').closest('div').children(':not(header)').filter('div').first().css( 'padding-top','0px');
$('div[data-testid="data-testid dashboard controls"]').parent().closest('div').css('top','0px');
navToolbar.closest('header').hide();
$('button[title="Menu"]').css('display', 'none');

}

function hideAdminOnlyUI() {
//data-testid Toggle menu
//Toggle menu
//$('button[data-testid="data-testid Toggle menu"]').hide();
//console.log('hide admin only');
$('button[data-testid*="Toggle menu"]').hide();
$('button[title="Menu"]').hide();

const toolbar = $('div.css-1ntsjus-NavToolbar-actions');
if (toolbar.is(':visible')) {
if (toolbar.find('a[href="/logout"]').length === 0) {
createToolbarLogout();
}
toolbar.children().each(function () {
if (!$(this).is('a[href="/logout"]')) {
$(this).hide();
}
});
}
}

let rearangeStatus = false;

function isPanelReady() {
return $('.react-grid-layout').find('div.react-grid-layout').length > 0;
}

function rearrangePanel (){
if(!isPanelReady()){
reloadDashboard();
return;
}
//console.log('rearrange panel...');
const gridLayout = $('.react-grid-layout .react-grid-layout').first();
const gridItems = gridLayout.children('.react-grid-item').get();
const matched = $(gridItems).filter('[data-griditem-key^="grid-item-"]');
const layoutWidth = parseInt($(gridLayout).css('width'),10);
const firstPanelWidth = parseInt($(matched[0]).css('width'), 10);
//console.log('layoutWidth:'+layoutWidth+' / firstPanelWidth:'+firstPanelWidth);
if( layoutWidth - firstPanelWidth < 30 ){
gridItems.sort((a, b) => {
const idA = parseInt($(a).attr('data-griditem-key').match(/\d+$/)[0] || '0');
const idB = parseInt($(b).attr('data-griditem-key').match(/\d+$/)[0] || '0');
//console.log('idA:'+idA+' / idB:'+idB);
return idA - idB;
});
gridLayout.empty().append(gridItems);
let currentY = 0;
//if(!rearangeStatus){
$(gridItems).each(function (index) {
const height = $(this).outerHeight(true); // 包含 margin/padding 的實際高度
const x = 0;
const y = currentY;
if(index > 1)
$(this).css('transform', `translate(${x}px, ${y}px)`);
//console.log('before = '+height+':'+currentY);
currentY += height+6; // 下一個 panel 的起始 y
//console.log(currentY);
});
rearangeStatus = true;
//}
}
//window.dispatchEvent(new Event('resize'));
}

const translations = {
"Logout": "登出",
"No data": "查無資訊",
"The query didn't return any results.": "查無資訊",
"Dashboard": "儀表板",
"User": "使用者"
};

const translatedDashboards = ['R970100', 'R970101'];



function updateLocaleSettings(){
const currentDashboard = sessionStorage.getItem('current_dashboard');
const shouldTranslate = translatedDashboards.some(code =>
currentDashboard?.includes(code)
);

if (shouldTranslate) {
translatePageText();
} else {
restoreOriginalText();
}
/*
if (currentDashboard && currentDashboard.includes('R970100')) {
translatePageText();
}else{
restoreOriginalText();
}
*/
}

function escapeRegExp(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

function translateTextNode(originalText) {
return Object.entries(translations).reduce((text, [en, zh]) => {
const pattern = escapeRegExp(en);
return text.replace(new RegExp(pattern, 'g'), zh);
}, originalText);
}

function translatePageText() {
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);

let node;
while ((node = walker.nextNode())) {
const parentTag = node.parentNode?.nodeName?.toLowerCase();

// 跳過 style, script, meta, title, head 等不該修改的區域
if (['style', 'script', 'meta', 'title', 'noscript', 'head'].includes(parentTag)) {
continue;
}
/*
const originalText = node.nodeValue;
console.log(originalText);
const replacedText = Object.entries(translations).reduce((text, [en, zh]) => {
return text.replace(new RegExp(`\\b${en}\\b`, 'g'), zh);
}, originalText);

if (originalText !== replacedText) {
node.nodeValue = replacedText;
}
*/
const originalText = node.nodeValue;
const replacedText = translateTextNode(originalText);

if (originalText !== replacedText) {
node.parentNode.setAttribute('data-original-text', originalText);
node.nodeValue = replacedText;
}
}
}

function restoreOriginalText() {
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);

let node;
while ((node = walker.nextNode())) {
const parentTag = node.parentNode?.nodeName?.toLowerCase();

// 跳過 style, script, meta, title, head 等不該修改的區域
if (['style', 'script', 'meta', 'title', 'noscript', 'head'].includes(parentTag)) {
continue;
}
const parent = node.parentNode;
const backup = parent?.getAttribute('data-original-text');

if (backup) {
node.nodeValue = backup;
parent.removeAttribute('data-original-text'); // 移除標記
}
}
}
(4-4/7)