Просмотр исходного кода

fix: support relative paths for resources

fix #130
Gerald 8 лет назад
Родитель
Сommit
9ec9102890
4 измененных файлов с 67 добавлено и 45 удалено
  1. 39 31
      src/background/utils/db.js
  2. 2 4
      src/background/utils/script.js
  3. 11 0
      src/common/index.js
  4. 15 10
      src/options/views/confirm.vue

+ 39 - 31
src/background/utils/db.js

@@ -1,5 +1,5 @@
 import Promise from 'sync-promise-lite';
-import { i18n, request, buffer2string } from 'src/common';
+import { i18n, request, buffer2string, getFullUrl } from 'src/common';
 import { getNameURI, getScriptInfo, isRemote, parseMeta, newScript } from './script';
 import { testScript, testBlacklist } from './tester';
 
@@ -494,36 +494,43 @@ export function parseScript(data) {
     },
   };
   const tx = db.transaction(['scripts', 'require'], 'readwrite');
-  // @require
-  meta.require.forEach(url => {
-    const cache = data.require && data.require[url];
-    if (cache) saveRequire(url, cache, tx);
-    else fetchRequire(url);
-  });
-  // @resource
-  Object.keys(meta.resources).forEach(k => {
-    const url = meta.resources[k];
-    const cache = data.resources && data.resources[url];
-    if (cache) saveCache(url, cache);
-    else fetchCache(url);
-  });
-  // @icon
-  if (isRemote(meta.icon)) {
-    fetchCache(meta.icon, ({ blob: getBlob }) => new Promise((resolve, reject) => {
-      const blob = getBlob({ type: 'image/png' });
-      const url = URL.createObjectURL(blob);
-      const image = new Image();
-      const free = () => URL.revokeObjectURL(url);
-      image.onload = () => {
-        free();
-        resolve();
-      };
-      image.onerror = () => {
-        free();
-        reject();
-      };
-      image.src = url;
-    }));
+  function fetchResources(base) {
+    // @require
+    meta.require.forEach(url => {
+      const fullUrl = getFullUrl(url, base);
+      const cache = data.require && data.require[fullUrl];
+      if (cache) saveRequire(fullUrl, cache, tx);
+      else fetchRequire(fullUrl);
+    });
+    // @resource
+    Object.keys(meta.resources).forEach(k => {
+      const url = meta.resources[k];
+      const fullUrl = getFullUrl(url, base);
+      const cache = data.resources && data.resources[fullUrl];
+      if (cache) saveCache(fullUrl, cache);
+      else fetchCache(fullUrl);
+    });
+    // @icon
+    if (isRemote(meta.icon)) {
+      fetchCache(
+        getFullUrl(meta.icon, base),
+        ({ blob: getBlob }) => new Promise((resolve, reject) => {
+          const blob = getBlob({ type: 'image/png' });
+          const url = URL.createObjectURL(blob);
+          const image = new Image();
+          const free = () => URL.revokeObjectURL(url);
+          image.onload = () => {
+            free();
+            resolve();
+          };
+          image.onerror = () => {
+            free();
+            reject();
+          };
+          image.src = url;
+        }),
+      );
+    }
   }
   return queryScript(data.id, meta, tx)
   .then(result => {
@@ -547,6 +554,7 @@ export function parseScript(data) {
       script.custom.homepageURL = data.from;
     }
     if (isRemote(data.url)) script.custom.lastInstallURL = data.url;
+    fetchResources(script.custom.lastInstallURL);
     script.custom.modified = data.modified || Date.now();
     return saveScript(script, tx);
   })

+ 2 - 4
src/background/utils/script.js

@@ -1,10 +1,8 @@
+export { isRemote } from 'src/common';
+
 const metaStart = '==UserScript==';
 const metaEnd = '==/UserScript==';
 
-export function isRemote(url) {
-  return url && !(/^(file|data):/.test(url));
-}
-
 export function isUserScript(text) {
   if (/^\s*</.test(text)) return false; // HTML
   if (text.indexOf(metaStart) < 0) return false;  // Lack of meta block

+ 11 - 0
src/common/index.js

@@ -187,3 +187,14 @@ export function buffer2string(buffer) {
   }
   return str;
 }
+
+export function getFullUrl(url, base) {
+  const obj = new URL(url, base);
+  // Do not allow `file:` protocol
+  if (obj.protocol === 'file:') obj.protocol = 'http:';
+  return obj.href;
+}
+
+export function isRemote(url) {
+  return url && !(/^(file|data):/.test(url));
+}

+ 15 - 10
src/options/views/confirm.vue

@@ -30,7 +30,7 @@
 </template>
 
 <script>
-import { sendMessage, zfill, request, buffer2string } from 'src/common';
+import { sendMessage, zfill, request, buffer2string, isRemote, getFullUrl } from 'src/common';
 import options from 'src/common/options';
 import initCache from 'src/common/cache';
 import VmCode from './code';
@@ -63,7 +63,7 @@ export default {
       return this.store.route.query;
     },
     isLocal() {
-      return /^file:\/\/\//.test(this.info.url);
+      return !isRemote(this.info.url);
     },
   },
   mounted() {
@@ -131,14 +131,19 @@ export default {
         updateStatus();
         this.require = {};
         this.resources = {};
-        const promises = script.require.map(url => (
-          this.getFile(url, { useCache: true }).then(res => {
-            this.require[url] = res;
-          })
-        ))
-        .concat(urls.map(url => this.getFile(url, { isBlob: true, useCache: true }).then((res) => {
-          this.resources[url] = res;
-        })))
+        const promises = script.require.map(url => {
+          const fullUrl = getFullUrl(url, this.info.url);
+          return this.getFile(fullUrl, { useCache: true }).then(res => {
+            this.require[fullUrl] = res;
+          });
+        })
+        .concat(urls.map(url => {
+          const fullUrl = getFullUrl(url, this.info.url);
+          return this.getFile(fullUrl, { isBlob: true, useCache: true })
+          .then(res => {
+            this.resources[fullUrl] = res;
+          });
+        }))
         .map(promise => promise.then(() => {
           finished += 1;
           updateStatus();