From 0a1b853beb893142495e8903bba85c1df960810f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20Andreas=20Nilsen?= Date: Thu, 7 Aug 2025 14:33:52 +0200 Subject: [PATCH] innsida search now contains a menu. Changed the hotkey to be concequent with other scripts in this repo --- innsida-search.user.js | 265 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 241 insertions(+), 24 deletions(-) diff --git a/innsida-search.user.js b/innsida-search.user.js index 808c6da..4fe033b 100644 --- a/innsida-search.user.js +++ b/innsida-search.user.js @@ -1,11 +1,12 @@ // ==UserScript== // @name Innsida - Quick Search // @namespace http://tampermonkey.net/ -// @version 1.0.4 -// @description `Alt` + `/` to search on Innsida +// @version 1.2.0 +// @description `Ctrl` + `Shift` + `F` to search on Innsida // @author Øyvind Nilsen (on@ntnu.no) // @match https://innsida.ntnu.no/* // @grant none +// @run-at document-end // @icon https://www.google.com/s2/favicons?sz=64&domain=ntnu.no // @updateURL https://git.ntnu.no/M365-Drift/MonkeyMagic/raw/main/innsida-search.user.js // @downloadURL https://git.ntnu.no/M365-Drift/MonkeyMagic/raw/main/innsida-search.user.js @@ -14,39 +15,255 @@ (function() { 'use strict'; + let currentSelection = 0; // 0 = input box, 1+ = menu items + let menuItems = []; + let links = []; + + // Language support + const translations = { + en: { + searchPlaceholder: 'Search Innsida...', + mineNotFound: 'Mine div not found, using default links', + linksFound: 'Found {count} links in "mine" section' + }, + nb: { + searchPlaceholder: 'Søk på Innsida...', + mineNotFound: 'Mine-div ikke funnet, bruker standardlenker', + linksFound: 'Fant {count} lenker i "mine"-seksjonen' + }, + nn: { + searchPlaceholder: 'Søk på Innsida...', + mineNotFound: 'Mine-div ikkje funne, brukar standardlenkjer', + linksFound: 'Fann {count} lenkjer i "mine"-seksjonen' + } + }; + + function getCurrentLanguage() { + const lang = localStorage.getItem('colossus_lang') || 'en'; + return translations[lang] ? lang : 'en'; + } + + function t(key, params = {}) { + const lang = getCurrentLanguage(); + let text = translations[lang][key] || translations.en[key] || key; + + // Replace placeholders + Object.keys(params).forEach(param => { + text = text.replace(`{${param}}`, params[param]); + }); + + return text; + } + + // Create container + const container = document.createElement('div'); + container.style.position = 'fixed'; + container.style.top = '50%'; + container.style.left = '50%'; + container.style.transform = 'translate(-50%, -50%)'; + container.style.zIndex = '10000'; + container.style.display = 'none'; + container.style.backgroundColor = 'white'; + container.style.border = '2px solid #ccc'; + container.style.borderRadius = '8px'; + container.style.padding = '20px'; + container.style.boxShadow = '0 4px 20px rgba(0,0,0,0.3)'; + container.style.minWidth = '300px'; + container.style.maxHeight = '80vh'; + container.style.overflowY = 'auto'; + // Create and style the input box const inputBox = document.createElement('input'); inputBox.type = 'text'; - inputBox.style.position = 'fixed'; - inputBox.style.top = '10px'; - inputBox.style.left = '50%'; - inputBox.style.transform = 'translateX(-50%)'; - inputBox.style.zIndex = '10000'; - inputBox.style.display = 'none'; - inputBox.style.padding = '5px'; + inputBox.style.width = '100%'; + inputBox.style.padding = '10px'; inputBox.style.fontSize = '16px'; - document.body.appendChild(inputBox); + inputBox.style.border = '2px solid #007acc'; + inputBox.style.borderRadius = '4px'; + inputBox.style.marginBottom = '10px'; + inputBox.style.outline = 'none'; + + // Create menu container + const menu = document.createElement('div'); + + container.appendChild(inputBox); + container.appendChild(menu); + document.body.appendChild(container); + + function loadLinksFromMine() { + const mineDiv = document.querySelector('div#mine'); + if (!mineDiv) { + console.log(t('mineNotFound')); + return [ + { text: 'DFØ Selvbetjening', url: 'https://selvbetjening.dfo.no/' }, + { text: 'Bestille', url: 'https://i.ntnu.no/bestille' }, + { text: 'Berg-Hansen', url: 'https://berg-hansen.eu.auth0.com/authorize?client_id=srhy4Jdgs38QCBhnoXBTP58FZ9ES6tmS&response_type=code&connection=Feide&redirect_uri=https://booking.webgate.no/account/callback' }, + { text: 'Parkering Sluppen', url: 'https://innsida.ntnu.no/start/feed/fead7da8-7ddf-3598-96fe-4fc9532a7a0b/6fe863b6-f206-3bb5-9f87-3b169c3a6d45' }, + { text: 'K-Sted', url: 'https://studntnu.sharepoint.com/:x:/s/KommIT/EXdOlr9S_R9ArkhP8IVHLSEBwhcATXuCPXdEwPgNIyVAnw?e=RdaIKK' } + ]; + } + + const linkElements = mineDiv.querySelectorAll('a[href]'); + const extractedLinks = []; + + linkElements.forEach(linkEl => { + const href = linkEl.getAttribute('href'); + const divEl = linkEl.querySelector('div'); + const text = divEl ? divEl.textContent.trim() : href; + + if (href && text) { + extractedLinks.push({ text, url: href }); + } + }); + + console.log(t('linksFound', { count: extractedLinks.length })); + return extractedLinks.length > 0 ? extractedLinks : [ + { text: 'DFØ Selvbetjening', url: 'https://selvbetjening.dfo.no/' }, + { text: 'Bestille', url: 'https://i.ntnu.no/bestille' }, + { text: 'Berg-Hansen', url: 'https://berg-hansen.eu.auth0.com/authorize?client_id=srhy4Jdgs38QCBhnoXBTP58FZ9ES6tmS&response_type=code&connection=Feide&redirect_uri=https://booking.webgate.no/account/callback' }, + { text: 'Parkering Sluppen', url: 'https://innsida.ntnu.no/start/feed/fead7da8-7ddf-3598-96fe-4fc9532a7a0b/6fe863b6-f206-3bb5-9f87-3b169c3a6d45' }, + { text: 'K-Sted', url: 'https://studntnu.sharepoint.com/:x:/s/KommIT/EXdOlr9S_R9ArkhP8IVHLSEBwhcATXuCPXdEwPgNIyVAnw?e=RdaIKK' } + ]; + } + + function createMenu() { + // Clear existing menu + menu.innerHTML = ''; + menuItems = []; + + // Load links from "mine" div only + links = loadLinksFromMine(); + + links.forEach((link, index) => { + const menuItem = document.createElement('div'); + menuItem.textContent = link.text; + menuItem.style.padding = '8px 12px'; + menuItem.style.cursor = 'pointer'; + menuItem.style.borderRadius = '4px'; + menuItem.style.marginBottom = '2px'; + menuItem.style.backgroundColor = '#f5f5f5'; + menuItem.style.border = '1px solid transparent'; + menuItem.style.whiteSpace = 'nowrap'; + menuItem.style.overflow = 'hidden'; + menuItem.style.textOverflow = 'ellipsis'; + menuItem.dataset.url = link.url; + menuItem.title = link.url; // Show full URL on hover + + menuItem.addEventListener('click', function() { + window.location.href = link.url; + }); - // Show the input box when "/" is pressed + menu.appendChild(menuItem); + menuItems.push(menuItem); + }); + } + + function updateSelection() { + // Reset all styles + inputBox.style.borderColor = '#007acc'; + menuItems.forEach(item => { + item.style.backgroundColor = '#f5f5f5'; + item.style.borderColor = 'transparent'; + item.style.color = 'black'; + }); + + // Highlight current selection + if (currentSelection === 0) { + inputBox.style.borderColor = '#0056b3'; + inputBox.focus(); + } else if (currentSelection > 0 && currentSelection <= menuItems.length) { + const selectedItem = menuItems[currentSelection - 1]; + selectedItem.style.backgroundColor = '#007acc'; + selectedItem.style.borderColor = '#0056b3'; + selectedItem.style.color = 'white'; + inputBox.blur(); + + // Scroll into view if needed + selectedItem.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + } + } + + function hideContainer() { + container.style.display = 'none'; + inputBox.value = ''; + currentSelection = 0; + updateSelection(); + } + + function showContainer() { + // Update placeholder text based on current language + inputBox.placeholder = t('searchPlaceholder'); + + createMenu(); // Refresh menu each time + container.style.display = 'block'; + currentSelection = 0; + updateSelection(); + } + + // Show the container when Ctrl+Shift+F is pressed document.addEventListener('keydown', function(event) { - if ((event.altKey || event.metaKey) && event.shiftKey && event.code === 'Digit7') { + if (event.ctrlKey && event.shiftKey && event.key === 'F') { event.preventDefault(); - inputBox.style.display = 'block'; - inputBox.focus(); + showContainer(); + } + }); + + // Handle navigation and actions + document.addEventListener('keydown', function(event) { + // Only handle keys when container is visible + if (container.style.display === 'none') return; + + switch(event.key) { + case 'ArrowDown': + event.preventDefault(); + currentSelection++; + if (currentSelection > menuItems.length) { + currentSelection = 0; // Cycle back to search box + } + updateSelection(); + break; + + case 'ArrowUp': + event.preventDefault(); + currentSelection--; + if (currentSelection < 0) { + currentSelection = menuItems.length; // Cycle to last menu item + } + updateSelection(); + break; + + case 'Enter': + event.preventDefault(); + if (currentSelection === 0) { + // Search on Innsida + const searchQuery = inputBox.value.trim(); + if (searchQuery) { + const url = `https://innsida.ntnu.no/sok?q=${encodeURIComponent(searchQuery)}&pageSize=10&curPage=1`; + window.location.href = url; + } + } else if (currentSelection > 0 && currentSelection <= menuItems.length) { + // Navigate to selected link + const selectedUrl = menuItems[currentSelection - 1].dataset.url; + window.location.href = selectedUrl; + } + break; + + case 'Escape': + event.preventDefault(); + hideContainer(); + break; } }); - // Redirect to the search URL when Enter is pressed - inputBox.addEventListener('keydown', function(event) { - if (event.key === 'Enter') { - const searchQuery = inputBox.value.trim(); - const url = `https://innsida.ntnu.no/sok?q=${encodeURIComponent(searchQuery)}&pageSize=10&curPage=1`; - window.location.href = url; + // Hide container when clicking outside + document.addEventListener('click', function(event) { + if (!container.contains(event.target)) { + hideContainer(); } }); - // Hide the input box when it loses focus - inputBox.addEventListener('blur', function() { - inputBox.style.display = 'none'; + // Prevent container from losing focus when clicking inside + container.addEventListener('click', function(event) { + event.stopPropagation(); }); -})(); +})(); \ No newline at end of file