Last active
January 22, 2026 10:04
-
-
Save okkdev/3499d3ead23be42933ff12d5e4b81204 to your computer and use it in GitHub Desktop.
MyAbacus Better Time Display
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Better Time Display | |
| // @namespace Violentmonkey Scripts | |
| // @match https://abaprod01.sympasol.com/portal/myabacus/proj_inandout* | |
| // @grant none | |
| // @version 3.0 | |
| // @author js | |
| // @run-at document-end | |
| // ==/UserScript== | |
| ;(function () { | |
| "use strict" | |
| const selectors = [ | |
| ".hours-container > .va-label > .va-label-text", | |
| ".total-label > .va-label-text", | |
| '[movie-id="id_pnl_workingTime"] .va-label-text', | |
| '[movie-id="id_pnl_overTime"] .va-label-text', | |
| ] | |
| let baseTotal = null | |
| function convertHours() { | |
| document.querySelectorAll(selectors.join(", ")).forEach((el) => { | |
| const match = el.textContent.trim().match(/^(-?)(\d+),(\d+)( Std)?$/) | |
| if (!match) return | |
| const negative = match[1] === "-" | |
| const hours = parseInt(match[2], 10) | |
| const minutes = Math.round(parseFloat("0." + match[3]) * 60) | |
| if (el.closest(".total-label")) { | |
| baseTotal = hours * 60 + minutes | |
| } | |
| const sign = negative ? "-" : "" | |
| el.textContent = `${sign}${hours}h ${minutes}m` | |
| }) | |
| } | |
| function updateLiveHours() { | |
| const toInputs = [ | |
| ...document.querySelectorAll('[id^="id_history_to_"] input'), | |
| ] | |
| const toInput = toInputs.find((el) => el.value.trim() === "") | |
| if (!toInput) return | |
| const row = toInput.closest("vaadin-horizontal-layout") | |
| const fromInput = row.querySelector('[id^="id_history_from_"] input') | |
| const hoursLabel = row.querySelector(".hours-container .va-label-text") | |
| const totalLabel = document.querySelector(".total-label > .va-label-text") | |
| if (!fromInput || fromInput.value.trim() === "") return | |
| const fromMatch = fromInput.value.match(/(\d{1,2})\D(\d{2})/) | |
| if (!fromMatch) return | |
| const fromMinutes = | |
| parseInt(fromMatch[1], 10) * 60 + parseInt(fromMatch[2], 10) | |
| const now = new Date() | |
| const diffMinutes = now.getHours() * 60 + now.getMinutes() - fromMinutes | |
| if (diffMinutes < 0) return | |
| hoursLabel.textContent = `${Math.floor(diffMinutes / 60)}h ${diffMinutes % 60}m` | |
| if (totalLabel && baseTotal !== null) { | |
| const newTotal = baseTotal + diffMinutes | |
| totalLabel.textContent = `${Math.floor(newTotal / 60)}h ${newTotal % 60}m` | |
| } | |
| } | |
| function addNowButton() { | |
| const inputSelectors = [ | |
| '[id^="id_history_from_"] input', | |
| '[id^="id_history_to_"] input', | |
| ] | |
| inputSelectors.forEach((selector) => { | |
| const inputs = [...document.querySelectorAll(selector)] | |
| const emptyInput = inputs.find((el) => el.value.trim() === "") | |
| if (!emptyInput) return | |
| const vaadinField = emptyInput.closest("vaadin-text-field") | |
| if (!vaadinField) return | |
| if (vaadinField.parentElement.querySelector(".now-btn")) return | |
| const btn = document.createElement("button") | |
| btn.textContent = "Now" | |
| btn.className = "now-btn va-button-secondary" | |
| btn.style.cssText = ` | |
| position: absolute; | |
| transform: translate(-105%, 25%); | |
| ` | |
| btn.addEventListener("click", (e) => { | |
| e.preventDefault() | |
| const now = new Date() | |
| const hours = String(now.getHours()).padStart(2, "0") | |
| const minutes = String(now.getMinutes()).padStart(2, "0") | |
| emptyInput.value = `${hours}:${minutes}` | |
| emptyInput.dispatchEvent(new Event("input", { bubbles: true })) | |
| emptyInput.dispatchEvent(new Event("change", { bubbles: true })) | |
| btn.remove() | |
| }) | |
| vaadinField.insertAdjacentElement("afterend", btn) | |
| }) | |
| } | |
| function setupEnterToSave() { | |
| const inOut = document.querySelector('#inOut') | |
| if (!inOut || inOut.dataset.enterListenerAdded) return | |
| inOut.addEventListener('keydown', function(e) { | |
| if (e.key === 'Enter' && e.target.matches('input')) { | |
| e.preventDefault() | |
| this.querySelector('[movie-id="save"]')?.click() | |
| } | |
| }) | |
| inOut.dataset.enterListenerAdded = 'true' | |
| } | |
| convertHours() | |
| updateLiveHours() | |
| addNowButton() | |
| setupEnterToSave() | |
| setInterval(() => { | |
| convertHours() | |
| updateLiveHours() | |
| addNowButton() | |
| setupEnterToSave() | |
| }, 1000) | |
| })() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment