WebBrowser/GreaseMonkey/GreaseMonkeyScript.py

changeset 5715
cbcca230679f
parent 5650
4c52f07c186e
child 5726
e1dbd217214a
diff -r 90c57b50600f -r cbcca230679f WebBrowser/GreaseMonkey/GreaseMonkeyScript.py
--- a/WebBrowser/GreaseMonkey/GreaseMonkeyScript.py	Tue Apr 25 18:40:46 2017 +0200
+++ b/WebBrowser/GreaseMonkey/GreaseMonkeyScript.py	Tue Apr 25 19:20:18 2017 +0200
@@ -10,10 +10,11 @@
 from __future__ import unicode_literals
 
 from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QUrl, QRegExp, \
-    QByteArray, QCryptographicHash
+    QByteArray, QCryptographicHash, qVersion
 from PyQt5.QtWebEngineWidgets import QWebEngineScript
 
 from .GreaseMonkeyJavaScript import bootstrap_js, values_js
+from .GreaseMonkeyDownloader import GreaseMonkeyDownloader
 
 from ..Tools.DelayedFileWatcher import DelayedFileWatcher
 from ..WebBrowserPage import WebBrowserPage
@@ -28,6 +29,7 @@
     DocumentIdle = 2
     
     scriptChanged = pyqtSignal()
+    updatingChanged = pyqtSignal(bool)
     
     def __init__(self, manager, path):
         """
@@ -48,6 +50,7 @@
         
         self.__include = []
         self.__exclude = []
+        self.__require = []
         
         self.__downloadUrl = QUrl()
         self.__updateUrl = QUrl()
@@ -59,6 +62,10 @@
         self.__valid = False
         self.__noFrames = False
         
+        self.__updating = False
+        
+        self.__downloaders = []
+        
         self.__parseScript()
         
         self.__fileWatcher.delayedFileChanged.connect(
@@ -177,22 +184,31 @@
         """
         return self.__exclude[:]
     
-    def script(self):
+    def require(self):
         """
-        Public method to get the Javascript source.
+        Public method to get the list of required scripts.
         
-        @return Javascript source (string)
+        @return list of required scripts (list of strings)
         """
-        return self.__script
+        return self.__require[:]
     
     def fileName(self):
         """
         Public method to get the path of the Javascript file.
         
-        @return path path of the Javascript file (string)
+        @return path of the Javascript file (string)
         """
         return self.__fileName
     
+    def isUpdating(self):
+        """
+        Public method to get the updating flag.
+        
+        @return updating flag
+        @rtype bool
+        """
+        return self.__updating
+    
     @pyqtSlot(str)
     def __watchedFileChanged(self, fileName):
         """
@@ -202,12 +218,7 @@
         @type str
         """
         if self.__fileName == fileName:
