MediaWiki:Common.js: Difference between revisions
No edit summary |
No edit summary |
||
| Line 460: | Line 460: | ||
ev.preventDefault(); | ev.preventDefault(); | ||
$(this).trigger('click'); | $(this).trigger('click'); | ||
} | |||
}); | |||
})(jQuery); | |||
}); | |||
/* Enable collapsible system */ | |||
mw.loader.load('jquery.makeCollapsible'); | |||
/* Click to expand anywhere */ | |||
mw.loader.using('jquery', function () { | |||
(function ($) { | |||
$(document).on('click', '.ts-expand-block', function (e) { | |||
var targetId = $(this).attr('data-target'); | |||
if (!targetId) return; | |||
var $section = $('#' + targetId); | |||
if ($section.length) { | |||
$section.toggleClass('mw-collapsed'); // open/close | |||
} | } | ||
}); | }); | ||
})(jQuery); | })(jQuery); | ||
}); | }); | ||
Revision as of 13:39, 9 December 2025
$(document).ready(function() {
$('input#searchInput').attr('placeholder', 'Search for Transight Wiki');
});
// Open all external links in a new tab
$(document).ready(function () {
$("a.external").attr("target", "_blank");
});
mw.loader.using('mediawiki.util', function () {
// Force small text
document.documentElement.classList.remove('vector-feature-custom-font-size-standard', 'vector-feature-custom-font-size-large');
document.documentElement.classList.add('vector-feature-custom-font-size-small');
// Force wide layout
document.documentElement.classList.remove('vector-feature-limited-width');
document.documentElement.classList.add('vector-feature-wide-width');
});
/* === Transight site-wide footer (robust body-append) === */
mw.loader.using(['mediawiki.util']).then(function () {
function injectTsFooter() {
if (document.getElementById('ts-footer')) return; // avoid duplicates
var html = '\
<div id="ts-footer" class="ts-footer">\
<div class="ts-footer__container">\
<nav class="ts-footer__sitemap">\
<ul class="ts-footer__col">\
<li class="ts-footer__title">USE CASES</li>\
<li><a href="https://transight.com/solutions/fleet-management/">Fleet Telematics</a></li>\
<li><a href="https://transight.com/solutions/remote-management-system/">Remote Monitoring System</a></li>\
<li><a href="https://transight.com/solutions/automation/">Automation</a></li>\
<li><a href="https://transight.com/solutions/asset-tracking/">Asset Tracking</a></li>\
<li><a href="https://transight.com/transforming-battery-management-for-ev/">Advanced EV Telematics</a></li>\
<li><a href="https://transight.com/remote-cold-chain-management/">Cold Chain Management</a></li>\
<li><a href="https://transight.com/redefining-telematics-in-global-farm-equipment-sector//">Global Farm Equipment Sector</a></li>\
</ul>\
<ul class="ts-footer__col">\
<li class="ts-footer__title">PRODUCTS</li>\
<li><a href="https://telematics.transight.com/Trackers">Trackers</a></li>\
<li><a href="https://telematics.transight.com/Accessories">Accessories</a></li>\
<li><a href="https://transight.com/products/cloud-iot-platform/">Cloud IoT Solutions</a></li>\
</ul>\
<ul class="ts-footer__col">\
<li class="ts-footer__title">SUPPORT</li>\
<li><a href="https://transight.com/client-support/">Product Support</a></li>\
<li><a href="https://telematics.transight.com/">Wiki Knowlege Base</a></li>\
<li><a href="/wiki/RMA_Guidelines">Warranty & Repair</a></li>\
</ul>\
<ul class="ts-footer__col">\
<li class="ts-footer__title">ABOUT US</li>\
<li><a href="https://transight.com/about/">Mission, Vision</a></li>\
<li><a href="/wiki/Career">Career</a></li>\
<li><a href="https://transight.com/contact/">Contacts</a></li>\
</ul>\
<ul class="ts-footer__col">\
<li class="ts-footer__title">LOCATION</li>\
<li>\
<div class="ts-footer__mapbox">\
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3928.5275868424515!2d76.35275553427442!3d10.055785794465395!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x3b080c05015f9bf9%3A0x8e58791613152f5e!2sTransight!5e0!3m2!1sen!2sin!4v1765272619872!5m2!1sen!2sin" \
width="100%" height="140" style="border:0; border-radius:6px;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>\
</div>\
</li>\
</ul>\
</nav>\
<div class="ts-footer__bottom">\
<p class="ts-footer__legal">© 2024, Transight | <a href="/wiki/Privacy">Privacy</a> | <a href="/wiki/Cookies">Cookies</a> | <a href="/wiki/Policies">All Policies</a></p>\
<p class="ts-footer__social"><a href="https://facebook.com">Facebook</a> <a href="https://www.linkedin.com/company/transight/">LinkedIn</a> <a href="https://x.com/transight_iot?s=21">X</a> <a href="https://youtube.com/@transightsystems">YouTube</a> <a href="https://www.instagram.com/transightsystems/">Instagram</a></p>\
</div>\
</div>\
</div>';
document.body.insertAdjacentHTML("beforeend", html);
}
injectTsFooter();
});
/* === Inject floating buttons: "Go to our web" & "Go to Top" === */
mw.loader.using(['mediawiki.util']).then(function () {
// Prevent duplicate injection
if (!document.getElementById('ts-webfab')) {
var webUrl = 'https://transight.com/';
var htmlWeb = ''
+ '<div id="ts-webfab" class="ts-fab">'
+ ' <a class="ts-fab__btn" href="' + webUrl + '" target="_blank" rel="noopener" aria-label="Go to our website"></a>'
+ ' <span class="ts-fab__bubble">Go to our web</span>'
+ '</div>';
document.body.insertAdjacentHTML('beforeend', htmlWeb);
}
if (!document.getElementById('ts-topfab')) {
var htmlTop = ''
+ '<div id="ts-topfab" class="ts-fab">'
+ ' <a class="ts-fab__btn" href="javascript:void(0);" aria-label="Go to top"></a>'
+ ' <span class="ts-fab__bubble">Go to Top</span>'
+ '</div>';
document.body.insertAdjacentHTML('beforeend', htmlTop);
// Smooth scroll to top
document.querySelector('#ts-topfab .ts-fab__btn').addEventListener('click', function() {
window.scrollTo({ top: 0, behavior: 'smooth' });
});
}
});
/* === Transightee: Sticky header helper === */
( function () {
if ( window.transighteeStickyHeaderInit ) return;
window.transighteeStickyHeaderInit = true;
function getTopFixedElementsHeight(excludeEl) {
// find fixed-position elements at the very top (likely toolbars) and sum their heights
var all = document.getElementsByTagName('*');
var sum = 0;
for (var i = 0; i < all.length; i++) {
var el = all[i];
if (el === excludeEl) continue;
var cs = window.getComputedStyle(el);
if (cs.position === 'fixed' && cs.display !== 'none' && el.offsetHeight > 0) {
var rect = el.getBoundingClientRect();
// consider elements whose top is near the top of viewport
if (rect.top >= -2 && rect.top <= 10) {
sum += el.offsetHeight;
}
}
}
return sum;
}
function updateStickyHeader() {
var header = document.querySelector('.vector-header-container');
var pageContainer = document.querySelector('.mw-page-container');
if (!header || !pageContainer) {
// If header or container not present yet, keep trying later
return;
}
// Ensure header has a stable background so it doesn't appear transparent after becoming fixed
try {
var comp = getComputedStyle(header);
if (!header.style.background && comp.backgroundColor && comp.backgroundColor !== 'rgba(0, 0, 0, 0)') {
header.style.backgroundColor = comp.backgroundColor;
}
} catch (e) {
// ignore
}
// Detect any other fixed elements at the top (toolbars) and position header below them
var topOffset = getTopFixedElementsHeight(header);
header.style.top = topOffset + 'px';
// measure header height AFTER top is applied
// force reflow to get accurate size
var height = header.offsetHeight;
// total vertical space header occupies (top offset + header height) = required padding
var totalSpace = topOffset + height;
document.documentElement.style.setProperty('--trans-header-height', totalSpace + 'px');
// add body class to enable CSS that uses the variable
document.body.classList.add('transightee-has-sticky-header');
}
// debounce helper for resize events
var resizeTimer = null;
function scheduleUpdate() {
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(function () {
updateStickyHeader();
resizeTimer = null;
}, 120);
}
document.addEventListener('DOMContentLoaded', function () {
// initial attempt
updateStickyHeader();
// update when all resources loaded (images, fonts can change header height)
window.addEventListener('load', updateStickyHeader);
// keep updated on resize
window.addEventListener('resize', scheduleUpdate);
// Observe mutations inside header (e.g. buttons collapsing/expanding) and update padding
var header = document.querySelector('.vector-header-container');
if (header && window.MutationObserver) {
var mo = new MutationObserver(function () {
scheduleUpdate();
});
mo.observe(header, { attributes: true, childList: true, subtree: true, characterData: true });
// keep reference to avoid GC in some environments
window._transighteeStickyMO = mo;
}
});
// Also try a periodic update a couple of times in case skin scripts alter header after load
var tries = 0;
var intId = setInterval(function () {
updateStickyHeader();
tries++;
if (tries > 6) clearInterval(intId);
}, 300);
}() );
/* Mobile menu and navigation helper for MediaWiki (vanilla JS, no jQuery) */
(function () {
'use strict';
/**
* Utility: safely query a single element
* @param {string} selector
* @returns {Element|null}
*/
function $$(selector) {
return document.querySelector(selector);
}
/**
* Utility: safely query multiple elements
* @param {string} selector
* @returns {NodeListOf<Element>}
*/
function $$$ (selector) {
return document.querySelectorAll(selector);
}
/**
* Create the menu toggle element (hamburger) only if not already present.
* Returns the toggle element.
* @returns {HTMLElement|null}
*/
function ensureMenuToggle () {
var existing = $$('#menu-toggle');
if (existing) return existing;
var toggle = document.createElement('div');
toggle.id = 'menu-toggle';
toggle.setAttribute('role', 'button');
toggle.setAttribute('tabindex', '0');
toggle.setAttribute('aria-label', 'Toggle menu');
toggle.className = 'menu-toggle';
// Create bars
var bar1 = document.createElement('div'); bar1.className = 'bar1';
var bar2 = document.createElement('div'); bar2.className = 'bar2';
var bar3 = document.createElement('div'); bar3.className = 'bar3';
toggle.appendChild(bar1);
toggle.appendChild(bar2);
toggle.appendChild(bar3);
// Click and keyboard handling
function toggleHandler (e) {
// Only handle left click or Enter/Space key
if (e.type === 'click' || e.key === 'Enter' || e.key === ' ') {
mobileMenuToggle();
e.preventDefault();
}
}
toggle.addEventListener('click', toggleHandler, false);
toggle.addEventListener('keydown', toggleHandler, false);
return toggle;
}
/**
* Toggle the mobile menu state by toggling the 'open-toggle' class on #mw-panel
*/
function mobileMenuToggle () {
var panel = $$('#mw-panel');
if (!panel) return;
panel.classList.toggle('open-toggle');
}
/**
* Remove the mobile menu open state when window is wide
*/
function handleResize () {
var panel = $$('#mw-panel');
if (!panel) return;
if (window.innerWidth > 800) {
panel.classList.remove('open-toggle');
}
}
/**
* Copy anchors from a source selector into a target ul inside #p-cactions.
* Keeps existing anchors' href and text.
* @param {string} sourceSelector - e.g. "#p-views a"
*/
function copyAnchorsToPCActions (sourceSelector) {
var anchors = $$$ (sourceSelector);
if (!anchors || anchors.length === 0) return;
var pCActions = $$('#p-cactions');
if (!pCActions) return;
// Find or create inner ul (the original code assumed p-cactions has a ul)
var ul = pCActions.querySelector('ul');
if (!ul) {
ul = document.createElement('ul');
pCActions.appendChild(ul);
}
// Append items (avoid duplicating items by checking href+text)
Array.prototype.forEach.call(anchors, function (a) {
if (!(a && a.href)) return;
// Skip if an identical item already exists
var exists = Array.prototype.some.call(ul.querySelectorAll('a'), function (x) {
return x.href === a.href && x.textContent.trim() === a.textContent.trim();
});
if (exists) return;
var li = document.createElement('li');
var newA = document.createElement('a');
newA.href = a.href;
newA.textContent = a.textContent.trim();
// preserve title if present
if (a.title) newA.title = a.title;
li.appendChild(newA);
ul.appendChild(li);
});
// Make p-cactions visible if there are items
if (ul.children.length > 0) {
pCActions.style.display = 'block';
}
}
/**
* Copy namespace anchors into p-cactions (same as above but from #p-namespaces a)
*/
function copyNamespacesToPCActions () {
copyAnchorsToPCActions('#p-namespaces a');
}
/**
* Take the first anchor inside #p-namespaces, shorten its text at the last space,
* create an anchor and append into the span inside #p-namespaces.
*/
function updateNamespacesFirstElementText () {
var namespaces = $$('#p-namespaces');
if (!namespaces) return;
var anchors = namespaces.querySelectorAll('a');
if (!anchors || anchors.length === 0) return;
var firstAnchor = anchors[0];
var rawText = firstAnchor.textContent.trim();
var newText = rawText;
var lastSpaceIndex = rawText.lastIndexOf(' ');
if (lastSpaceIndex > 0) {
newText = rawText.substring(0, lastSpaceIndex);
}
var span = namespaces.querySelector('span');
if (!span) {
// if span doesn't exist, create and append to #p-namespaces
span = document.createElement('span');
namespaces.appendChild(span);
}
// Create text anchor
var textnodeHref = document.createElement('a');
textnodeHref.href = firstAnchor.href || '#';
textnodeHref.title = firstAnchor.title || '';
textnodeHref.textContent = newText.length > 0 ? newText : rawText;
// Remove previous appended anchor if it exists to avoid duplication
// (Assume it had no special id)
var old = span.querySelector('a');
if (old) span.removeChild(old);
span.appendChild(textnodeHref);
}
/**
* Show p-cactions only when #p-views has anchors (mirrors original logic)
*/
function revealPCActionsIfPViewsNotEmpty () {
var pViews = $$('#p-views');
if (!pViews) return;
var anchors = pViews.querySelectorAll('a');
var pCActions = $$('#p-cactions');
if (!pCActions) return;
if (anchors && anchors.length > 0) {
pCActions.style.display = 'block';
}
}
/**
* Initialization run on DOMContentLoaded
*/
function init () {
// Insert menu-toggle into #mw-head and #mw-panel (if they exist)
var toggle = ensureMenuToggle();
var mwHead = $$('#mw-head');
var mwPanel = $$('#mw-panel');
// Insert a clone (or same node) into both places. Use clones to keep two elements.
if (mwHead) {
// Only append if not already present
if (!mwHead.querySelector('#menu-toggle')) {
mwHead.appendChild(toggle.cloneNode(true));
}
}
if (mwPanel) {
if (!mwPanel.querySelector('#menu-toggle')) {
mwPanel.appendChild(toggle.cloneNode(true));
}
}
// Setup copy operations (safe-guarded)
copyAnchorsToPCActions('#p-views a');
copyNamespacesToPCActions();
updateNamespacesFirstElementText();
revealPCActionsIfPViewsNotEmpty();
// Remove open state on resize > 800
window.addEventListener('resize', handleResize, false);
// A small safety: also run handleResize immediately to ensure correct state on load
handleResize();
}
// Run when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();
// expand collapse for entire column in front page //
mw.loader.using('jquery', function () {
(function ($) {
$(document).on('click', '.ts-expand-block', function (e) {
var $targetBlock = $(this);
var targetId = $targetBlock.attr('data-target');
if (!targetId) return;
var $section = $('#' + targetId);
if (!$section.length) return;
$section.toggleClass('mw-collapsed');
if ($(e.target).closest('a').length === 0) {
e.preventDefault();
}
});
$('.ts-expand-block').attr('role','button').attr('tabindex','0');
$(document).on('keydown', '.ts-expand-block', function (ev) {
if (ev.key === 'Enter' || ev.key === ' ' || ev.key === 'Spacebar') {
ev.preventDefault();
$(this).trigger('click');
}
});
})(jQuery);
});
/* Enable collapsible system */
mw.loader.load('jquery.makeCollapsible');
/* Click to expand anywhere */
mw.loader.using('jquery', function () {
(function ($) {
$(document).on('click', '.ts-expand-block', function (e) {
var targetId = $(this).attr('data-target');
if (!targetId) return;
var $section = $('#' + targetId);
if ($section.length) {
$section.toggleClass('mw-collapsed'); // open/close
}
});
})(jQuery);
});