1# Copyright (c) 2017-2021 Cedric Bellegarde <cedric.bellegarde@adishatz.org> 2# This program is free software: you can redistribute it and/or modify 3# it under the terms of the GNU General Public License as published by 4# the Free Software Foundation, either version 3 of the License, or 5# (at your option) any later version. 6# This program is distributed in the hope that it will be useful, 7# but WITHOUT ANY WARRANTY; without even the implied warranty of 8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9# GNU General Public License for more details. 10# You should have received a copy of the GNU General Public License 11# along with this program. If not, see <http://www.gnu.org/licenses/>. 12 13from gi.repository import Gtk, GObject 14 15from gettext import gettext as _ 16from urllib.parse import urlparse 17 18from eolie.logger import Logger 19from eolie.define import App 20from eolie.utils import emit_signal 21from eolie.helper_gestures import GesturesHelper 22 23 24class ScriptRow(Gtk.ListBoxRow, GesturesHelper): 25 """ 26 Script row (Allowing to select a script for uri) 27 """ 28 29 __gsignals__ = { 30 "activated": (GObject.SignalFlags.RUN_FIRST, None, ()), 31 } 32 33 def __init__(self, uri, toggled): 34 """ 35 Init row 36 @param uri as str 37 @param toggled as bool 38 """ 39 Gtk.ListBoxRow.__init__(self) 40 self.__uri = uri 41 grid = Gtk.Grid() 42 grid.set_column_spacing(5) 43 grid.show() 44 label = Gtk.Label.new(uri) 45 label.set_hexpand(True) 46 label.set_property("halign", Gtk.Align.START) 47 label.set_tooltip_text(uri) 48 label.show() 49 self.__check = Gtk.CheckButton() 50 self.__check.set_active(toggled) 51 self.__check.connect("toggled", self.__on_check_toggled) 52 self.__check.show() 53 grid.add(self.__check) 54 grid.add(label) 55 eventbox = Gtk.EventBox.new() 56 eventbox.show() 57 eventbox.add(grid) 58 self.add(eventbox) 59 GesturesHelper.__init__(self, eventbox) 60 61 def set_active(self, active): 62 """ 63 Set row active 64 @param active as bool 65 """ 66 self.__check.set_active(active) 67 68 @property 69 def uri(self): 70 """ 71 Get uri 72 @return str 73 """ 74 return self.__uri 75 76 @property 77 def is_active(self): 78 """ 79 Get Check button 80 @return bool 81 """ 82 return self.__check.get_active() 83 84####################### 85# PROTECTED # 86####################### 87 def _on_primary_press_gesture(self, x, y, event): 88 """ 89 Toggle check button 90 @param x as int 91 @param y as int 92 @param event as Gdk.Event 93 """ 94 toggled = not self.__check.get_active() 95 self.__check.set_active(toggled) 96 97####################### 98# PRIVATE # 99####################### 100 def __on_check_toggled(self, button): 101 """ 102 Emit activated signal 103 @param button as Gtk.CheckButton 104 """ 105 emit_signal(self, "activated") 106 107 108class ScriptsMenu(Gtk.Grid): 109 """ 110 Menu allowing user to enable scripts for URI 111 """ 112 113 __ALLOW_ALL = _("Allow all scripts") 114 115 def __init__(self, uri, window): 116 """ 117 Init widget 118 @param uri as str 119 @param window as Window 120 """ 121 Gtk.Grid.__init__(self) 122 self.set_column_spacing(10) 123 self.set_orientation(Gtk.Orientation.VERTICAL) 124 self.__uri = uri 125 self.__window = window 126 self.__back_button = Gtk.ModelButton.new() 127 self.__back_button.show() 128 self.__back_button.set_property("menu_name", "main") 129 self.__back_button.set_property("inverted", True) 130 self.__back_button.set_property("centered", True) 131 self.__back_button.set_property("text", _("Scripts")) 132 self.__scrolled = Gtk.ScrolledWindow.new() 133 self.__scrolled.show() 134 self.__scrolled.set_size_request(-1, 300) 135 self.__scrolled.set_shadow_type(Gtk.ShadowType.NONE) 136 self.__listbox = Gtk.ListBox.new() 137 self.__listbox.show() 138 self.__listbox.get_style_context().add_class("menu-listbox") 139 self.__listbox.set_selection_mode(Gtk.SelectionMode.NONE) 140 self.__listbox.connect("map", self.__on_map) 141 self.set_property("margin", 5) 142 self.__scrolled.add(self.__listbox) 143 self.add(self.__back_button) 144 self.add(self.__scrolled) 145 146####################### 147# PRIVATE # 148####################### 149 def __is_script_active(self, script, netloc, internal): 150 """ 151 True if script active for netloc 152 @param script as str 153 @param netloc as str 154 @param internal as bool 155 @return bool 156 """ 157 content_blocker = App().get_content_blocker("block-scripts") 158 if script == ".*": 159 uri = ".*" 160 else: 161 script_parsed = urlparse(script) 162 uri = "%s%s.*" % (script_parsed.netloc, script_parsed.path) 163 result = content_blocker.exceptions.is_domain_exception( 164 netloc, uri, internal) 165 return result 166 167 def __on_map(self, listbox): 168 """ 169 Populate languages 170 @param listbox as Gtk.ListBox 171 """ 172 if listbox.get_children(): 173 return 174 webview = self.__window.container.webview 175 webview.run_javascript_from_gresource( 176 "/org/gnome/Eolie/javascript/GetScripts.js", None, 177 self.__on_get_scripts) 178 179 def __on_get_scripts(self, source, result): 180 """ 181 Add scripts to menu 182 @param source as GObject.Object 183 @param result as Gio.AsyncResult 184 """ 185 scripts = [] 186 try: 187 data = source.run_javascript_from_gresource_finish(result) 188 scripts = data.get_js_value().to_string().split("@@@") 189 except Exception as e: 190 Logger.warning("ScriptsMenu::__on_get_scripts(): %s", e) 191 parsed = urlparse(self.__window.container.webview.uri) 192 allow_all_active = self.__is_script_active('.*', parsed.netloc, False) 193 row = ScriptRow(self.__ALLOW_ALL, allow_all_active) 194 row.connect("activated", self.__on_row_activated, False) 195 row.show() 196 self.__listbox.add(row) 197 for script in scripts: 198 if not script: 199 continue 200 internal = script.find(parsed.netloc) != -1 201 row = ScriptRow(script, 202 self.__is_script_active(script, 203 parsed.netloc, 204 internal)) 205 row.connect("activated", self.__on_row_activated, internal) 206 if allow_all_active: 207 row.set_sensitive(False) 208 row.show() 209 self.__listbox.add(row) 210 211 def __on_row_activated(self, row, internal): 212 """ 213 Update exceptions 214 @param row as ScriptRow 215 @param internal as bool 216 """ 217 parsed = urlparse(self.__window.container.webview.uri) 218 content_blocker = App().get_content_blocker("block-scripts") 219 if row.uri == self.__ALLOW_ALL: 220 uri = ".*" 221 for _row in self.__listbox.get_children()[1:]: 222 _row.set_active(False) 223 _row.set_sensitive(not row.is_active) 224 else: 225 script_parsed = urlparse(row.uri) 226 uri = "%s%s.*" % (script_parsed.netloc, script_parsed.path) 227 if row.is_active: 228 content_blocker.exceptions.add_domain_exception( 229 parsed.netloc, uri, internal) 230 else: 231 content_blocker.exceptions.remove_domain_exception( 232 parsed.netloc, uri, internal) 233 content_blocker.exceptions.save() 234 content_blocker.update() 235 self.__window.container.webview.reload() 236