-            self.__parseScript()
-            
-            self.__manager.removeScript(self, False)
-            self.__manager.addScript(self)
-            
-            self.scriptChanged.emit()
+            self.__reloadScript()
     
     def __parseScript(self):
         """
@@ -221,6 +232,7 @@
         
         self.__include = []
         self.__exclude = []
+        self.__require = []
         
         self.__downloadUrl = QUrl()
         self.__updateUrl = QUrl()
@@ -250,7 +262,6 @@
             # invalid script file
             return
         
-        requireList = []
         for line in metaDataBlock.splitlines():
             if not line.strip():
                 continue
@@ -290,7 +301,7 @@
                 self.__exclude.append(value)
             
             elif key == "@require":
-                requireList.append(value)
+                self.__require.append(value)
             
             elif key == "@run-at":
                 if value == "document-end":
@@ -313,33 +324,38 @@
             QByteArray(self.fullName().encode("utf-8")),
             QCryptographicHash.Md4).toHex()).decode("ascii")
         valuesScript = values_js.format(nspace)
-        runCheck = """
-            for (var value of {0}) {{
-                var re = new RegExp(value);
-                if (re.test(window.location.href)) {{
+        if qVersion() < "5.8.0":
+            runCheck = """
+                for (var value of {0}) {{
+                    var re = new RegExp(value);
+                    if (re.test(window.location.href)) {{
+                        return;
+                    }}
+                }}
+                __eric_includes = false;
+                for (var value of {1}) {{
+                    var re = new RegExp(value);
+                    if (re.test(window.location.href)) {{
+                        __eric_includes = true;
+                        break;
+                    }}
+                }}
+                if (!__eric_includes) {{
                     return;
                 }}
-            }}
-            __eric_includes = false;
-            for (var value of {1}) {{
-                var re = new RegExp(value);
-                if (re.test(window.location.href)) {{
-                    __eric_includes = true;
-                    break;
-                }}
-            }}
-            if (!__eric_includes) {{
-                return;
-            }}
-            delete __eric_includes;""".format(
-            self.__toJavaScriptList(self.__exclude[:]),
-            self.__toJavaScriptList(self.__include[:])
-        )
-        runCheck = ""
-        self.__script = "(function(){{{0}\n{1}\n{2}\n{3}\n}})();".format(
-            runCheck, valuesScript,
-            self.__manager.requireScripts(requireList), fileData
-        )
+                delete __eric_includes;""".format(
+                self.__toJavaScriptList(self.__exclude[:]),
+                self.__toJavaScriptList(self.__include[:])
+            )
+            self.__script = "(function(){{{0}\n{1}\n{2}\n{3}\n}})();".format(
+                runCheck, valuesScript,
+                self.__manager.requireScripts(self.__require), fileData
+            )
+        else:
+            self.__script = "(function(){{{0}\n{1}\n{2}\n}})();".format(
+                valuesScript, self.__manager.requireScripts(self.__require),
+                fileData
+            )
         self.__valid = True
     
     def webScript(self):
@@ -350,21 +366,23 @@
         @rtype QWebEngineScript
         @exception ValueError raised to indicate an unsupported start point
         """
-        if self.startAt() == GreaseMonkeyScript.DocumentStart:
-            injectionPoint = QWebEngineScript.DocumentCreation
-        elif self.startAt() == GreaseMonkeyScript.DocumentEnd:
-            injectionPoint = QWebEngineScript.DocumentReady
-        elif self.startAt() == GreaseMonkeyScript.DocumentIdle:
-            injectionPoint = QWebEngineScript.Deferred
-        else:
-            raise ValueError("Wrong script start point.")
+        if qVersion() < "5.8.0":
+            if self.startAt() == GreaseMonkeyScript.DocumentStart:
+                injectionPoint = QWebEngineScript.DocumentCreation
+            elif self.startAt() == GreaseMonkeyScript.DocumentEnd:
+                injectionPoint = QWebEngineScript.DocumentReady
+            elif self.startAt() == GreaseMonkeyScript.DocumentIdle:
+                injectionPoint = QWebEngineScript.Deferred
+            else:
+                raise ValueError("Wrong script start point.")
         
         script = QWebEngineScript()
         script.setSourceCode("{0}\n{1}".format(
             bootstrap_js, self.__script
         ))
         script.setName(self.fullName())
-        script.setInjectionPoint(injectionPoint)
+        if qVersion() < "5.8.0":
+            script.setInjectionPoint(injectionPoint)
         script.setWorldId(WebBrowserPage.SafeJsWorld)
         script.setRunsOnSubFrames(not self.__noFrames)
         return script
@@ -379,15 +397,102 @@
         @return JavaScript script containing the list
         @rtype str
         """
-        patternList = []
-        for pattern in patterns:
-            if pattern.startswith("/") and pattern.endswith("/") and \
-                    len(pattern) > 1:
-                pattern = pattern[1:-1]
-            else:
-                pattern = pattern.replace(".", "\\.").replace("*", ".*")
-            pattern = "'{0}'".format(pattern)
-            patternList.append(pattern)
+        if qVersion() >= "5.8.0":
+            script = ""
+        else:
+            patternList = []
+            for pattern in patterns:
+                if pattern.startswith("/") and pattern.endswith("/") and \
+                        len(pattern) > 1:
+                    pattern = pattern[1:-1]
+                else:
+                    pattern = pattern.replace(".", "\\.").replace("*", ".*")
+                pattern = "'{0}'".format(pattern)
+                patternList.append(pattern)
+            
+            script = "[{0}]".format(",".join(patternList))
+        return script
+    
+    def updateScript(self):
+        """
+        Public method to updated the script.
+        """
+        if not self.__downloadUrl.isValid() or self.__updating:
+            return
+        
+        self.__updating = True
+        self.updatingChanged.emit(self.__updating)
+        
+        downloader = GreaseMonkeyDownloader(
+            self.__downloadUrl,
+            self.__manager,
+            GreaseMonkeyDownloader.DownloadMainScript)
+        downloader.updateScript(self.__fileName)
+        downloader.finished.connect(self.__downloaderFinished)
+        downloader.error.connect(self.__downloaderError)
+        self.__downloaders.append(downloader)
         
-        script = "[{0}]".format(",".join(patternList))
-        return script
+        self.__downloadRequires()
+    
+    def __downloaderFinished(self):
+        """
+        Private slot to handle a finished download.
+        """
+        downloader = self.sender()
+        if downloader in self.__downloaders:
+            self.__downloaders.remove(downloader)
+        self.__updating = False
+        self.updatingChanged.emit(self.__updating)
+    
+    def __downloaderError(self):
+        """
+        Private slot to handle a downloader error.
+        """
+        downloader = self.sender()
+        if downloader in self.__downloaders:
+            self.__downloaders.remove(downloader)
+        self.__updating = False
+        self.updatingChanged.emit(self.__updating)
+    
+    def __reloadScript(self):
+        """
+        Private method to reload the script.
+        """
+        self.__parseScript()
+        
+        self.__manager.removeScript(self, False)
+        self.__manager.addScript(self)
+        
+        self.scriptChanged.emit()
+    
+    def __downloadRequires(self):
+        """
+        Private method to download the required scripts.
+        """
+        for urlStr in self.__require:
+            if not self.__manager.requireScripts([urlStr]):
+                downloader = GreaseMonkeyDownloader(
+                    QUrl(urlStr),
+                    self.__manager,
+                    GreaseMonkeyDownloader.DownloadRequireScript)
+                downloader.finished.connect(self.__requireDownloaded)
+                downloader.error.connect(self.__requireDownloadError)
+                self.__downloaders.append(downloader)
+    
+    def __requireDownloaded(self):
+        """
+        Private slot to handle a finished download of a required script.
+        """
+        downloader = self.sender()
+        if downloader in self.__downloaders:
+            self.__downloaders.remove(downloader)
+        
+        self.__reloadScript()
+    
+    def __requireDownloadError(self):
+        """
+        Private slot to handle a downloader error.
+        """
+        downloader = self.sender()
+        if downloader in self.__downloaders:
+            self.__downloaders.remove(downloader)

eric ide

mercurial