// ==UserScript== // @name Animate Context Menus // @version 1.0.1 // @author aminomancer // @homepage https://github.com/aminomancer/uc.css.js // @description Give all context menus the same opening animation that panel popups like the app menu have — the menu slides down 70px and fades in opacity at the same time. It's a cool effect that doesn't trigger a reflow since it uses transform, but it does repaint the menu, so I wouldn't recommend using this on weak hardware. // @license This Source Code Form is subject to the terms of the Creative Commons Attribution-NonCommercial-ShareAlike International License, v. 4.0. If a copy of the CC BY-NC-SA 4.0 was not distributed with this file, You can obtain one at http://creativecommons.org/licenses/by-nc-sa/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. // @include * // ==/UserScript== class AnimateContextMenus { constructor() { document.documentElement.setAttribute("animate-menupopups", true); addEventListener("popupshowing", this); addEventListener("popupshown", this); addEventListener("popuphidden", this); let css = ` :root[animate-menupopups] :not(menulist) > menupopup:not([position], [type="arrow"], [animate="false"]) { opacity: 0; transform: translateY(-70px) scaleX(0.95) scaleY(0.5); transform-origin: top; transition-property: transform, opacity; transition-duration: 0.18s, 0.18s; transition-timing-function: var(--animation-easing-function, cubic-bezier(.07, .95, 0, 1)), ease-out; transform-style: flat; backface-visibility: hidden; } :root[animate-menupopups] :not(menulist) > menupopup:not([position], [type="arrow"])[animate][animate="open"] { opacity: 1.0; transition-duration: 0.18s, 0.18s; transform: none !important; transition-timing-function: var(--animation-easing-function, cubic-bezier(.07, .95, 0, 1)), ease-in-out; } :root[animate-menupopups] :not(menulist) > menupopup:not([position], [type="arrow"])[animate][animate="cancel"] { transform: none; } :root[animate-menupopups] :not(menulist) > menupopup:not([position], [type="arrow"])[animating] { pointer-events: none; } `; const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); let sss = Cc["@mozilla.org/content/style-sheet-service;1"].getService( Ci.nsIStyleSheetService ); let uri = Services.io.newURI("data:text/css;charset=UTF=8," + encodeURIComponent(css)); if (!sss.sheetRegistered(uri, sss.AUTHOR_SHEET)) sss.loadAndRegisterSheet(uri, sss.AUTHOR_SHEET); } handleEvent(e) { if (e.target.tagName !== "menupopup") return; if (e.target.hasAttribute("position")) return; if (e.target.getAttribute("type") == "arrow") return; if (e.target.parentElement) if (e.target.parentElement.tagName == "menulist") return; if ( e.target.shadowRoot && e.target.shadowRoot.firstElementChild.classList.contains("panel-arrowcontainer") ) return; this[`on_${e.type}`](e); } on_popupshowing(e) { if (e.target.getAttribute("animate") != "false") { e.target.setAttribute("animate", "open"); e.target.setAttribute("animating", "true"); } } on_popupshown(e) { e.target.removeAttribute("animating"); } on_popuphidden(e) { if (e.target.getAttribute("animate") != "false") e.target.removeAttribute("animate"); } } new AnimateContextMenus();