eric6/Helpviewer/GreaseMonkey/GreaseMonkeyManager.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Helpviewer/GreaseMonkey/GreaseMonkeyManager.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,319 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the manager for GreaseMonkey scripts.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSignal, QObject, QTimer, QFile, QDir, QSettings, \
+    QUrl, QByteArray
+from PyQt5.QtNetwork import QNetworkAccessManager
+from PyQt5.QtWebKitWidgets import QWebFrame
+
+import Utilities
+import Preferences
+
+
+class GreaseMonkeyManager(QObject):
+    """
+    Class implementing the manager for GreaseMonkey scripts.
+    
+    @signal scriptsChanged() emitted to indicate a change of scripts
+    """
+    scriptsChanged = pyqtSignal()
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(GreaseMonkeyManager, self).__init__(parent)
+        
+        self.__disabledScripts = []
+        self.__endScripts = []
+        self.__startScripts = []
+        self.__downloaders = []
+        
+        QTimer.singleShot(0, self.__load)
+    
+    def showConfigurationDialog(self, parent=None):
+        """
+        Public method to show the configuration dialog.
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        from .GreaseMonkeyConfiguration.GreaseMonkeyConfigurationDialog \
+            import GreaseMonkeyConfigurationDialog
+        self.__configDiaolg = GreaseMonkeyConfigurationDialog(self, parent)
+        self.__configDiaolg.show()
+    
+    def downloadScript(self, request):
+        """
+        Public method to download a GreaseMonkey script.
+        
+        @param request reference to the request (QNetworkRequest)
+        """
+        from .GreaseMonkeyDownloader import GreaseMonkeyDownloader
+        downloader = GreaseMonkeyDownloader(request, self)
+        downloader.finished.connect(
+            lambda: self.__downloaderFinished(downloader))
+        self.__downloaders.append(downloader)
+    
+    def __downloaderFinished(self, downloader):
+        """
+        Private slot to handle the completion of a script download.
+        
+        @param downloader reference to the downloader object
+        @type GreaseMonkeyDownloader
+        """
+        if downloader in self.__downloaders:
+            self.__downloaders.remove(downloader)
+    
+    def scriptsDirectory(self):
+        """
+        Public method to get the path of the scripts directory.
+        
+        @return path of the scripts directory (string)
+        """
+        return os.path.join(
+            Utilities.getConfigDir(), "browser", "greasemonkey")
+    
+    def requireScriptsDirectory(self):
+        """
+        Public method to get the path of the scripts directory.
+        
+        @return path of the scripts directory (string)
+        """
+        return os.path.join(self.scriptsDirectory(), "requires")
+    
+    def requireScripts(self, urlList):
+        """
+        Public method to get the sources of all required scripts.
+        
+        @param urlList list of URLs (list of string)
+        @return sources of all required scripts (string)
+        """
+        requiresDir = QDir(self.requireScriptsDirectory())
+        if not requiresDir.exists() or len(urlList) == 0:
+            return ""
+        
+        script = ""
+        
+        settings = QSettings(
+            os.path.join(self.requireScriptsDirectory(), "requires.ini"),
+            QSettings.IniFormat)
+        settings.beginGroup("Files")
+        for url in urlList:
+            if settings.contains(url):
+                fileName = settings.value(url)
+                try:
+                    f = open(fileName, "r", encoding="utf-8")
+                    source = f.read()
+                    f.close()
+                except (IOError, OSError):
+                    source = ""
+                script += source.strip() + "\n"
+        
+        return script
+    
+    def saveConfiguration(self):
+        """
+        Public method to save the configuration.
+        """
+        Preferences.setHelp("GreaseMonkeyDisabledScripts",
+                            self.__disabledScripts)
+    
+    def allScripts(self):
+        """
+        Public method to get a list of all scripts.
+        
+        @return list of all scripts (list of GreaseMonkeyScript)
+        """
+        return self.__startScripts[:] + self.__endScripts[:]
+    
+    def containsScript(self, fullName):
+        """
+        Public method to check, if the given script exists.
+        
+        @param fullName full name of the script (string)
+        @return flag indicating the existence (boolean)
+        """
+        for script in self.__startScripts:
+            if script.fullName() == fullName:
+                return True
+        for script in self.__endScripts:
+            if script.fullName() == fullName:
+                return True
+        return False
+    
+    def enableScript(self, script):
+        """
+        Public method to enable the given script.
+        
+        @param script script to be enabled (GreaseMonkeyScript)
+        """
+        script.setEnabled(True)
+        fullName = script.fullName()
+        if fullName in self.__disabledScripts:
+            self.__disabledScripts.remove(fullName)
+    
+    def disableScript(self, script):
+        """
+        Public method to disable the given script.
+        
+        @param script script to be disabled (GreaseMonkeyScript)
+        """
+        script.setEnabled(False)
+        fullName = script.fullName()
+        if fullName not in self.__disabledScripts:
+            self.__disabledScripts.append(fullName)
+    
+    def addScript(self, script):
+        """
+        Public method to add a script.
+        
+        @param script script to be added (GreaseMonkeyScript)
+        @return flag indicating success (boolean)
+        """
+        if not script:
+            return False
+        
+        from .GreaseMonkeyScript import GreaseMonkeyScript
+        if script.startAt() == GreaseMonkeyScript.DocumentStart:
+            self.__startScripts.append(script)
+        else:
+            self.__endScripts.append(script)
+        
+        self.scriptsChanged.emit()
+        return True
+    
+    def removeScript(self, script):
+        """
+        Public method to remove a script.
+        
+        @param script script to be removed (GreaseMonkeyScript)
+        @return flag indicating success (boolean)
+        """
+        if not script:
+            return False
+        
+        from .GreaseMonkeyScript import GreaseMonkeyScript
+        if script.startAt() == GreaseMonkeyScript.DocumentStart:
+            try:
+                self.__startScripts.remove(script)
+            except ValueError:
+                pass
+        else:
+            try:
+                self.__endScripts.remove(script)
+            except ValueError:
+                pass
+        
+        fullName = script.fullName()
+        if fullName in self.__disabledScripts:
+            self.__disabledScripts.remove(fullName)
+        QFile.remove(script.fileName())
+        
+        self.scriptsChanged.emit()
+        return True
+    
+    def canRunOnScheme(self, scheme):
+        """
+        Public method to check, if scripts can be run on a scheme.
+        
+        @param scheme scheme to check (string)
+        @return flag indicating, that scripts can be run (boolean)
+        """
+        return scheme in ["http", "https", "data", "ftp"]
+    
+    def pageLoadStarted(self):
+        """
+        Public slot to handle the start of loading a page.
+        """
+        frame = self.sender()
+        if frame is None or not isinstance(frame, QWebFrame):
+            return
+        
+        urlScheme = frame.url().scheme()
+        urlString = bytes(frame.url().toEncoded()).decode()
+        
+        if not self.canRunOnScheme(urlScheme):
+            return
+        
+        from .GreaseMonkeyJavaScript import bootstrap_js
+        for script in self.__startScripts:
+            if script.match(urlString):
+                frame.evaluateJavaScript(bootstrap_js + script.script())
+        
+        for script in self.__endScripts:
+            if script.match(urlString):
+                javascript = 'window.addEventListener("DOMContentLoaded",' \
+                    'function(e) {{ {0} }}, false);'.format(
+                        bootstrap_js + script.script())
+                frame.evaluateJavaScript(javascript)
+    
+    def __load(self):
+        """
+        Private slot to load the available scripts into the manager.
+        """
+        scriptsDir = QDir(self.scriptsDirectory())
+        if not scriptsDir.exists():
+            scriptsDir.mkpath(self.scriptsDirectory())
+        
+        if not scriptsDir.exists("requires"):
+            scriptsDir.mkdir("requires")
+        
+        self.__disabledScripts = \
+            Preferences.getHelp("GreaseMonkeyDisabledScripts")
+        
+        from .GreaseMonkeyScript import GreaseMonkeyScript
+        for fileName in scriptsDir.entryList(["*.js"], QDir.Files):
+            absolutePath = scriptsDir.absoluteFilePath(fileName)
+            script = GreaseMonkeyScript(self, absolutePath)
+            
+            if script.fullName() in self.__disabledScripts:
+                script.setEnabled(False)
+            
+            if script.startAt() == GreaseMonkeyScript.DocumentStart:
+                self.__startScripts.append(script)
+            else:
+                self.__endScripts.append(script)
+    
+    def connectPage(self, page):
+        """
+        Public method to allow the GreaseMonkey manager to connect to the page.
+        
+        @param page reference to the web page (HelpWebPage)
+        """
+        page.mainFrame().javaScriptWindowObjectCleared.connect(
+            self.pageLoadStarted)
+    
+    def createRequest(self, op, request, outgoingData=None):
+        """
+        Public method to create a request.
+        
+        @param op the operation to be performed
+            (QNetworkAccessManager.Operation)
+        @param request reference to the request object (QNetworkRequest)
+        @param outgoingData reference to an IODevice containing data to be sent
+            (QIODevice)
+        @return reference to the created reply object (QNetworkReply)
+        """
+        if op == QNetworkAccessManager.GetOperation and \
+           request.rawHeader(b"X-Eric6-UserLoadAction") == QByteArray(b"1"):
+            urlString = request.url().toString(
+                QUrl.RemoveFragment | QUrl.RemoveQuery)
+            if urlString.endswith(".user.js"):
+                self.downloadScript(request)
+                from Helpviewer.Network.EmptyNetworkReply import \
+                    EmptyNetworkReply
+                return EmptyNetworkReply(self)
+        
+        return None

eric ide

mercurial