Skip to content

Instantly share code, notes, and snippets.

@damsleth
Last active December 18, 2023 13:33
Show Gist options
  • Save damsleth/38468341a6330cedde976d9dfcb6eca8 to your computer and use it in GitHub Desktop.
Save damsleth/38468341a6330cedde976d9dfcb6eca8 to your computer and use it in GitHub Desktop.
Hack to duplicate calendar events by holding down the meta (cmd) key and right clicking them in Outlook Web Access
// ==UserScript==
// @name OWAEventDuplicator
// @namespace http://tampermonkey.net/
// @version 0.3.2
// @description Duplicate events by holding down the meta key and right clicking them
// @author @damsleth
// @match https://outlook.office.com/calendar/view/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=office.com
// @grant none
// ==/UserScript==
// Last updated 2023-12-18
(function () {
'use strict'
let checkDuplicateButtonInterval,
checkSaveButtonInterval,
keyDownTime = null,
isActiveListener = false
function showToast(message) {
const toast = document.createElement("div")
toast.textContent = message
toast.style.position = "fixed"
toast.style.top = "135px"
toast.style.right = "100px"
toast.style.backgroundColor = "rgba(60, 60, 60, 0.9)"
toast.style.color = "white"
toast.style.padding = "10px"
toast.style.borderRadius = "5px"
toast.style.zIndex = "1000"
toast.style.boxShadow = "10px 10px 22px rgba(0, 0, 0, 0.2)"
toast.style.transition = "all .2s ease-out"
document.body.appendChild(toast)
setTimeout(() => {
toast.style.opacity = '0'
setTimeout(() => toast.remove(), 600)
}, 3000)
}
function handleMetaDown(e) {
if (e.key === 'Meta') {
isActiveListener = true
keyDownTime = Date.now()
showToast("Meta key down. Looking for duplicate button.")
hideSaveModal()
checkDuplicateButtonInterval = window.setInterval(lookForDuplicateButton, 40)
}
}
function handleMetaUp(e) {
if (e.key === 'Meta')
isActiveListener = false
keyDownTime = null
unhideSaveModal()
}
function lookForDuplicateButton() {
const duplicateButton = document.querySelector("button[name*='Dup']")
if (duplicateButton) {
showToast("Duplicate button found. Duplicating event.")
clearInterval(checkDuplicateButtonInterval)
duplicateButton.click()
checkSaveButtonInterval = window.setInterval(lookForSaveButton, 30)
} else {
console.log("Duplicate button not found.")
}
}
function lookForSaveButton() {
const saveButton = document.querySelector("i[data-icon-name='SaveRegular']").closest("button")
if (saveButton) {
showToast("Save button found. Saving event.")
clearInterval(checkSaveButtonInterval)
saveButton.click()
} else {
console.log("Save button not found.")
}
}
function hideSaveModal() {
const saveModal = document.getElementById("fluent-default-layer-host")
if (saveModal) {
saveModal.style.opacity = 0
} else {
console.log("Save modal not found.")
}
}
function unhideSaveModal() {
const saveModal = document.getElementById("fluent-default-layer-host")
if (saveModal) {
saveModal.style.opacity = 1
} else {
console.log("Save modal not found.")
}
}
// Fallback mechanism
setInterval(function () {
if (isActiveListener && keyDownTime && Date.now() - keyDownTime > 5000) { // 5 seconds as an example
isActiveListener = false
keyDownTime = null
showToast("Fallback: Meta key up assumed.")
unhideSaveModal()
}
}, 120) // Check every 120 ms
// Global event listeners
document.addEventListener("keydown", handleMetaDown, { capture: true })
document.addEventListener("keyup", handleMetaUp, { capture: true })
showToast("OWA Event Duplicator loaded.")
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment