Zoom, Find in Page & other actions in Web Panels
-
Good catch! I fixed it just now.
-
@LonM Added some small fixes for the height size of the footer div and the first button div so that the click box is fully viewable:
/* * Panel Actions (A Mod for Vivaldi) * LonM.vivaldi.net * Search actions by tam710562 and joao.rossa on vivaldi.net * https://forum.vivaldi.net/topic/26623/zoom-other-page-actions-in-web-panels/ * No Copyright Reserved */ (function panel_actions(){ "use strict"; const ZOOM_STEP = 0.1; /*Step amount. 0.1 is 10%*/ /* Dictionary of panel actions. They will be added to the toolbar in the order specified below. key must be unique title: string for tooltip script: (target, webview) => {}: void. target is button that was clicked. webview is the webview attached to the button for content scripts, Call doContentScript with the webview and a () => {}: void display: string of html - The innerHTML of the toolbar button display_class: string - One or more classes to give the button */ const ACTIONS_SEARCHTEXT = { search_label :{ title: "Search label", script: function(target, webview){ }, display:"<span>Find in panel: </span>", display_class: "search-label" }, search_input :{ title: "Search input", script: function(target, webview){ target.addEventListener("input", function() { ACTIONS_SEARCHTEXT.value = target.value; webview.find(ACTIONS_SEARCHTEXT.value); }); target.addEventListener("keypress", function(e) { if (e.keyCode == 13) { if (!e.shiftKey) { webview.find(ACTIONS_SEARCHTEXT.value); } else { webview.find(ACTIONS_SEARCHTEXT.value, { backward: true }); } } }); }, display:"<input type='search' id='panel-search-input'/>", display_class: "search-input" }, previous_match : { title: "Previous match", script: function(target, webview){ webview.find(ACTIONS_SEARCHTEXT.value, { backward: true }); }, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M5 8L8.63432 4.36568C9.13829 3.86171 10 4.21865 10 4.93137L10 11.0686C10 11.7814 9.13829 12.1383 8.63431 11.6343L5 8Z"></path> </svg>`, display_class: "previous-match" }, next_match : { title: "Next match", script: function(target, webview){ webview.find(ACTIONS_SEARCHTEXT.value); }, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M11 8L7.36568 11.6343C6.86171 12.1383 6 11.7814 6 11.0686L6 4.93137C6 4.21865 6.86171 3.86171 7.36569 4.36569L11 8Z"></path> </svg>`, display_class: "next-match" }, cancel_search :{ title: "Cancel search", script: function(target, webview){ webview.parentElement.parentElement.querySelector("#pamodsearchTextBar").remove(); webview.stopFinding("clear"); delete ACTIONS_SEARCHTEXT.value; }, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path d="M4.29289 4.29289C4.68342 3.90237 5.31658 3.90237 5.70711 4.29289L8 6.58579L10.2929 4.29289C10.6834 3.90237 11.3166 3.90237 11.7071 4.29289C12.0976 4.68342 12.0976 5.31658 11.7071 5.70711L9.41421 8L11.7071 10.2929C12.0976 10.6834 12.0976 11.3166 11.7071 11.7071C11.3166 12.0976 10.6834 12.0976 10.2929 11.7071L8 9.41421L5.70711 11.7071C5.31658 12.0976 4.68342 12.0976 4.29289 11.7071C3.90237 11.3166 3.90237 10.6834 4.29289 10.2929L6.58579 8L4.29289 5.70711C3.90237 5.31658 3.90237 4.68342 4.29289 4.29289Z"></path> </svg>`, display_class: "cancel-search" } }; const ACTIONS = { zoom_out: { title: "Decrease zoom", script: function(target, webview){ webview.getZoom(current => { changeZoom(webview, current -= ZOOM_STEP); }); }, display: "-", display_class: "zoom-out" }, zoom_reset: { title: "Set zoom to 100%", script: function(target, webview){ changeZoom(webview, 1); }, display: "100%", display_class: "zoom-reset" }, zoom_in: { title: "Increase zoom", script: function(target, webview){ webview.getZoom(current => { changeZoom(webview, current += ZOOM_STEP); }); }, display: "+", display_class: "zoom-in" }, invert: { title: "Invert the colours on the page", script: function(target, webview){ doContentScript(webview, () => { const style_element = document.createElement("style"); style_element.innerHTML = ` html { background-color: white;} body.inverted {filter: invert(1) hue-rotate(180deg);} body.inverted img, body.inverted video {filter: invert(1) hue-rotate(180deg);}`; document.body.appendChild(style_element); document.body.classList.toggle("inverted"); }); }, display: `<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg"> <path d="M 7.984375 0 A 7.9850645 7.9850645 0 0 0 0 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 15.970703 A 7.9850645 7.9850645 0 0 0 15.970703 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 0 z M 7.9960938 0.74804688 L 7.9960938 7.984375 L 7.9960938 15.222656 A 7.2378569 7.2378569 0 0 1 1.7265625 11.603516 A 7.2378569 7.2378569 0 0 1 1.7265625 4.3652344 A 7.2378569 7.2378569 0 0 1 7.9960938 0.74804688 z " fill=""></path> </svg>`, display_class: "panel-action-invert" }, terminate: { title: "Kills the panel to free memory. WARNING! This will also kill any tabs using the same process.", script: function(target, webview){ webview.terminate(); }, display: "x", display_class: "panel-action-terminate" }, mute: { title: "Mute this panel", script: function(target, webview){ webview.isAudioMuted(mute => { webview.setAudioMuted(!mute); target.innerHTML = mute ? "<svg viewBox='0 -1 18 18' xmlns='http://www.w3.org/2000/svg'><path d='m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z'></path></svg>" : "<svg viewBox='0 -1 18 18' xmlns='http://www.w3.org/2000/svg'><path d='m 10.425781,-0.1412354 -5.5410155,4.96094 H 0.6503908 v 4.75 h 4.1074217 l 5.6679685,5.2285204 z m 0.853516,4.1211 -0.707031,0.70703 1.917969,1.91797 -1.917969,1.91992 0.707031,0.70703 1.917969,-1.91992 1.919922,1.91992 0.707031,-0.70703 -1.919922,-1.91992 1.919922,-1.91797 -0.707031,-0.70703 -1.919922,1.91796 z'></path></svg>"; target.title = mute ? "Mute this panel" : "Panel Muted. Click to Un-Mute"; }); }, display: `<svg viewBox="0 -1 18 18" xmlns="http://www.w3.org/2000/svg"> <path d="m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z"></path> </svg>`, display_class: "panel-action-mute" }, search: { title: "Search Text", script: function(target, webview){ addSearchTextControls(webview); }, display:`<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path d="M944.448 934.656c-7.552 7.616-19.968 7.616-27.52 0l-124.416-124.352c10.368-8 20.096-16.64 29.12-25.984l122.816 122.752C952.064 914.624 952.064 926.976 944.448 934.656zM638.72 823.616c-118.4 0-214.336-95.872-214.336-214.272 0-118.336 95.936-214.272 214.336-214.272 118.336 0 214.272 95.936 214.272 214.272C852.992 727.744 757.056 823.616 638.72 823.616zM638.72 434.112c-96.832 0-175.36 78.528-175.36 175.296 0 96.832 78.528 175.296 175.36 175.296 96.832 0 175.296-78.528 175.296-175.296C814.08 512.576 735.552 434.112 638.72 434.112zM210.176 745.728l0-38.976 194.752 0c5.696 13.696 12.672 26.624 20.608 38.976L210.176 745.728zM210.176 628.864 210.176 589.888l176.256 0C385.984 596.352 385.472 602.816 385.472 609.344c0 6.656 0.512 13.056 0.96 19.52L210.176 628.864zM210.176 356.16l194.752 0 0 38.912L210.176 395.072 210.176 356.16zM404.992 512 404.992 512 210.176 512 210.176 473.024l194.752 0L404.928 512zM736.128 356.16 638.72 356.16l0 0L638.656 356.16 580.288 356.16c-43.072 0-77.952-34.88-77.952-77.952L502.336 102.976 151.744 102.976c-21.504 0-38.912 17.408-38.912 38.912l0 740.224c0 21.504 17.408 38.848 38.912 38.848l545.408 0c21.504 0 38.912-17.344 38.912-38.848l0-38.976c7.936-3.328 15.68-6.976 23.232-11.008l15.68 15.744 0 34.24c0 43.008-34.88 77.888-77.888 77.888L151.744 960c-43.008 0-77.888-34.88-77.888-77.888L73.856 141.888C73.856 98.88 108.736 64 151.744 64c0 0 149.632 0 292.16 0C447.424 64 450.88 64 454.4 64c6.784 0 13.376 0 20.096 0l54.464 0 240.448 258.944-1.216 6.848 6.848 6.848 0 8.704 0 49.728 0 1.152c-12.288-7.936-25.344-14.912-38.912-20.608L736.128 356.16zM541.312 135.36l0 142.912c0 21.504 17.408 38.976 38.976 38.976l131.584 0L541.312 135.36z" /> </svg>`, display_class: "panel-action-search-text" }/*, template: { title: "", script: function(event, webview){ }, display: ``, display_class: `` },*/ }; function addSearchTextControls(webview){ const panel = webview.parentElement.parentElement; const alreadyAdded = panel.querySelector("#pamodsearchTextBar"); if(alreadyAdded){return;} const searchTextBar = document.createElement("div"); searchTextBar.id = "pamodsearchTextBar"; searchTextBar.className = "toolbar toolbar-medium toolbar-statusbar"; for(const key in ACTIONS_SEARCHTEXT){ const action = ACTIONS_SEARCHTEXT[key]; let newButton; if(key === "value") { continue; } else if(key === "search_label" || key === "search_input") { newButton = createElement(action, webview); } else { newButton = createActionButton(action, webview); } searchTextBar.appendChild(newButton); } panel.insertBefore(searchTextBar,panel.querySelector("footer")); } function createElement(action, webview){ const template = document.createElement("template"); template.innerHTML = action.display.trim(); const element = template.content.firstChild; action.script(element, webview); element.title = action.title; return element; } /** * Change the zoom * @param webview to update * @param zoom new zoom factor */ function changeZoom(webview, zoom){ webview.setZoom(zoom, () => { updateZoomLabel(webview); }); } /** * Update the zoom label * @param webview to get zoom value from */ function updateZoomLabel(webview){ const panelZoom = webview.parentElement.parentElement.querySelector(".zoom-reset"); if(!panelZoom){ console.error("[lonm-panel-actions] Panel Zoom Label Missing"); return; } webview.getZoom(current => { const newValue = Math.floor(current * 100); panelZoom.firstChild.innerHTML = newValue + "%"; }); } /** * Inject a script as a content script * @param webview to use * @param scriptMethod Method to inject */ function doContentScript(webview, scriptMethod){ const scriptText = "("+scriptMethod+")()"; webview.executeScript({code: scriptText}); } /** * Create a panel action button * REMARK: For some reason the button click currentTarget is not always the button * @param action object * @param webview dom object button will attach to * @returns dom object */ function createActionButton(action, webview){ const newBtnDiv = document.createElement("div"); if(action.display_class==="zoom-out"){ newBtnDiv.style.paddingLeft = "1px"; } newBtnDiv.className = action.display_class+" button-toolbar mod-panel-action"; const newBtn = document.createElement("button"); newBtn.className = action.display_class+" button-toolbar mod-panel-action"; newBtn.innerHTML = action.display; newBtn.addEventListener("click", event => { let eventSource = event.target; while(eventSource.tagName.toLowerCase()!== "button"){ eventSource = eventSource.parentElement; } action.script(eventSource, webview); }); newBtn.title = action.title; newBtnDiv.appendChild(newBtn); return newBtnDiv; } /** * Add the panel action controls * @param panel dom node */ function addPanelControls(panel){ const alreadyAdded = panel.querySelector("footer"); if(alreadyAdded){return;} const footer = document.createElement("footer"); const footerToolbar = document.createElement("div"); footerToolbar.className = "toolbar toolbar-medium toolbar-statusbar"; footerToolbar.style.height = "24px"; footer.appendChild(footerToolbar); const webview = panel.querySelector("webview"); for(const key in ACTIONS){ const action = ACTIONS[key]; const newButton = createActionButton(action, webview); footerToolbar.appendChild(newButton); } panel.appendChild(footer); } /** * upgrade a web panel by adding controls, listeners, etc. * @param panel dom node */ function upgradePanel(panel){ addPanelControls(panel); const webview = panel.querySelector("webview"); webview.addEventListener("zoomchange", () => { updateZoomLabel(webview); }); webview.addEventListener("loadcommit", () => { updateZoomLabel(webview); }); } /** * Observe changes to the panels * Remark: This will either be to upgrade a panel when it is first created * or to re-add the panel controls if removed after a panel was toggled */ const PANEL_CHANGE_OBSERVER = new MutationObserver(records => { records.forEach(record => { if(record.type==="attributes"){ const targetClasses = record.target.classList; if(targetClasses.contains("visible") && targetClasses.contains("webpanel")){ addPanelControls(record.target); } } else if (record.type==="childList") { record.addedNodes.forEach(node => { if(node.classList && node.classList.contains("webpanel")){ upgradePanel(node); } }); } }); }); /** * Begin observing the changes to panels * @param webPanelStack The web panel stack div */ function beginObservation(webPanelStack){ PANEL_CHANGE_OBSERVER.observe(webPanelStack, { attributes: true, attributeFilter: ["class"], childList: true, subtree: true }); } /** * Initialise the mod */ function initMod(){ const webPanels = document.querySelector("#panels"); if(webPanels){ beginObservation(webPanels); const alreadyOpenPanel = document.querySelector(".panel.webpanel.visible"); if(alreadyOpenPanel){ upgradePanel(alreadyOpenPanel); } } else { setTimeout(initMod, 500); } } /* Start 500ms after the browser is opened */ setTimeout(initMod, 500); })();
function createActionButton(action, webview){ const newBtnDiv = document.createElement("div"); if(action.display_class==="zoom-out"){ newBtnDiv.style.paddingLeft = "1px"; } ...} function addPanelControls(panel){ ... footerToolbar.style.height = "24px"; ... }
-
Implemented the misc fixes by @joao-rossa and I've also made the "terminate" button require a double-click. this should hopefully prevent accidental clicks killing panels.
If you want to go back to the old way where it just takes a single click, find
... terminate: { ... doubleclick: function(target, webview){ webview.terminate(); }, ...
and change it to
... terminate: { ... script: function(target, webview){ webview.terminate(); }, ...
-
@LonM Is this working for the latest snapshot? just added to it and it doenst show anything.
-
@joao-rossa It's working for me on Vivaldi 2.7.1609.4
For newly added webpanels you may need to close and re-open.
-
Hi, can someone help me with the installation of this script, I can't seem to get it to work.
I have no experience in coding but from my understanding, I enabled css modifications, then I copy pasted the code from this topic and saved it as a .js, .css file through notepad++ and placed it in a onedrive folder which I redirected Vivaldi to.
Any help will be deeply appreciated.
-
@uz3390
Hi, the css modification setting work only for .css files, for .js you have to create the file in your Vivaldi installation directory. Therefor I copy my .css in to "style" and my .js to /opt/vivaldi-snapshot/resources/vivaldi/ on Linux.
You have to modify the browser.html file like:<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Vivaldi</title> <link rel="stylesheet" href="style/common.css" /> <link rel="stylesheet" href="style/custom.css" /> <link rel="stylesheet" href="style/your_file.css" /> </head> <body style=" background-color: #d4d4d4; background-image: url('resources/vivaldi-splash-icon.svg'); background-size: 16%; background-position: center; background-repeat: no-repeat;"> <div id="app" /> <script src="localeSettings-bundle.js"></script> <script src="background-common-bundle.js"></script> <script src="vendor-bundle.js"></script> <script src="settings-bundle.js"></script> <script src="urlbar-bundle.js"></script> <script src="components-bundle.js"></script> <script src="bundle.js"></script> <script src="history.js"></script> <script src="your_file.js"></script> </body> </html>
The browser.html file has to recreated after update Vivaldi.
Sometimes the .css file too.Cheers, mib
-
This is what I,ve done
- Enable css modifications in experiments.
- Changed custom ui modification folder to root of Vivaldi installation (AppData/Local/Vivaldi).
- I replaced the browser.html with the code you provided.
- Made the .js AND .css script and named it your_file.js and your_file.css
- Placed in the root of Vivaldi installation folder as above.
- Restarted Vivaldi.
Still doesn't work, what am I doing wrong?
-
@uz3390
Is the .css file in: /opt/vivaldi-snapshot/resources/vivaldi/style/
nearby common.css?Cheers, mib
-
@uz3390 said:
Still doesn't work, what am I doing wrong?
This:
- Placed in the root of Vivaldi installation folder as above.
You should place it in
vivaldi_folder\Application\version_number\resources\vivaldi\
, the.css
in astyle
subfolder (if you chose to use this way to apply CSS; otherwise the old location of.css
is correct). -
@potmeklecbohdan , @mib2berlin
Sorry for the late reply, and thanks for the help. Placing the .js file in vivaldi_folder\Application\version_number\resources\vivaldi\ and the .css file in vivaldi_folder\Application\version_number\resources\vivaldi\style worked.
-
Hi, how do you set the default zoom to 75%?
-
@uz3390 that would take a lot of work - more than I'm able to put in. It seems to be very difficult or convoluted to get a default zoom at anything Other than 109
-
Don't worry about it, its already a great mod. I've set the reset button to zoom to 75% for now that works pretty well.
-
@uz3390 Yes its very useful, i wonder why vivaldi hasn't put more focus on adding more panel functionalities...
-
I'm struggling to get this code to work. I've download Panel Actions JS from Lom's GitHub. Saved that to C:\Users\Username\AppData\Local\Vivaldi\Application\2.6.1566.49\resources\vivaldi.
I thought I read on this post about a CSS script that needs to be saved, but I can't tell what the CSS script is that I need.
My browser.html is already modified.
What am I missing?
-
@mdoverl Please post directory structure of the
resources\vivaldi
folder (only the files you added there should be enough) and the part ofbrowser.html
you changed. Without that we cannot help you.If you want the code nicely formatted, put
```
(three backticks) on the line above and below it. -
Please don't hate me. Below is the complete file structure of C:\Users\username\AppData\Local\Vivaldi\Application\2.6.1566.49\resources\vivaldi
C:\Users\username\AppData\Local\Vivaldi\Application\2.6.1566.49\resources\vivaldi β background-bundle.js β background-common-bundle.js β browser - Copy.html β browser.html β bundle.js β devtools.html β devtools.js β ext-bar.css β inject-all-bundle.js β inject-all-spatnav-bundle.js β inject-root-bundle.js β panel_actions.js β prefs_definitions.json β vendor-bundle.js β vivaldi.txt β ββββcomponents β ββββprivate-intro β β private-intro.html β β β ββββsettings β β settings.html β β β ββββthumbnail β β capture.html β β β ββββwelcome β welcome.html β ββββdefault-bookmarks β be.json β de.json β en-AU.json β en-GB.json β en-IN.json β en-US.json β es.json β fallback-partner-ids.json β fr.json β is.json β it.json β ja.json β nb.json β nn.json β pl.json β ru.json β sv.json β tr.json β uk.json β ββββresources β bg.jpg β bg_alt_1.jpg β bg_alt_2.jpg β bg_alt_3.jpg β bg_alt_4.jpg β bg_alt_5.jpg β bg_alt_6.jpg β bg_alt_7.jpg β check-selected.png β [email protected] β check-white.png β [email protected] β close-white.png β [email protected] β contact-company.png β contact-m1.png β contact-m2.png β contact-person.png β contact-w1.png β contact-w2.png β default-avatar.png β default_favicon.png β default_favicon_64.png β favicon-bookmarks.png β [email protected] β favicon-speeddials.png β [email protected] β favicon.png β [email protected] β favicon_history.png β [email protected] β favicon_mail.png β [email protected] β favicon_settings.png β [email protected] β folder.png β [email protected] β folder_dark.png β folder_speeddial.png β folder_speeddial_dark.png β icon_128.png β icon_16.png β icon_notifications.png β input-arrow-down.svg β input-arrow-up.svg β launch-url.png β [email protected] β mail_notification_icon.png β menu_bookmarks.png β menu_capture.png β menu_contacts.png β menu_downloads.png β menu_history.png β menu_mail.png β menu_notes.png β menu_pinned.png β menu_settings.png β menu_stack.png β menu_vivaldi.png β menu_window.png β more-white.png β [email protected] β old_bg_alt_1.jpg β old_bg_alt_2.jpg β old_bg_alt_3.jpg β old_bg_alt_4.jpg β old_bg_alt_5.jpg β old_bg_alt_6.jpg β open-white.png β [email protected] β pref-eyedropper.png β [email protected] β pref-lock.svg β private-window-favicon.png β rte-bold.svg β rte-createLink.svg β rte-indent.svg β rte-insertImage.svg β rte-insertOrderedList.svg β rte-insertUnorderedList.svg β rte-italic.svg β rte-justifyCenter.svg β rte-justifyFull.svg β rte-justifyLeft.svg β rte-justifyRight.svg β rte-outdent.svg β rte-redo.svg β rte-removeFormat.svg β rte-strikeThrough.svg β rte-underline.svg β rte-undo.svg β sd_abc.net.au.png β sd_aliexpress.png β sd_amazon.png β sd_arstechnica.png β sd_blick.png β sd_booking.com.png β sd_by_naviny.png β sd_by_onliner.png β sd_by_tutby.png β sd_de_bild.png β sd_de_derstandard.png β sd_de_focus.png β sd_de_spiegel.png β sd_de_stern.png β sd_de_urlaubsbox.png β sd_de_web.de.png β sd_ebay.png β sd_en_GB_bbc.png β sd_en_GB_theguardian.png β sd_en_GB_thetelegraph.png β sd_en_us_turbotax.png β sd_es_abc.png β sd_es_elmundo.png β sd_es_elpais.png β sd_es_marca.png β sd_es_milanuncios.png β sd_expedia.png β sd_facebook.png β sd_fr_begeek.png β sd_fr_free.png β sd_fr_leboncoin.png β sd_fr_lefigaro.png β sd_fr_lemonde.png β sd_fr_lexpress.png β sd_fr_nextinpact.png β sd_groupon.png β sd_habrahabr.png β sd_help.png β sd_in_cricbuzz.png β sd_in_flipkart.png β sd_in_indiatimes.png β sd_in_makemytrip.png β sd_in_ndtv.png β sd_in_quora.png β sd_is_dv.png β sd_is_mbl.png β sd_is_pressan.png β sd_is_ruv.png β sd_is_vb.png β sd_is_vedur.png β sd_is_visir.png β sd_it_corrieredellasera.png β sd_it_lagazzettadellosport.png β sd_it_libero.png β sd_ja_itmedia.png β sd_ja_mainichi.png β sd_ja_nhk.png β sd_kayak.png β sd_nb_aftenposten.png β sd_nb_dagbladet.png β sd_nb_finn.png β sd_nb_nrk.png β sd_nb_vg.png β sd_news.com.au.png β sd_newyorktimes.png β sd_reddit.png β sd_ru_interfax.png β sd_ru_itkvariat.png β sd_ru_lenta.png β sd_ru_ozon.png β sd_ru_tass.png β sd_ru_yandex.png β sd_simplygames.png β sd_spyr.png β sd_startme.png β sd_sv_sverigesradio.png β sd_sv_svt.png β sd_sv_yle.png β sd_target.png β sd_techcrunch.png β sd_ted.png β sd_tripadvisor.png β sd_tr_cnnturk.png β sd_tr_haberturk.png β sd_tr_hurriyet.png β sd_tr_milliyet.png β sd_tr_ntv.png β sd_tr_sahibinden.png β sd_tr_yandex.png β sd_twitter.png β sd_uk_interfax.png β sd_uk_telegraph.png β sd_vivaldi.png β sd_vivaldi_community.gif β sd_vk.png β sd_webmail.png β sd_wikipedia.png β sd_youtube.png β symbol-add.png β [email protected] β symbol-delete-white.png β [email protected] β symbol-edit-white.png β [email protected] β symbol-edit.png β symbol-eye.png β [email protected] β symbol-reload-dark.png β [email protected] β symbol-reload.png β [email protected] β symbol-remove.png β [email protected] β symbol-takescreenshot.png β [email protected] β symbol-zoomscreenshot.png β [email protected] β triangles_pattern_vivaldi.png β vivaldi-splash-icon.svg β welcome-arrow.svg β welcome-step-complete.svg β welcomepage-chrome.svg β welcomepage-chromium.svg β welcomepage-edge.svg β welcomepage-explorer.svg β welcomepage-firefox.svg β welcomepage-html-document.svg β welcomepage-opera-12.svg β welcomepage-opera.svg β welcomepage-safari.svg β welcomepage-vivaldi.svg β welcomepage-yandex.svg β ββββrss β hidepage.css β preview.css β showfeed.html β showopml.html β ββββstyle β common.css β common.js β ββββuser_files β Content_Blocker.css β CSS_Debugger.js β Filter_Black_and_White.css β Filter_Grayscale.css β Filter_Intensify.css β Filter_Invert.css β Filter_Obscure.css β Filter_Sepia.css β Fonts_Monospace.css β Highlight_Focus.css β Highlight_Hover.css β Inline_Access_Keys.css β Reader_View.js β Skewed_Images.js β Transform_3D.css β Transitions_Forced.css β Transitions_Removed.css β ββββutil β internalPageUtil.js β ββββ_locales ββββaf β messages.json β ββββar β messages.json β ββββbar β messages.json β ββββbe β messages.json β ββββbg β messages.json β ββββbs β messages.json β ββββca β messages.json β ββββca@valencia β messages.json β ββββcs β messages.json β ββββcy β messages.json β ββββda β messages.json β ββββde β messages.json β ββββde_CH β messages.json β ββββel β messages.json β ββββen β messages.json β ββββen_GB β messages.json β ββββeo β messages.json β ββββes β messages.json β ββββes_AR β messages.json β ββββes_MX β messages.json β ββββes_PE β messages.json β ββββet β messages.json β ββββeu β messages.json β ββββfa β messages.json β ββββfi β messages.json β ββββfil β messages.json β ββββfr β messages.json β ββββfy β messages.json β ββββgd β messages.json β ββββgl β messages.json β ββββhe β messages.json β ββββhi β messages.json β ββββhr β messages.json β ββββhu β messages.json β ββββhy β messages.json β ββββid β messages.json β ββββio β messages.json β ββββis β messages.json β ββββit β messages.json β ββββja β messages.json β ββββjbo β messages.json β ββββka β messages.json β ββββkn β messages.json β ββββko β messages.json β ββββku β messages.json β ββββln β messages.json β ββββlt β messages.json β ββββlv β messages.json β ββββmk β messages.json β ββββml β messages.json β ββββmn β messages.json β ββββms β messages.json β ββββnb β messages.json β ββββnl β messages.json β ββββnn β messages.json β ββββpl β messages.json β ββββpt_BR β messages.json β ββββpt_PT β messages.json β ββββro β messages.json β ββββru β messages.json β ββββsc β messages.json β ββββsk β messages.json β ββββsl β messages.json β ββββsq β messages.json β ββββsr β messages.json β ββββsr_Latn β messages.json β ββββsv β messages.json β ββββta β messages.json β ββββth β messages.json β ββββtr β messages.json β ββββuk β messages.json β ββββvi β messages.json β ββββzh_CN β messages.json β ββββzh_TW messages.json
Below is the code of panel_actions.js
/* * Panel Actions (A Mod for Vivaldi) * LonM.vivaldi.net * No Copyright Reserved */ (function panel_actions(){ "use strict"; const ZOOM_STEP = 0.1; /*Step amount. 0.1 is 10%*/ /* Dictionary of panel actions. They will be added to the toolbar in the order specified below. key must be unique title: string for tooltip script: (target, webview) => {}: void. target is button that was clicked. webview is the webview attached to the button for content scripts, Call doContentScript with the webview and a () => {}: void display: string of html - The innerHTML of the toolbar button display_class: string - One or more classes to give the button */ const ACTIONS_SEARCHTEXT = { search_input :{ title: "Insert text", script: function(target, webview){ }, display:`Find in panel: <input type="search" value/>`, display_class: `searchtext-input` }, previous_match : { title: "Previous match", script: function(target, webview){}, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M5 8L8.63432 4.36568C9.13829 3.86171 10 4.21865 10 4.93137L10 11.0686C10 11.7814 9.13829 12.1383 8.63431 11.6343L5 8Z"></path> </svg>`, display_class: `previous-match` }, next_match : { title: "Next match", script: function(target, webview){}, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M11 8L7.36568 11.6343C6.86171 12.1383 6 11.7814 6 11.0686L6 4.93137C6 4.21865 6.86171 3.86171 7.36569 4.36569L11 8Z"></path> </svg>`, display_class: `next-match` }, cancel_search :{ title: "Cancel search", script: function(target, webview){ webview.parentElement.parentElement.querySelector("searchTextBar").remove(); }, display:`<svg viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg"> <path d="M4.29289 4.29289C4.68342 3.90237 5.31658 3.90237 5.70711 4.29289L8 6.58579L10.2929 4.29289C10.6834 3.90237 11.3166 3.90237 11.7071 4.29289C12.0976 4.68342 12.0976 5.31658 11.7071 5.70711L9.41421 8L11.7071 10.2929C12.0976 10.6834 12.0976 11.3166 11.7071 11.7071C11.3166 12.0976 10.6834 12.0976 10.2929 11.7071L8 9.41421L5.70711 11.7071C5.31658 12.0976 4.68342 12.0976 4.29289 11.7071C3.90237 11.3166 3.90237 10.6834 4.29289 10.2929L6.58579 8L4.29289 5.70711C3.90237 5.31658 3.90237 4.68342 4.29289 4.29289Z"></path> </svg>`, display_class: `cancel-search` } }; const ACTIONS = { zoom_out: { title: "Decrease zoom", script: function(target, webview){ webview.getZoom(current => { changeZoom(webview, current -= ZOOM_STEP); }); }, display: `-`, display_class: `zoom-out` }, zoom_reset: { title: "Set zoom to 100%", script: function(target, webview){ changeZoom(webview, 1); }, display: `100%`, display_class: `zoom-reset` }, zoom_in: { title: "Increase zoom", script: function(target, webview){ webview.getZoom(current => { changeZoom(webview, current += ZOOM_STEP); }); }, display: `+`, display_class: `zoom-in` }, invert: { title: "Invert the colours on the page", script: function(target, webview){ doContentScript(webview, () => { const style_element = document.createElement('style'); style_element.innerHTML = ` html { background-color: white;} body.inverted {filter: invert(1) hue-rotate(180deg);} body.inverted img, body.inverted video {filter: invert(1) hue-rotate(180deg);}`; document.body.appendChild(style_element); document.body.classList.toggle("inverted"); }); }, display: `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="M 7.984375 0 A 7.9850645 7.9850645 0 0 0 0 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 15.970703 A 7.9850645 7.9850645 0 0 0 15.970703 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 0 z M 7.9960938 0.74804688 L 7.9960938 7.984375 L 7.9960938 15.222656 A 7.2378569 7.2378569 0 0 1 1.7265625 11.603516 A 7.2378569 7.2378569 0 0 1 1.7265625 4.3652344 A 7.2378569 7.2378569 0 0 1 7.9960938 0.74804688 z " fill=""></path> </svg>`, display_class: "panel-action-invert" }, terminate: { title: "Kills the panel to free memory. WARNING! This will also kill any tabs using the same process.", script: function(target, webview){ webview.terminate(); }, display: `X`, display_class: `panel-action-terminate` }, mute: { title: "Mute this panel", script: function(target, webview){ webview.isAudioMuted(mute => { webview.setAudioMuted(!mute); target.innerHTML = mute ? `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z"></path></svg>` : `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m 10.425781,-0.1412354 -5.5410155,4.96094 H 0.6503908 v 4.75 h 4.1074217 l 5.6679685,5.2285204 z m 0.853516,4.1211 -0.707031,0.70703 1.917969,1.91797 -1.917969,1.91992 0.707031,0.70703 1.917969,-1.91992 1.919922,1.91992 0.707031,-0.70703 -1.919922,-1.91992 1.919922,-1.91797 -0.707031,-0.70703 -1.919922,1.91796 z"></path></svg>`; target.title = mute ? "Mute this panel" : "Panel Muted. Click to Un-Mute"; }); }, display: `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"> <path d="m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z"></path> </svg>`, display_class: `panel-action-mute` }, search: { title: "Search Text", script: function(target, webview){ addSearchTextControls(webview); }, display:`<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"> <path d="M944.448 934.656c-7.552 7.616-19.968 7.616-27.52 0l-124.416-124.352c10.368-8 20.096-16.64 29.12-25.984l122.816 122.752C952.064 914.624 952.064 926.976 944.448 934.656zM638.72 823.616c-118.4 0-214.336-95.872-214.336-214.272 0-118.336 95.936-214.272 214.336-214.272 118.336 0 214.272 95.936 214.272 214.272C852.992 727.744 757.056 823.616 638.72 823.616zM638.72 434.112c-96.832 0-175.36 78.528-175.36 175.296 0 96.832 78.528 175.296 175.36 175.296 96.832 0 175.296-78.528 175.296-175.296C814.08 512.576 735.552 434.112 638.72 434.112zM210.176 745.728l0-38.976 194.752 0c5.696 13.696 12.672 26.624 20.608 38.976L210.176 745.728zM210.176 628.864 210.176 589.888l176.256 0C385.984 596.352 385.472 602.816 385.472 609.344c0 6.656 0.512 13.056 0.96 19.52L210.176 628.864zM210.176 356.16l194.752 0 0 38.912L210.176 395.072 210.176 356.16zM404.992 512 404.992 512 210.176 512 210.176 473.024l194.752 0L404.928 512zM736.128 356.16 638.72 356.16l0 0L638.656 356.16 580.288 356.16c-43.072 0-77.952-34.88-77.952-77.952L502.336 102.976 151.744 102.976c-21.504 0-38.912 17.408-38.912 38.912l0 740.224c0 21.504 17.408 38.848 38.912 38.848l545.408 0c21.504 0 38.912-17.344 38.912-38.848l0-38.976c7.936-3.328 15.68-6.976 23.232-11.008l15.68 15.744 0 34.24c0 43.008-34.88 77.888-77.888 77.888L151.744 960c-43.008 0-77.888-34.88-77.888-77.888L73.856 141.888C73.856 98.88 108.736 64 151.744 64c0 0 149.632 0 292.16 0C447.424 64 450.88 64 454.4 64c6.784 0 13.376 0 20.096 0l54.464 0 240.448 258.944-1.216 6.848 6.848 6.848 0 8.704 0 49.728 0 1.152c-12.288-7.936-25.344-14.912-38.912-20.608L736.128 356.16zM541.312 135.36l0 142.912c0 21.504 17.408 38.976 38.976 38.976l131.584 0L541.312 135.36z" /> </svg>`, display_class: `panel-action-search-text` }/*, template: { title: "", script: function(event, webview){ }, display: ``, display_class: `` },*/ }; function addSearchTextControls(webview){ const panel = webview.parentElement.parentElement; const alreadyAdded = panel.querySelector("searchTextBar"); if(alreadyAdded){return;} const searchTextBar = document.createElement("searchTextBar"); for(const key in ACTIONS_SEARCHTEXT){ const action = ACTIONS_SEARCHTEXT[key]; const newButton = createActionButton(action, webview); searchTextBar.appendChild(newButton); } //panel.appendChild(searchTextBar); //create searchtext bar before footer panel.insertBefore(searchTextBar,panel.querySelector("footer")) } /** * Change the zoom * @param webview to update * @param zoom new zoom factor */ function changeZoom(webview, zoom){ webview.setZoom(zoom, () => { updateZoomLabel(webview); }); } /** * Update the zoom label * @param webview to get zoom value from */ function updateZoomLabel(webview){ const panelZoom = webview.parentElement.parentElement.querySelector(".zoom-reset"); if(!panelZoom){ console.error("[lonm-panel-actions] Panel Zoom Label Missing"); return; } webview.getZoom(current => { const newValue = Math.floor(current * 100); panelZoom.innerHTML = newValue + "%"; }); } /** * Inject a script as a content script * @param webview to use * @param scriptMethod Method to inject */ function doContentScript(webview, scriptMethod){ const scriptText = "("+scriptMethod+")()"; webview.executeScript({code: scriptText}); } /** * Create a panel action button * REMARK: For some reason the button click currentTarget is not always the button * @param action object * @param webview dom object button will attach to * @returns dom object */ function createActionButton(action, webview){ const newBtn = document.createElement("button"); newBtn.className = action.display_class+" button-toolbar-small mod-panel-action"; newBtn.innerHTML = action.display; newBtn.addEventListener("click", event => { let eventSource = event.target; while(eventSource.tagName.toLowerCase()!== "button"){ eventSource = eventSource.parentElement; } action.script(eventSource, webview); }); newBtn.title = action.title; return newBtn; } /** * Add the panel action controls * @param panel dom node */ function addPanelControls(panel){ const alreadyAdded = panel.querySelector("footer"); if(alreadyAdded){return;} const footer = document.createElement("footer"); const webview = panel.querySelector("webview"); for(const key in ACTIONS){ const action = ACTIONS[key]; const newButton = createActionButton(action, webview); footer.appendChild(newButton); } panel.appendChild(footer); } /** * upgrade a web panel by adding controls, listeners, etc. * @param panel dom node */ function upgradePanel(panel){ addPanelControls(panel); const webview = panel.querySelector("webview"); webview.addEventListener("zoomchange", () => { updateZoomLabel(webview); }); webview.addEventListener("loadcommit", () => { updateZoomLabel(webview); }); } /** * Observe changes to the panels * Remark: This will either be to upgrade a panel when it is first created * or to re-add the panel controls if removed after a panel was toggled */ const PANEL_CHANGE_OBSERVER = new MutationObserver(records => { records.forEach(record => { if(record.type==="attributes"){ const targetClasses = record.target.classList; if(targetClasses.contains("visible") && targetClasses.contains("webpanel")){ addPanelControls(record.target); } } else if (record.type==="childList") { record.addedNodes.forEach(node => { if(node.classList && node.classList.contains("webpanel")){ upgradePanel(node); } }); } }); }); /** * Begin observing the changes to panels * @param webPanelStack The web panel stack div */ function beginObservation(webPanelStack){ PANEL_CHANGE_OBSERVER.observe(webPanelStack, { attributes: true, attributeFilter: ["class"], childList: true, subtree: true }); } /** * Initialise the mod */ function initMod(){ const webPanels = document.querySelector("#panels"); if(webPanels){ beginObservation(webPanels); const alreadyOpenPanel = document.querySelector(".panel.webpanel.visible"); if(alreadyOpenPanel){ upgradePanel(alreadyOpenPanel); } } else { setTimeout(initMod, 500); } } /* Start 500ms after the browser is opened */ setTimeout(initMod, 500); })();
mod edit: added code fences ```
-
@mdoverl If it looks like I hate you, I'm sorry. I don't.
So the line you added to
browser.html
is this?<script src="panel_actions.js"></script>
-
@potmeklecbohdan said in Zoom, Find in Page & other actions in Web Panels:
@mdoverl If it looks like I hate you, I'm sorry. I don't.
So the line you added to
browser.html
is this?<script src="panel_actions.js"></script>
let me paste the contents of browser.html here.
<html> <head> <meta charset="UTF-8" /> <title>Vivaldi</title> <link rel="stylesheet" href="style/common.css" /> <link rel="stylesheet" href="style/custom.css" /> <link rel="stylesheet" href="style/your_file.css" /> </head> <body style=" background-color: #d4d4d4; background-image: url('resources/vivaldi-splash-icon.svg'); background-size: 16%; background-position: center; background-repeat: no-repeat;"> <div id="app" /> <script src="localeSettings-bundle.js"></script> <script src="background-common-bundle.js"></script> <script src="vendor-bundle.js"></script> <script src="settings-bundle.js"></script> <script src="urlbar-bundle.js"></script> <script src="components-bundle.js"></script> <script src="bundle.js"></script> <script src="history.js"></script> <script src="your_file.js"></script> </body> </html>``` Well, well, looks like I didn't. Do I need to do this for every script that I add?