diff options
Diffstat (limited to 'src/hydrilla/proxy/policies/injectable_scripts/popup.js.jinja')
-rw-r--r-- | src/hydrilla/proxy/policies/injectable_scripts/popup.js.jinja | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/src/hydrilla/proxy/policies/injectable_scripts/popup.js.jinja b/src/hydrilla/proxy/policies/injectable_scripts/popup.js.jinja new file mode 100644 index 0000000..593673b --- /dev/null +++ b/src/hydrilla/proxy/policies/injectable_scripts/popup.js.jinja @@ -0,0 +1,221 @@ +{# +SPDX-License-Identifier: GPL-3.0-or-later + +Haketilo popup display script. + +This file is part of Hydrilla&Haketilo. + +Copyright (C) 2021,2022 Wojtek Kosior + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +As additional permission under GNU GPL version 3 section 7, you +may distribute forms of that code without the copy of the GNU +GPL normally required by section 4, provided you include this +license notice and, in case of non-source distribution, a URL +through which recipients can access the Corresponding Source. +If you modify file(s) with this exception, you may extend this +exception to your version of the file(s), but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +As a special exception to the GPL, any HTML file which merely +makes function calls to this code, and for that purpose +includes it by reference shall be deemed a separate work for +copyright law purposes. If you modify this code, you may extend +this exception to your version of the code, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. + + +I, Wojtek Kosior, thereby promise not to sue for violation of this +file's license. Although I request that you do not make use of this +code in a proprietary program, I am not going to enforce this in court. +#} + +(function(){ + document.currentScript.remove(); + + /* + * To slightly decrease the chance of accidental popup breakage we snapshot + * methods that other code might redefine. + */ + function get_setter(obj, name) { + return Object.getOwnPropertyDescriptor(obj, name).set; + } + + const ElementPrototype = [0, 0, 0] + .reduce(n => Object.getPrototypeOf(n), document.documentElement); + + const prepend_fun = ElementPrototype.prepend; + const setattr_fun = ElementPrototype.setAttribute; + const remove_fun = ElementPrototype.remove; + const setinner_fun = get_setter(ElementPrototype, "innerHTML"); + const open_fun = window.open; + + const shortcut = "HKT"; + const nonce = atob("{{nonce_b64}}"); + const popup_style = "{{popup_style}}"; + const popup_html = atob("{{popup_page_b64}}"); + const popup_container = document.createElement("div"); + const popup_frame = document.createElement("iframe"); + + function make_style(styles_obj) { + return Object.entries(styles_obj) + .map(([key, val]) => `${key}: ${val} !important`) + .join(';'); + } + + const frame_style = make_style({ + "position": "absolute", + "left": "50%", + "top": "50%", + "transform": "translate(-50%, -50%)", + "display": "block", + "visibility": "visible", + "min-width": "initial", + "width": "600px", + "max-width": "calc(100vw - 20px)", + "min-height": "initial", + "height": "700px", + "max-height": "calc(100vh - 20px)", + "background-color": "#fff", + "opacity": "100%", + "margin": 0, + "padding": 0, + "border": "none", + "border-radius": "5px" + }); + + const container_style = make_style({ + "position": "fixed", + "left": "0", + "top": "0", + "transform": "initial", + "z-index": 2147483647, + "display": "block", + "visibility": "visible", + "min-width": "100vw", + "max-width": "100vw", + "min-height": "100vh", + "max-height": "100vh", + "background-color": "#0008", + "opacity": "100%", + "margin": 0, + "padding": 0, + "border": "none", + "border-radius": 0 + }); + + const popup_blob_opts = {type: "text/html;charset=UTF-8"}; + const popup_blob = new Blob([popup_html], popup_blob_opts); + const popup_url = URL.createObjectURL(popup_blob); + + function show_popup_dialog() { + setattr_fun.call(popup_frame, "srcdoc", popup_html); + setattr_fun.call(popup_frame, "nonce", nonce); + setattr_fun.call(popup_frame, "style", frame_style); + + setattr_fun.call(popup_container, "style", container_style); + setinner_fun.call(popup_container, ""); + prepend_fun.call(popup_container, popup_frame); + + prepend_fun.call(document.body, popup_container); + } + + let popup_newtab_wanted = false; + + function show_popup_newtab() { + /* + * We cannot open popup directly here because browsers block window + * creation attempts from "keypress" event handlers. Instead, we set a + * flag to have "click" event handler open the popup. + */ + popup_newtab_wanted = true; + console.info(`You typed "${shortcut}". Please click anywhere on the page to show Haketilo page information.`); + } + + function show_popup() { + if (popup_style === "T") { + show_popup_newtab(); + } else { + /* popup_syle === "D" */ + show_popup_dialog(); + } + } + + function hide_popup_dialog() { + remove_fun.call(popup_container); + } + + let letters_matched = 0; + + function matches_previous(letter) { + return letters_matched > 0 && letter === shortcut[letters_matched - 1]; + } + + function match_letter(letter) { + if (letter !== shortcut[letters_matched] && !matches_previous(letter)) + letters_matched = 0; + + if (letter === shortcut[letters_matched]) { + if (++letters_matched === shortcut.length) { + letters_matched = 0; + return true; + } + } + + return false; + } + + function consume_keypress(event) { + if (!event.isTrusted) + return; + + if (match_letter(event.key)) + show_popup(); + } + + function cancel_event(event) { + event.stopImmediatePropagation(); + event.stopPropagation(); + event.preventDefault(); + } + + function consume_click(event) { + if (!event.isTrusted) + return; + + if (popup_style === "T") { + if (popup_newtab_wanted) { + popup_newtab_wanted = false; + cancel_event(event); + window.open( + popup_url, + "_blank", + "popup,width=600px,height=700px" + ); + } + } else { + /* popup_syle === "D" */ + if (event.target === popup_container) { + hide_popup_dialog(); + cancel_event(event); + } + } + } + + document.addEventListener("keypress", consume_keypress, {capture: true}); + document.addEventListener("click", consume_click, {capture: true}); +})(); |