[Pkg-mozext-commits] [greasemonkey] 01/03: Imported Upstream version 1.13~beta2

David Prévot taffit at alioth.debian.org
Fri Oct 4 22:51:11 UTC 2013


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository greasemonkey.

commit 51cf9ac924cbfc4ffde31f8862a2df22ef8fa93b
Author: David Prévot <taffit at debian.org>
Date:   Fri Oct 4 18:38:04 2013 -0400

    Imported Upstream version 1.13~beta2
---
 components/greasemonkey.js           |    3 +-
 content/addons4-overlay.js           |    1 +
 content/config.js                    |   41 ++----
 content/options.js                   |    6 +-
 content/options.xul                  |   23 ++--
 defaults/preferences/greasemonkey.js |    3 +
 install.rdf                          |    2 +-
 locale/ar/greasemonkey.dtd           |    2 +
 locale/ca/greasemonkey.dtd           |    2 +
 locale/cs/greasemonkey.dtd           |    2 +
 locale/da/greasemonkey.dtd           |    2 +
 locale/de/greasemonkey.dtd           |    2 +
 locale/el/greasemonkey.dtd           |    2 +
 locale/en-US/greasemonkey.dtd        |    2 +
 locale/es-AR/greasemonkey.dtd        |    2 +
 locale/es-CL/greasemonkey.dtd        |    2 +
 locale/es-ES/greasemonkey.dtd        |    2 +
 locale/es-MX/greasemonkey.dtd        |    2 +
 locale/et/greasemonkey.dtd           |    2 +
 locale/fa/greasemonkey.dtd           |    2 +
 locale/fi/greasemonkey.dtd           |    2 +
 locale/fr/greasemonkey.dtd           |    2 +
 locale/gl/greasemonkey.dtd           |    2 +
 locale/he/greasemonkey.dtd           |    2 +
 locale/hu/greasemonkey.dtd           |    2 +
 locale/it/greasemonkey.dtd           |    2 +
 locale/ja/greasemonkey.dtd           |    2 +
 locale/ko/greasemonkey.dtd           |    2 +
 locale/lt/greasemonkey.dtd           |    2 +
 locale/nl/greasemonkey.dtd           |    2 +
 locale/pl/greasemonkey.dtd           |    2 +
 locale/pt-BR/greasemonkey.dtd        |    2 +
 locale/ro/greasemonkey.dtd           |    2 +
 locale/ru/greasemonkey.dtd           |    2 +
 locale/si/greasemonkey.dtd           |    2 +
 locale/sk/greasemonkey.dtd           |    2 +
 locale/sr/greasemonkey.dtd           |    2 +
 locale/sv-SE/greasemonkey.dtd        |    2 +
 locale/tr/greasemonkey.dtd           |    2 +
 locale/uk/greasemonkey.dtd           |    2 +
 locale/zh-CN/gm-addons.dtd           |    2 +-
 locale/zh-CN/gm-addons.properties    |    2 +-
 locale/zh-CN/greasemonkey.dtd        |    6 +-
 locale/zh-TW/greasemonkey.dtd        |    2 +
 modules/addons4.js                   |    3 +-
 {content => modules}/miscapis.js     |  153 ++++++++++++++++++++-
 modules/parseScript.js               |   10 +-
 modules/remoteScript.js              |   17 ++-
 modules/script.js                    |   65 +++++----
 modules/scriptDependency.js          |    2 +-
 modules/sync.js                      |  251 ++++++++++++++++++++++++++++++++++
 modules/util/apiLeakCheck.js         |    5 +-
 52 files changed, 569 insertions(+), 94 deletions(-)

diff --git a/components/greasemonkey.js b/components/greasemonkey.js
index 7a04bff..6ebc422 100644
--- a/components/greasemonkey.js
+++ b/components/greasemonkey.js
@@ -11,8 +11,10 @@ var Cu = Components.utils;
 Cu.import("resource://greasemonkey/third-party/getChromeWinForContentWin.js");
 Cu.import('resource://greasemonkey/GM_setClipboard.js');
 Cu.import('resource://greasemonkey/constants.js');
+Cu.import("resource://greasemonkey/miscapis.js");
 Cu.import("resource://greasemonkey/parseScript.js");
 Cu.import("resource://greasemonkey/prefmanager.js");
+Cu.import("resource://greasemonkey/sync.js");
 Cu.import("resource://greasemonkey/util.js");
 Cu.import("resource://greasemonkey/xmlhttprequester.js");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -303,7 +305,6 @@ function startup(aService) {
       .getService(Ci.mozIJSSubScriptLoader);
   loader.loadSubScript("chrome://global/content/XPCNativeWrapper.js");
   loader.loadSubScript("chrome://greasemonkey/content/config.js");
-  loader.loadSubScript("chrome://greasemonkey/content/miscapis.js");
   loader.loadSubScript("chrome://greasemonkey/content/third-party/mpl-utils.js");
 
   var observerService = Components.classes['@mozilla.org/observer-service;1']
diff --git a/content/addons4-overlay.js b/content/addons4-overlay.js
index 089af8e..6d249b4 100644
--- a/content/addons4-overlay.js
+++ b/content/addons4-overlay.js
@@ -72,6 +72,7 @@ var observer = {
         if (!data) break;
         var oldAddon = ScriptAddonFactoryByScript({'id': data});
         if (!oldAddon) break;
+        addon = ScriptAddonFactoryByScript(script, true);
 
         // Use old and new the addon references to update the view.
         var item = createItem(addon);
diff --git a/content/config.js b/content/config.js
index 244afb1..401daf4 100644
--- a/content/config.js
+++ b/content/config.js
@@ -227,7 +227,7 @@ Config.prototype.updateModifiedScripts = function(aWhen, aSafeWin) {
       var scope = {};
       Components.utils.import('resource://greasemonkey/parseScript.js', scope);
       var parsedScript = scope.parse(
-          script.textContent, GM_util.uriFromUrl(script._downloadURL));
+          script.textContent, GM_util.uriFromUrl(script.downloadURL));
       // TODO: Show PopupNotifications about parse error(s)?
       script.updateFromNewScript(parsedScript, aSafeWin);
     } else {
@@ -256,20 +256,15 @@ Config.prototype._updateVersion = function() {
   Components.utils.import("resource://gre/modules/AddonManager.jsm");
   AddonManager.getAddonByID(this.GM_GUID, GM_util.hitch(this, function(addon) {
     var oldVersion = GM_prefRoot.getValue("version");
-    if ('0.0' == oldVersion) {
-      // In case of pref branch transition, find the existing version there.
-      oldVersion = this._getLegacyPrefMan().getValue("version", "0.0");
-    }
     var newVersion = addon.version;
 
     var versionChecker = Components
         .classes["@mozilla.org/xpcom/version-comparator;1"]
         .getService(Components.interfaces.nsIVersionComparator);
     if (oldVersion != '0.0'
-        && (versionChecker.compare(oldVersion, '1.5') < 0)
-        && (versionChecker.compare(newVersion, '1.5beta1') >= 0)
+      && (versionChecker.compare(oldVersion, '1.13') < 0)
     ) {
-      this._migratePrefs();
+      this._migrateScriptValsToStorage();
     }
 
     // Update the stored current version so we don't do this work again.
@@ -291,22 +286,14 @@ Config.prototype._updateVersion = function() {
   }));
 };
 
-Config.prototype._getLegacyPrefMan = function() {
-  // Supports #1652.
-  var legacyPrefMan = new GM_PrefManager();
-  legacyPrefMan.pref = Components.classes["@mozilla.org/preferences-service;1"]
-     .getService(Components.interfaces.nsIPrefService)
-     .getBranch('greasemonkey.');
-  return legacyPrefMan;
-};
-
-Config.prototype._migratePrefs = function() {
-  // See #1652.  Migrates from "greasemonkey." to "extensions.greasemonkey.".
-  var fromBranch = this._getLegacyPrefMan();
-  var toBranch = GM_prefRoot;
-  var prefNames = fromBranch.listValues();
-  for (var i = 0, prefName = null; prefName = prefNames[i]; i++) {
-    toBranch.setValue(prefName, fromBranch.getValue(prefName));
-    fromBranch.remove(prefName);
-  }
-};
+Config.prototype._migrateScriptValsToStorage = function() {
+  for (var i = 0, script; script = this._scripts[i]; i++) {
+    var prefsVals = new GM_ScriptStoragePrefs(script);
+    var storageVals = new GM_ScriptStorage(script);
+    var names = prefsVals.listValues();
+    for (var j = 0, name = null; name = names[j]; j++) {
+      storageVals.setValue(name, prefsVals.getValue(name));
+      prefsVals.deleteValue(name);
+    }
+  };
+}
diff --git a/content/options.js b/content/options.js
index 3869684..ae087b8 100644
--- a/content/options.js
+++ b/content/options.js
@@ -4,6 +4,8 @@ Components.utils.import('resource://greasemonkey/util.js');
 function GM_loadOptions() {
   document.getElementById('check-uninstall')
       .checked = GM_prefRoot.getValue('uninstallPreferences');
+  document.getElementById('check-sync')
+  .checked = GM_prefRoot.getValue('sync.enabled');
   document.getElementById('secure-update')
       .checked = GM_prefRoot.getValue('requireSecureUpdates');
   document.getElementById('submit-stats')
@@ -17,6 +19,8 @@ function GM_loadOptions() {
 }
 
 function GM_saveOptions(checkbox) {
+  GM_prefRoot.setValue('sync.enabled',
+      !!document.getElementById('check-sync').checked);
   GM_prefRoot.setValue('uninstallPreferences',
       !!document.getElementById('check-uninstall').checked);
   GM_prefRoot.setValue('requireSecureUpdates',
@@ -27,6 +31,6 @@ function GM_saveOptions(checkbox) {
       document.getElementById('globalExcludes').pages;
   GM_prefRoot.setValue('newScript.removeUnused',
       !!document.getElementById('newScript-removeUnused').checked);
-  GM_prefRoot.getValue('newScript.template',
+  GM_prefRoot.setValue('newScript.template',
       document.getElementById('newScript-template').value);
 }
diff --git a/content/options.xul b/content/options.xul
index ed99cc0..288dbcc 100644
--- a/content/options.xul
+++ b/content/options.xul
@@ -27,26 +27,23 @@
 
 <vbox>
   <groupbox>
-    <caption label="&options.editor;" />
-    <hbox>
-      <button oncommand="GM_util.setEditor(1)" label="&options.defaultEditor;" flex="1"/>
-      <button oncommand="GM_util.setEditor(0)" label="&options.browseForEditor;" flex="1"/>
-    </hbox>
-  </groupbox>
-
-  <groupbox>
-    <caption label="&Uninstall;" />
+    <caption label="&prefWindow.titleWin;" />
     <checkbox id="check-uninstall" label="&AlsoUninstallPrefs;" />
+    <checkbox id="secure-update" label="&RequireSecureUpdates;" />
+    <checkbox id="submit-stats" label="&SubmitStats;" />
   </groupbox>
 
   <groupbox>
-    <caption label="&UpdateChecking;" />
-    <checkbox id="secure-update" label="&RequireSecureUpdates;" />
+    <caption label="&options.experimental;" />
+    <checkbox id="check-sync" label="&EnableFirefoxSync;" />
   </groupbox>
 
   <groupbox>
-    <caption label="&AnonymousStatistics;" />
-    <checkbox id="submit-stats" label="&SubmitStats;" />
+    <caption label="&options.editor;" />
+    <hbox>
+      <button oncommand="GM_util.setEditor(1)" label="&options.defaultEditor;" flex="1"/>
+      <button oncommand="GM_util.setEditor(0)" label="&options.browseForEditor;" flex="1"/>
+    </hbox>
   </groupbox>
 
   <groupbox>
diff --git a/defaults/preferences/greasemonkey.js b/defaults/preferences/greasemonkey.js
index 29a9dec..7950603 100644
--- a/defaults/preferences/greasemonkey.js
+++ b/defaults/preferences/greasemonkey.js
@@ -16,6 +16,9 @@ pref("extensions.greasemonkey.stats.lastsubmittime", "Thu, 01 Jan 1970 00:00:00
 pref("extensions.greasemonkey.stats.optedin", false);
 pref("extensions.greasemonkey.stats.prompted", false);
 pref("extensions.greasemonkey.stats.url", "https://stats.greasespot.net/submit/");
+pref("extensions.greasemonkey.sync.enabled", false);
+pref("extensions.greasemonkey.sync.values", false);
+pref("extensions.greasemonkey.sync.values_max_size_per_script", 65536);
 pref("extensions.greasemonkey.uninstallPreferences", true);
 pref("extensions.greasemonkey.unmhtIsGreaseable", false);
 pref("extensions.greasemonkey.version", "0.0");
diff --git a/install.rdf b/install.rdf
index 7596330..7ac7dbb 100644
--- a/install.rdf
+++ b/install.rdf
@@ -6,7 +6,7 @@
   <Description about="urn:mozilla:install-manifest">
 
     <em:id>{e4a8a97b-f2ed-450b-b12d-ee082ba24781}</em:id>
-    <em:version>1.12</em:version>
+    <em:version>1.13beta2</em:version>
     <em:creator>Aaron Boodman; http://youngpup.net/</em:creator>
     <em:homepageURL>http://www.greasespot.net/</em:homepageURL>
     <em:optionsURL>chrome://greasemonkey/content/options.xul</em:optionsURL>
diff --git a/locale/ar/greasemonkey.dtd b/locale/ar/greasemonkey.dtd
index a803627..bee8f0f 100644
--- a/locale/ar/greasemonkey.dtd
+++ b/locale/ar/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "لايعمل على (صحة لكل سطر)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "المحرر">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "باستثناء العالمية">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "إلغاء التثبيت">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "أيضا مسح جميع الأعدادات">
 <!ENTITY UpdateChecking "تحديث السكربت">
diff --git a/locale/ca/greasemonkey.dtd b/locale/ca/greasemonkey.dtd
index 22997c4..66b16bf 100644
--- a/locale/ca/greasemonkey.dtd
+++ b/locale/ca/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excludes (One per line)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Uninstall">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Also uninstall associated preferences">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/cs/greasemonkey.dtd b/locale/cs/greasemonkey.dtd
index c66e5b0..cbc95f6 100644
--- a/locale/cs/greasemonkey.dtd
+++ b/locale/cs/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Vyloučené stránky (každá na jeden řádek)">
 <!ENTITY newscript.fromClipboard "Sestavit skript ze schránky">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Použít výchozí editor">
 <!ENTITY options.browseForEditor "Vybrat program pro editaci">
 <!ENTITY options.globalExcludes "Vyloučené stránky globálně">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Odebrat nepoužité řádky">
 <!ENTITY Uninstall "Odinstalace">
 <!ENTITY AnonymousStatistics "Anonymní statistiky">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Shromažďovat a odesílat anonymní statistiky o používání pro zlepšení Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Odinstalovat i přidružená nastavení">
 <!ENTITY UpdateChecking "Kontrola aktualizací">
diff --git a/locale/da/greasemonkey.dtd b/locale/da/greasemonkey.dtd
index 5c5cc4b..5e7d018 100644
--- a/locale/da/greasemonkey.dtd
+++ b/locale/da/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Ekskluderinger (en pr. linje)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Redigeringsprogram">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Globale ekskluderinger">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Afinstaller">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Også afinstallere tilhørende indstilliner">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/de/greasemonkey.dtd b/locale/de/greasemonkey.dtd
index ad271ec..d5926a2 100644
--- a/locale/de/greasemonkey.dtd
+++ b/locale/de/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Nicht auf diese Seiten anwenden (zeilenweise angeben):">
 <!ENTITY newscript.fromClipboard "Script aus der Zwischenablage verwenden.">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Standard Editor verwenden">
 <!ENTITY options.browseForEditor "Nach Editor Programm suchen">
 <!ENTITY options.globalExcludes "Globale Ausschlüsse">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Deinstallieren">
 <!ENTITY AnonymousStatistics "Anonyme Statistik">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Sammeln und einreichen von anonymen Nutzungsstatistiken an Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Zugehörige Einstellungen ebenfalls entfernen">
 <!ENTITY UpdateChecking "Auf Aktualisierungen überprüfen">
diff --git a/locale/el/greasemonkey.dtd b/locale/el/greasemonkey.dtd
index c464d47..a29717b 100644
--- a/locale/el/greasemonkey.dtd
+++ b/locale/el/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Εξαιρέσεις (Μια ανά γραμμή)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Επεξεργαστής κειμένου">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Καθολικές Εξαιρέσεις">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Απεγκατάσταση">
 <!ENTITY AnonymousStatistics "Ανώνυμα στατιστικά">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Συγκέντρωση και υποβολή στατιστικών ανώνυμης χρήσης για βελτίωση του Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Απεγκατάσταση και των σχετικών ρυθμίσεων">
 <!ENTITY UpdateChecking "Έλεγχος Ενημέρωσης">
diff --git a/locale/en-US/greasemonkey.dtd b/locale/en-US/greasemonkey.dtd
index 22997c4..66b16bf 100644
--- a/locale/en-US/greasemonkey.dtd
+++ b/locale/en-US/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excludes (One per line)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Uninstall">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Also uninstall associated preferences">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/es-AR/greasemonkey.dtd b/locale/es-AR/greasemonkey.dtd
index 1a59a19..b40688b 100644
--- a/locale/es-AR/greasemonkey.dtd
+++ b/locale/es-AR/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excluidos (Uno por línea)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Desinstalar">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "También desinstalar las preferencias asociadas">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/es-CL/greasemonkey.dtd b/locale/es-CL/greasemonkey.dtd
index a2ba228..e4604aa 100644
--- a/locale/es-CL/greasemonkey.dtd
+++ b/locale/es-CL/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excludes (uno por línea)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Exclusiones generales">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Eliminar">
 <!ENTITY AnonymousStatistics "Estadãsticas Anônimas">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Recolectar y enviar estadãsticas anônimas de uso para mejorar Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Eliminar preferencias asociadas">
 <!ENTITY UpdateChecking "Verificar para actualizar">
diff --git a/locale/es-ES/greasemonkey.dtd b/locale/es-ES/greasemonkey.dtd
index 22997c4..66b16bf 100644
--- a/locale/es-ES/greasemonkey.dtd
+++ b/locale/es-ES/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excludes (One per line)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Uninstall">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Also uninstall associated preferences">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/es-MX/greasemonkey.dtd b/locale/es-MX/greasemonkey.dtd
index 86a2407..cde973d 100644
--- a/locale/es-MX/greasemonkey.dtd
+++ b/locale/es-MX/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excluidas(Uno por línea)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Desinstalar">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "También desinstalar preferencias asociadas">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/et/greasemonkey.dtd b/locale/et/greasemonkey.dtd
index 89e30b2..69d9655 100644
--- a/locale/et/greasemonkey.dtd
+++ b/locale/et/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excludes (One per line)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Redaktor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Eemalda">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Also uninstall associated preferences">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/fa/greasemonkey.dtd b/locale/fa/greasemonkey.dtd
index b3145ef..fa3799b 100644
--- a/locale/fa/greasemonkey.dtd
+++ b/locale/fa/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "مستثنا کردن (یکی در هر خط)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "ویراستار">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "مستثنا های کلی">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "عزل">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "همچنین حذف تنظیمات وابسته">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/fi/greasemonkey.dtd b/locale/fi/greasemonkey.dtd
index e4babb8..d716133 100644
--- a/locale/fi/greasemonkey.dtd
+++ b/locale/fi/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Pois lukien sivut (yksi per rivi)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Tekstieditori">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Yleisesti poisluettavat">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Poisto">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Poista myös skriptin asetukset">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/fr/greasemonkey.dtd b/locale/fr/greasemonkey.dtd
index 5e436b8..71f1e8e 100644
--- a/locale/fr/greasemonkey.dtd
+++ b/locale/fr/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Exclus (un par ligne)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Éditeur">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Désinstaller">
 <!ENTITY AnonymousStatistics "Statistiques anonymes">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Récolte et envoie de statistiques anonymes destinées à améliorer Greasemonkey">
 <!ENTITY AlsoUninstallPrefs "Désinstalle également les préférences associées">
 <!ENTITY UpdateChecking "Vérifcation des mises à jour">
diff --git a/locale/gl/greasemonkey.dtd b/locale/gl/greasemonkey.dtd
index 8c2c5c2..64801b7 100644
--- a/locale/gl/greasemonkey.dtd
+++ b/locale/gl/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excluír (un por liña)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Exclusións globais">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Desinstalar">
 <!ENTITY AnonymousStatistics "Estadísticas anónimas">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Envía as estadísticas anónimas de uso para mellorar Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Tamén desinstalar as preferencias asociadas">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/he/greasemonkey.dtd b/locale/he/greasemonkey.dtd
index 7861b7e..947d0c4 100644
--- a/locale/he/greasemonkey.dtd
+++ b/locale/he/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "לא כולל (אחד בכל שורה)">
 <!ENTITY newscript.fromClipboard "השתמש בקובץ Script מהלוח">
 <!ENTITY options.editor "עורך">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "אי הכללה כללית">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "הסר">
 <!ENTITY AnonymousStatistics "עיבוד נתונים ללא זיהוי המשתמש">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "אסיפה ומשלוח עיבוד נתונים ללא זיהוי המשתמש לצורך שיפור Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "הסר גם את המאייפנים המשוייכים לקובץ Script משתמש זה">
 <!ENTITY UpdateChecking "בדיקת עדכון">
diff --git a/locale/hu/greasemonkey.dtd b/locale/hu/greasemonkey.dtd
index 4483917..dc38ebe 100644
--- a/locale/hu/greasemonkey.dtd
+++ b/locale/hu/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Kizárt oldalak (soronként egy)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Szerkesztő">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Globális kivételek">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Eltávolítás">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Hozzákapcsolódó beállítások eltávolítása">
 <!ENTITY UpdateChecking "Frissítések keresése">
diff --git a/locale/it/greasemonkey.dtd b/locale/it/greasemonkey.dtd
index b228096..01f7b0d 100644
--- a/locale/it/greasemonkey.dtd
+++ b/locale/it/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Pagine escluse (una per riga)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Disinstalla">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Disinstalla anche le preferenze associate">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/ja/greasemonkey.dtd b/locale/ja/greasemonkey.dtd
index 024bdec..81a8289 100644
--- a/locale/ja/greasemonkey.dtd
+++ b/locale/ja/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "実行しないページ (改行で複数指定)">
 <!ENTITY newscript.fromClipboard "クリップボードのスクリプトを使用する">
 <!ENTITY options.editor "エディタ">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "標準のエディタを使用">
 <!ENTITY options.browseForEditor "エディタプログラムを参照">
 <!ENTITY options.globalExcludes "実行しないページ">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "未使用の行を削除">
 <!ENTITY Uninstall "削除">
 <!ENTITY AnonymousStatistics "匿名の統計">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Greasemonkey を改善するために匿名の利用統計を収集し送信する。">
 <!ENTITY AlsoUninstallPrefs "関連付けられた設定も削除">
 <!ENTITY UpdateChecking "更新の確認">
diff --git a/locale/ko/greasemonkey.dtd b/locale/ko/greasemonkey.dtd
index 5792332..ada111a 100644
--- a/locale/ko/greasemonkey.dtd
+++ b/locale/ko/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "제외함 (한 줄에 하나씩)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "편집기">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "삭제">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "관련된 환경 설정도 삭제">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/lt/greasemonkey.dtd b/locale/lt/greasemonkey.dtd
index 769e885..a4f0e8b 100644
--- a/locale/lt/greasemonkey.dtd
+++ b/locale/lt/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Kuriuose neveikia (po vieną eilutėj)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Redaktorius">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Nevykdomi visur">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Pašalinti">
 <!ENTITY AnonymousStatistics "Anoniminė statistika">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Rinkti ir siųsti anoniminę naudojimo statistiką.">
 <!ENTITY AlsoUninstallPrefs "Taipogi pašalinti susijusius nustatymus">
 <!ENTITY UpdateChecking "Atnaujinimų tikrinimas">
diff --git a/locale/nl/greasemonkey.dtd b/locale/nl/greasemonkey.dtd
index e587c1f..6045fb4 100644
--- a/locale/nl/greasemonkey.dtd
+++ b/locale/nl/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Sluit uit (één per regel)">
 <!ENTITY newscript.fromClipboard "Script van klembord gebruiken">
 <!ENTITY options.editor "Tekstverwerker">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Standaard bewerkingsprogramma gebruiken">
 <!ENTITY options.browseForEditor "Naar bewerkingsprogramma bladeren">
 <!ENTITY options.globalExcludes "Sluit globaal uit">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Deïnstalleren">
 <!ENTITY AnonymousStatistics "Anonieme statistieken">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Verzamel en verstuur anonieme gebruiksstatistieken om Greasemonkey te verbeteren.">
 <!ENTITY AlsoUninstallPrefs "Bijbehorende instellingen ook verwijderen">
 <!ENTITY UpdateChecking "Updatecontrole">
diff --git a/locale/pl/greasemonkey.dtd b/locale/pl/greasemonkey.dtd
index 06d6e76..818a5db 100644
--- a/locale/pl/greasemonkey.dtd
+++ b/locale/pl/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Witryny, na których skrypt nie będzie uruchamiany (jedna w wierszu)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Edytor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Wykluczenia globalne">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Odinstaluj">
 <!ENTITY AnonymousStatistics "Anonimowe statystyki">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Zbieraj i przekazuj anonimowo statystyki używania Greasemonkey, by pomóc w udoskonaleniu aplikacji.">
 <!ENTITY AlsoUninstallPrefs "Odinstaluj również skojarzone ustawienia">
 <!ENTITY UpdateChecking "Sprawdzaj dostępność aktualizacji">
diff --git a/locale/pt-BR/greasemonkey.dtd b/locale/pt-BR/greasemonkey.dtd
index d651ceb..de0b33d 100644
--- a/locale/pt-BR/greasemonkey.dtd
+++ b/locale/pt-BR/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Exclui (Um por linha)">
 <!ENTITY newscript.fromClipboard "Usar Script da Área de Transferência">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Usar Editor Padrão">
 <!ENTITY options.browseForEditor "Procurar Programa Padrão">
 <!ENTITY options.globalExcludes "Exclusões Globais">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remover linhas sem uso">
 <!ENTITY Uninstall "Desinstalar">
 <!ENTITY AnonymousStatistics "Estatísticas anônimas">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Receba e envie estatísticas anônimas de uso para melhorar o Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Desinstalar também configurações associadas">
 <!ENTITY UpdateChecking "Verificação de Atualizações">
diff --git a/locale/ro/greasemonkey.dtd b/locale/ro/greasemonkey.dtd
index 060163c..bcc7c34 100644
--- a/locale/ro/greasemonkey.dtd
+++ b/locale/ro/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Excluderi (una pe linie)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Excluderi globale">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Dezinstalare">
 <!ENTITY AnonymousStatistics "Statistici anonime">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Adună și trimite statistici anonime de utilizare pentru a îmbunătății Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Dezinstalează și preferințele asociate">
 <!ENTITY UpdateChecking "Verificare actualizări">
diff --git a/locale/ru/greasemonkey.dtd b/locale/ru/greasemonkey.dtd
index 3686d5a..2707032 100644
--- a/locale/ru/greasemonkey.dtd
+++ b/locale/ru/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Исключения (одно на строку)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Редактор">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Глобальные исключения">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Удаление">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Также удалять настройки скриптов">
 <!ENTITY UpdateChecking "Проверка обновлений">
diff --git a/locale/si/greasemonkey.dtd b/locale/si/greasemonkey.dtd
index 0022abc..f1fb503 100644
--- a/locale/si/greasemonkey.dtd
+++ b/locale/si/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "ඇතුලත් නොවූ වෙබ් අඩවි(එක පේලියකට එකකි)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "සංස්කාරකය">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Global Excludes">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "ඉවත් කරන්න">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "එසේම ආශ්‍රිත අභිමතද ඉවත් කරන්න">
 <!ENTITY UpdateChecking "Update Checking">
diff --git a/locale/sk/greasemonkey.dtd b/locale/sk/greasemonkey.dtd
index edb02a3..45d57d9 100644
--- a/locale/sk/greasemonkey.dtd
+++ b/locale/sk/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Vylučuje (jeden na riadok)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Editor">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Zahrnúť globálne">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Odinštalovať">
 <!ENTITY AnonymousStatistics "Anonymous Statistics">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Gather and submit anonymous usage statistics to improve Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Odinštalovať aj pridružené nastavenia">
 <!ENTITY UpdateChecking "Kontrolovanie aktualizácií">
diff --git a/locale/sr/greasemonkey.dtd b/locale/sr/greasemonkey.dtd
index d10d789..ae2c144 100644
--- a/locale/sr/greasemonkey.dtd
+++ b/locale/sr/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Изузима (једно по линији)">
 <!ENTITY newscript.fromClipboard "Користи скрипту из оставе">
 <!ENTITY options.editor "Уређивач">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Користи подразумевани уређивач">
 <!ENTITY options.browseForEditor "Потражи уређивач">
 <!ENTITY options.globalExcludes "Општа изузимања">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Уклони">
 <!ENTITY AnonymousStatistics "Анонимна статистика">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Прикупљај и шаљи анонимну статистику о коришћењу ради побољшања додатка Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Уклони и подешавања">
 <!ENTITY UpdateChecking "Проверавање ажурирања">
diff --git a/locale/sv-SE/greasemonkey.dtd b/locale/sv-SE/greasemonkey.dtd
index f542420..6f369a1 100644
--- a/locale/sv-SE/greasemonkey.dtd
+++ b/locale/sv-SE/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Undantag (ett per rad)">
 <!ENTITY newscript.fromClipboard "Använd skript från Urklipp">
 <!ENTITY options.editor "Redigeringsprogram">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Använd standardredigeringsprogrammet">
 <!ENTITY options.browseForEditor "Bläddra efter redigeringsprogram">
 <!ENTITY options.globalExcludes "Globala undantag">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Avinstallera">
 <!ENTITY AnonymousStatistics "Anonym statistik">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Samla in och skicka in anonym användningsstatistik för att förbättra Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Avinstallera även associerade inställningar">
 <!ENTITY UpdateChecking "Uppdateringskontroll">
diff --git a/locale/tr/greasemonkey.dtd b/locale/tr/greasemonkey.dtd
index 30a9697..6ee9ac2 100644
--- a/locale/tr/greasemonkey.dtd
+++ b/locale/tr/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Çıkarılanlar (satır başına bir tane)">
 <!ENTITY newscript.fromClipboard "Panodan Betik Kullan">
 <!ENTITY options.editor "Editör">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Varsayılan Düzenleyi Kullan">
 <!ENTITY options.browseForEditor "Düzenleyici Program Bul">
 <!ENTITY options.globalExcludes "Global Çıkarılanlar">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Kaldır">
 <!ENTITY AnonymousStatistics "Anonim İstatistikler">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Greasemonkey geliştirmeleri için anonim kullanım istatistiklerini topla ve gönder.">
 <!ENTITY AlsoUninstallPrefs "Ayrıca ilişkili tercihleri kaldır">
 <!ENTITY UpdateChecking "Güncelleştirme Kontrol Ediliyor">
diff --git a/locale/uk/greasemonkey.dtd b/locale/uk/greasemonkey.dtd
index bf7b184..43f399e 100644
--- a/locale/uk/greasemonkey.dtd
+++ b/locale/uk/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "Винятки (один на рядок)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "Редактор">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "Глобальні винятки">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "Вилучити">
 <!ENTITY AnonymousStatistics "Анонимна статистика">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "Збирати та надсилати анонимну статистику про використання для покращення Greasemonkey.">
 <!ENTITY AlsoUninstallPrefs "Вилучити також пов'язані налаштування">
 <!ENTITY UpdateChecking "Перевірка оновлень">
diff --git a/locale/zh-CN/gm-addons.dtd b/locale/zh-CN/gm-addons.dtd
index 753a7d2..f39e7a9 100644
--- a/locale/zh-CN/gm-addons.dtd
+++ b/locale/zh-CN/gm-addons.dtd
@@ -6,7 +6,7 @@
 <!ENTITY ExecuteLater "稍后执行">
 <!ENTITY ExecuteSooner "稍早执行">
 <!ENTITY FindUpdate "查找更新">
-<!ENTITY ForcedFindUpdate "Forced Find Updates">
+<!ENTITY ForcedFindUpdate "强制更新">
 <!ENTITY InstallUpdate "安装更新">
 <!ENTITY MoveDown "下移">
 <!ENTITY MoveDown.accesskey "D">
diff --git a/locale/zh-CN/gm-addons.properties b/locale/zh-CN/gm-addons.properties
index 07b3be4..053f45a 100644
--- a/locale/zh-CN/gm-addons.properties
+++ b/locale/zh-CN/gm-addons.properties
@@ -1,4 +1,4 @@
-confirmForceUpdate=This script appears to be locally modified.  Overwrite with remote contents?  This action cannot be undone.
+confirmForceUpdate=此脚本在本地曾被修改。用远程内容覆盖吗?(此操作不可撤销!)
 executionorder=执行顺序
 executionorder.tooltip=按执行顺序排序
 userscripts=用户脚本
diff --git a/locale/zh-CN/greasemonkey.dtd b/locale/zh-CN/greasemonkey.dtd
index c5d1370..527f97c 100644
--- a/locale/zh-CN/greasemonkey.dtd
+++ b/locale/zh-CN/greasemonkey.dtd
@@ -35,13 +35,15 @@
 <!ENTITY newscript.excludes "排除(每行一条)">
 <!ENTITY newscript.fromClipboard "使用剪贴板中的脚本">
 <!ENTITY options.editor "编辑器">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "使用默认编辑器">
 <!ENTITY options.browseForEditor "选择编辑器程序">
 <!ENTITY options.globalExcludes "全局排除">
-<!ENTITY options.newScript.template "New script template">
-<!ENTITY options.newScript.removeUnused "Remove unused lines">
+<!ENTITY options.newScript.template "新建脚本模板">
+<!ENTITY options.newScript.removeUnused "移除未用的行">
 <!ENTITY Uninstall "卸载">
 <!ENTITY AnonymousStatistics "匿名统计数据">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "收集和提交匿名的使用统计数据以帮助改善 Greasemonkey。">
 <!ENTITY AlsoUninstallPrefs "同时清除相关的首选项设置">
 <!ENTITY UpdateChecking "检查更新">
diff --git a/locale/zh-TW/greasemonkey.dtd b/locale/zh-TW/greasemonkey.dtd
index 78afb9f..307dbe1 100644
--- a/locale/zh-TW/greasemonkey.dtd
+++ b/locale/zh-TW/greasemonkey.dtd
@@ -35,6 +35,7 @@
 <!ENTITY newscript.excludes "不包含(每行一項)">
 <!ENTITY newscript.fromClipboard "Use Script From Clipboard">
 <!ENTITY options.editor "腳本編輯器">
+<!ENTITY options.experimental "Experimental">
 <!ENTITY options.defaultEditor "Use Default Editor">
 <!ENTITY options.browseForEditor "Browse for Editor Program">
 <!ENTITY options.globalExcludes "全域排除">
@@ -42,6 +43,7 @@
 <!ENTITY options.newScript.removeUnused "Remove unused lines">
 <!ENTITY Uninstall "腳本移除設定">
 <!ENTITY AnonymousStatistics "匿名統計">
+<!ENTITY EnableFirefoxSync "Enable Firefox Sync for User Scripts">
 <!ENTITY SubmitStats "收集並送出匿名統計資訊以幫助改進 Greasemonkey。">
 <!ENTITY AlsoUninstallPrefs "同時移除相關偏好設定">
 <!ENTITY UpdateChecking "檢查更新">
diff --git a/modules/addons4.js b/modules/addons4.js
index 05590a5..c0eab51 100755
--- a/modules/addons4.js
+++ b/modules/addons4.js
@@ -283,7 +283,7 @@ ScriptInstall.prototype.install = function() {
       'onDownloadStarted', this._listeners, this);
   this.state = AddonManager.STATE_DOWNLOADING;
 
-  var rs = new RemoteScript(this._script._downloadURL);
+  var rs = new RemoteScript(this._script.downloadURL);
   rs.messageName = 'script.updated';
   rs.onProgress(this._progressCallback);
   rs.download(GM_util.hitch(this, function(aSuccess, aType) {
@@ -310,7 +310,6 @@ ScriptInstall.prototype.install = function() {
       // Note: This call also takes care of replacing the cached ScriptAddon
       // object with a new one for the updated script.
       rs.install(this._script);
-      rs.script._changed('modified');
 
       this.addon = ScriptAddonFactoryByScript(rs.script);
       AddonManagerPrivate.callInstallListeners(
diff --git a/content/miscapis.js b/modules/miscapis.js
similarity index 50%
rename from content/miscapis.js
rename to modules/miscapis.js
index aa709d9..4980276 100644
--- a/content/miscapis.js
+++ b/modules/miscapis.js
@@ -1,6 +1,19 @@
-Components.utils.import('resource://greasemonkey/prefmanager.js');
+var Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+Cu.import('resource://greasemonkey/prefmanager.js');
+Cu.import("resource://greasemonkey/util.js");
+
+
+var EXPORTED_SYMBOLS = [
+    'GM_addStyle', 'GM_console', 'GM_Resources',
+    'GM_ScriptLogger', 'GM_ScriptStorage', 'GM_ScriptStoragePrefs'];
+
 
 function GM_ScriptStorage(script) {
+  this._db = null;
+  this._script = script;
   this.prefMan = new GM_PrefManager(script.prefroot);
   this.stringBundle = Components
     .classes["@mozilla.org/intl/stringbundle;1"]
@@ -8,6 +21,25 @@ function GM_ScriptStorage(script) {
     .createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
 }
 
+
+GM_ScriptStorage.prototype.__defineGetter__('db',
+function GM_ScriptStorage_getDb() {
+  if (null == this._db) {
+    var file = this._script.baseDirFile;
+    file.append('values.db');
+    this._db = Services.storage.openDatabase(file);
+
+    this._db.executeSimpleSQL(
+        'CREATE TABLE IF NOT EXISTS scriptvals ('
+        + 'name TEXT PRIMARY KEY NOT NULL, '
+        + 'value TEXT '
+        + ')'
+        );
+  }
+  return this._db;
+});
+
+
 GM_ScriptStorage.prototype.setValue = function(name, val) {
   if (2 !== arguments.length) {
     throw new Error(this.stringBundle.GetStringFromName('error.args.setValue'));
@@ -17,30 +49,139 @@ GM_ScriptStorage.prototype.setValue = function(name, val) {
     return;
   }
 
-  this.prefMan.setValue(name, val);
+  var stmt = this.db.createStatement(
+      'INSERT OR REPLACE INTO scriptvals (name, value) VALUES (:name, :value)');
+  try {
+    stmt.params.name = name;
+    stmt.params.value = JSON.stringify(val);
+    stmt.execute();
+  } finally {
+    stmt.reset();
+  }
+
+  this._script.changed('val-set', name);
 };
 
+
 GM_ScriptStorage.prototype.getValue = function(name, defVal) {
   if (!GM_util.apiLeakCheck("GM_getValue")) {
     return undefined;
   }
 
-  return this.prefMan.getValue(name, defVal);
+  var value = null;
+  var stmt = this.db.createStatement(
+      'SELECT value FROM scriptvals WHERE name = :name');
+  try {
+    stmt.params.name = name;
+    while (stmt.step()) {
+      value = stmt.row.value;
+    }
+  } catch (e) {
+    dump('getValue err: ' + uneval(e) + '\n');
+  } finally {
+    stmt.reset();
+  }
+
+  if (value == null) return defVal;
+  try {
+    return JSON.parse(value);
+  } catch (e) {
+    dump('JSON parse error? ' + uneval(e) + '\n');
+    return defVal;
+  }
 };
 
+
 GM_ScriptStorage.prototype.deleteValue = function(name) {
   if (!GM_util.apiLeakCheck("GM_deleteValue")) {
     return undefined;
   }
 
-  return this.prefMan.remove(name);
+  var stmt = this.db.createStatement(
+      'DELETE FROM scriptvals WHERE name = :name');
+  try {
+    stmt.params.name = name;
+    stmt.execute();
+  } finally {
+    stmt.reset();
+  }
+
+  this._script.changed('val-del', name);
 };
 
+
 GM_ScriptStorage.prototype.listValues = function() {
   if (!GM_util.apiLeakCheck("GM_listValues")) {
     return undefined;
   }
 
+  var valueNames = [];
+
+  var stmt = this.db.createStatement('SELECT name FROM scriptvals');
+  try {
+    while (stmt.executeStep()) {
+      valueNames.push(stmt.row.name);
+    }
+  } finally {
+    stmt.reset();
+  }
+
+  // See #1637.
+  var vals = Array.prototype.slice.call(valueNames);
+  vals.__exposedProps__ = {'length': 'r'};
+  return vals;
+};
+
+
+// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ //
+
+
+// TODO: Remove this when we're confident enough users have updated from
+// prefs-base to Storage based script values.
+function GM_ScriptStoragePrefs(script) {
+  this._script = script;
+  this.prefMan = new GM_PrefManager(script.prefroot);
+  this.stringBundle = Components
+    .classes["@mozilla.org/intl/stringbundle;1"]
+    .getService(Components.interfaces.nsIStringBundleService)
+    .createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
+}
+
+GM_ScriptStoragePrefs.prototype.setValue = function(name, val) {
+  if (2 !== arguments.length) {
+    throw new Error(this.stringBundle.GetStringFromName('error.args.setValue'));
+  }
+
+  if (!GM_util.apiLeakCheck("GM_setValue")) {
+    return;
+  }
+
+  this.prefMan.setValue(name, val);
+  this._script.changed('val-set', name);
+};
+
+GM_ScriptStoragePrefs.prototype.getValue = function(name, defVal) {
+  if (!GM_util.apiLeakCheck("GM_getValue")) {
+    return undefined;
+  }
+
+  return this.prefMan.getValue(name, defVal);
+};
+
+GM_ScriptStoragePrefs.prototype.deleteValue = function(name) {
+  if (!GM_util.apiLeakCheck("GM_deleteValue")) {
+    return undefined;
+  }
+
+  return this.prefMan.remove(name);
+  this._script.changed('val-del', name);
+};
+
+GM_ScriptStoragePrefs.prototype.listValues = function() {
+  if (!GM_util.apiLeakCheck("GM_listValues")) {
+    return undefined;
+  }
+
   // See #1637.
   var vals = Array.prototype.slice.call(this.prefMan.listValues());
   vals.__exposedProps__ = {'length': 'r'};
@@ -51,6 +192,10 @@ GM_ScriptStorage.prototype.listValues = function() {
 
 function GM_Resources(script){
   this.script = script;
+  this.stringBundle = Components
+    .classes["@mozilla.org/intl/stringbundle;1"]
+    .getService(Components.interfaces.nsIStringBundleService)
+    .createBundle("chrome://greasemonkey/locale/greasemonkey.properties");
 }
 
 GM_Resources.prototype.getResourceURL = function(aScript, name) {
diff --git a/modules/parseScript.js b/modules/parseScript.js
index a2211e6..9337b50 100644
--- a/modules/parseScript.js
+++ b/modules/parseScript.js
@@ -33,7 +33,7 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
 
   var script = new Script();
 
-  if (aUri) script._downloadURL = aUri.spec;
+  if (aUri) script.downloadURL = aUri.spec;
   if (aUri && aUri.spec) {
     var name = aUri.spec;
     name = name.substring(0, name.indexOf(".user.js"));
@@ -70,8 +70,8 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
     case 'downloadURL':
     case 'updateURL':
       try {
-        var uri = GM_util.uriFromUrl(value, aUri || this._downloadURL);
-        script['_' + header] = uri.spec;
+        var uri = GM_util.uriFromUrl(value, aUri);
+        script[header] = uri.spec;
       } catch (e) {
         dump('Failed to parse ' + header + ' "' + value + '":\n' + e + '\n');
       }
@@ -164,8 +164,8 @@ function parse(aSource, aUri, aFailWhenMissing, aNoMetaOk) {
 }
 
 function setDefaults(script) {
-  if (!script.updateURL && script._downloadURL) {
-    script.updateURL = script._downloadURL;
+  if (!script.updateURL && script.downloadURL) {
+    script.updateURL = script.downloadURL;
   }
   if ('document-start' != script._runAt && 'document-end' != script._runAt) {
     script._runAt = 'document-end';
diff --git a/modules/remoteScript.js b/modules/remoteScript.js
index 8dc8eff..706cf4a 100644
--- a/modules/remoteScript.js
+++ b/modules/remoteScript.js
@@ -227,6 +227,7 @@ function RemoteScript(aUrl) {
   this._progressIndex = 0;
   this._scriptFile = null;
   this._scriptMetaCallbacks = [];
+  this._silent = false;
   this._tempDir = GM_util.getTempDir();
   this._uri = GM_util.uriFromUrl(aUrl);
   this._url = aUrl;
@@ -307,7 +308,7 @@ RemoteScript.prototype.install = function(aOldScript, aOnlyDependencies) {
     while (enumerator.hasMoreElements()) {
       var file = enumerator.getNext().QueryInterface(Ci.nsIFile);
       // TODO: Fix invalid private access.
-      file.moveTo(this.script._basedirFile, null);
+      file.moveTo(this.script.baseDirFile, null);
     }
   } else {
     // Completely install the new script.
@@ -341,10 +342,12 @@ RemoteScript.prototype.install = function(aOldScript, aOnlyDependencies) {
     this.script._changed('modified', this.script.id);
 
     // Let the user know we're all done.
-    GM_notification(
-        "'" + this.script.name + "' "
-            + stringBundleBrowser.GetStringFromName(this.messageName),
-        this.messageName);
+    if (!this._silent) {
+      GM_notification(
+          "'" + this.script.name + "' "
+              + stringBundleBrowser.GetStringFromName(this.messageName),
+          this.messageName);
+    }
   }
 };
 
@@ -402,6 +405,10 @@ RemoteScript.prototype.setScript = function(aScript, aTempFile) {
   this._postParseScript();
 };
 
+RemoteScript.prototype.setSilent = function(aVal) {
+  this._silent = !!aVal;
+};
+
 RemoteScript.prototype.showSource = function(aTabBrowser) {
   // Turn standard browser into tab browser, if necessary.
   if (aTabBrowser.getTabBrowser) aTabBrowser = aTabBrowser.getTabBrowser();
diff --git a/modules/script.js b/modules/script.js
index 22a13be..e27bf60 100644
--- a/modules/script.js
+++ b/modules/script.js
@@ -24,6 +24,13 @@ AddonManager.getAddonByID(GM_GUID, function(addon) {
   gGreasemonkeyVersion = '' + addon.version;
 });
 
+
+function usoFix(aUrl) {
+  return aUrl && aUrl.replace(
+      'http://userscripts.org/', 'https://userscripts.org/');
+}
+
+
 function Script(configNode) {
   this._observers = [];
 
@@ -96,8 +103,11 @@ Script.prototype.matchesURL = function(url) {
 };
 
 Script.prototype._changed = function(event, data) {
-  GM_util.getService().config._changed(this, event, data);
+  var dontSave = ('val-set' == event || 'val-del' == event);
+  GM_util.getService().config._changed(this, event, data, dontSave);
 };
+// TODO: Move this method to be public rather than just aliasing it.
+Script.prototype.changed = Script.prototype._changed;
 
 Script.prototype.__defineGetter__('installDate',
 function Script_getInstallDate() { return new Date(this._installTime); });
@@ -134,7 +144,9 @@ Script.prototype.__defineGetter__('description',
 function Script_getDescription() { return this._description; });
 
 Script.prototype.__defineGetter__('downloadURL',
-    function Script_getDescription() { return '' + this._downloadURL; });
+function Script_getDownloadUrl() { return this._downloadURL; });
+Script.prototype.__defineSetter__('downloadURL',
+function Script_setDownloadUrl(aVal) { this._downloadURL = usoFix(aVal); });
 
 Script.prototype.__defineGetter__('uuid',
 function Script_getUuid() { return this._uuid; });
@@ -196,29 +208,24 @@ function Script_getFilename() { return this._filename; });
 
 Script.prototype.__defineGetter__('file',
 function Script_getFile() {
-  var file = this._basedirFile;
+  var file = this.baseDirFile;
   file.append(this._filename);
   return file;
 });
 
 Script.prototype.__defineGetter__('updateURL',
-function Script_getUpdateURL() {
-  return this._updateURL || this._downloadURL;
-});
+function Script_getUpdateURL() { return this._updateURL || this.downloadURL; });
 Script.prototype.__defineSetter__('updateURL',
-function Script_setUpdateURL(url) {
-   this._updateURL = url;
-});
+function Script_setUpdateURL(url) { this._updateURL = usoFix(url); });
 
 Script.prototype.__defineGetter__('updateIsSecure',
 function Script_getUpdateIsSecure() {
-  if (!this._downloadURL) return null;
-
-  return /^https/.test(this._downloadURL);
+  if (!this.downloadURL) return null;
+  return /^https/.test(this.downloadURL);
 });
 
-Script.prototype.__defineGetter__('_basedirFile',
-function Script_getBasedirFile() {
+Script.prototype.__defineGetter__('baseDirFile',
+function Script_getBaseDirFile() {
   var file = GM_util.scriptDir();
   file.append(this._basedir);
   try {
@@ -243,7 +250,7 @@ Script.prototype.setFilename = function(aBaseName, aFileName) {
   // If this script was created from the "new script" dialog, pretend it
   // has been installed from its final location, so that relative dependency
   // paths can be resolved correctly.
-  if (!this._downloadURL) this._downloadURL = this.fileURL;
+  if (!this.downloadURL) this.downloadURL = this.fileURL;
 };
 
 Script.prototype.fixTimestampsOnInstall = function() {
@@ -254,10 +261,10 @@ Script.prototype.fixTimestampsOnInstall = function() {
 Script.prototype._loadFromConfigNode = function(node) {
   this._filename = node.getAttribute("filename");
   this._basedir = node.getAttribute("basedir") || ".";
-  this._downloadURL = node.getAttribute("installurl") || null;
+  this.downloadURL = node.getAttribute("installurl") || null;
   this.updateURL = node.getAttribute("updateurl") || null;
 
-  if (!this.fileExists(this._basedirFile)) return;
+  if (!this.fileExists(this.baseDirFile)) return;
   if (!this.fileExists(this.file)) return;
 
   if (!node.hasAttribute("modified")
@@ -267,7 +274,7 @@ Script.prototype._loadFromConfigNode = function(node) {
     var scope = {};
     Components.utils.import('resource://greasemonkey/parseScript.js', scope);
     var parsedScript = scope.parse(
-        this.textContent, GM_util.uriFromUrl(this._downloadURL));
+        this.textContent, GM_util.uriFromUrl(this.downloadURL));
 
     this._modifiedTime = this.file.lastModifiedTime;
     this._dependhash = GM_util.sha1(parsedScript._rawMeta);
@@ -413,8 +420,8 @@ Script.prototype.toConfigNode = function(doc) {
   scriptNode.setAttribute("uuid", this._uuid);
   scriptNode.setAttribute("version", this._version);
 
-  if (this._downloadURL) {
-    scriptNode.setAttribute("installurl", this._downloadURL);
+  if (this.downloadURL) {
+    scriptNode.setAttribute("installurl", this.downloadURL);
   }
   if (this.updateURL) {
     scriptNode.setAttribute("updateurl", this.updateURL);
@@ -491,7 +498,7 @@ Script.prototype.isRemoteUpdateAllowed = function(aForced) {
 
   var ioService = Components.classes["@mozilla.org/network/io-service;1"]
       .getService(Components.interfaces.nsIIOService);
-  var scheme = ioService.extractScheme(this._downloadURL);
+  var scheme = ioService.extractScheme(this.downloadURL);
   switch (scheme) {
   case 'about':
   case 'chrome':
@@ -563,7 +570,7 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin) {
   this._description = newScript._description;
   this._runAt = newScript._runAt;
   this._version = newScript._version;
-  this._downloadURL = newScript._downloadURL;
+  this.downloadURL = newScript.downloadURL;
   this.updateURL = newScript.updateURL;
 
   this.showGrantWarning();
@@ -587,7 +594,7 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin) {
     // Re-download dependencies.
     var scope = {};
     Components.utils.import('resource://greasemonkey/remoteScript.js', scope);
-    var rs = new scope.RemoteScript(this._downloadURL);
+    var rs = new scope.RemoteScript(this.downloadURL);
     newScript._basedir = this._basedir;
     rs.setScript(newScript);
     rs.download(GM_util.hitch(this, function(aSuccess) {
@@ -602,7 +609,7 @@ Script.prototype.updateFromNewScript = function(newScript, safeWin) {
       // Get rid of old dependencies' files.
       for (var i = 0, dep = null; dep = this.dependencies[i]; i++) {
         try {
-          if (dep.file.equals(this._basedirFile)) {
+          if (dep.file.equals(this.baseDirFile)) {
             // Bugs like an empty file name can cause "dep.file" to point to
             // the containing directory.  Don't remove that!
             GM_util.logError(
@@ -744,7 +751,7 @@ Script.prototype.checkRemoteVersion = function(req, aCallback, aForced) {
   var source = req.responseText;
   var scope = {};
   Components.utils.import('resource://greasemonkey/parseScript.js', scope);
-  var newScript = scope.parse(source, this._downloadURL);
+  var newScript = scope.parse(source, this.downloadURL);
   var remoteVersion = newScript.version;
   if (!remoteVersion) return aCallback(false);
 
@@ -762,8 +769,8 @@ Script.prototype.checkRemoteVersion = function(req, aCallback, aForced) {
 
 Script.prototype.allFiles = function() {
   var files = [];
-  if (!this._basedirFile.equals(GM_util.scriptDir())) {
-    files.push(this._basedirFile);
+  if (!this.baseDirFile.equals(GM_util.scriptDir())) {
+    files.push(this.baseDirFile);
   }
   files.push(this.file);
   for (var i = 0, r = null; r = this._requires[i]; i++) {
@@ -790,7 +797,7 @@ Script.prototype.allFilesExist = function() {
 Script.prototype.uninstall = function(forUpdate) {
   if ('undefined' == typeof(forUpdate)) forUpdate = false;
 
-  if (this._basedirFile.equals(GM_util.scriptDir())) {
+  if (this.baseDirFile.equals(GM_util.scriptDir())) {
     // if script is in the root, just remove the file
     try {
       this.file.remove(false);
@@ -800,7 +807,7 @@ Script.prototype.uninstall = function(forUpdate) {
   } else {
     // if script has its own dir, remove the dir + contents
     try {
-      this._basedirFile.remove(true);
+      this.baseDirFile.remove(true);
     } catch (e) {
       // Fail silently if it already does not exist.
     }
diff --git a/modules/scriptDependency.js b/modules/scriptDependency.js
index f7ead8b..ae75694 100644
--- a/modules/scriptDependency.js
+++ b/modules/scriptDependency.js
@@ -42,7 +42,7 @@ function ScriptDependency_getDownloadURL() {
 
 ScriptDependency.prototype.__defineGetter__('file',
 function ScriptDependency_getFile() {
-  var file = this._script._basedirFile;
+  var file = this._script.baseDirFile;
   file.append(this._filename);
   return file;
 });
diff --git a/modules/sync.js b/modules/sync.js
new file mode 100644
index 0000000..d8a3889
--- /dev/null
+++ b/modules/sync.js
@@ -0,0 +1,251 @@
+var EXPORTED_SYMBOLS = [];
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+
+
+Cu.import('resource://gre/modules/Services.jsm');
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+Cu.import('resource://services-crypto/utils.js');
+Cu.import("resource://greasemonkey/miscapis.js");
+Cu.import('resource://greasemonkey/prefmanager.js');
+Cu.import('resource://greasemonkey/util.js');
+
+
+var gSyncInitialized = false;
+
+var gWeave = {};
+Cu.import('resource://services-sync/engines.js', gWeave);
+Cu.import('resource://services-sync/record.js', gWeave);
+Cu.import('resource://services-sync/service.js', gWeave);
+Cu.import('resource://services-sync/status.js', gWeave);
+Cu.import('resource://services-sync/util.js', gWeave);
+
+
+var SyncServiceObserver = {
+  init: function() {
+    if (gWeave.Status.ready) {
+      this.initEngine();
+    } else {
+      Services.obs.addObserver(this, 'weave:service:ready', true);
+    }
+  },
+
+  initEngine: function() {
+    if (gSyncInitialized) return;
+    gSyncInitialized = true;
+
+    // This must be delayed until after the Greasemonkey service is set up.
+    Cu.import('resource://greasemonkey/remoteScript.js');
+
+    gWeave.Service.engineManager.register(ScriptEngine);
+  },
+
+  observe: function(aSubject, aTopic, aData) {
+    switch (aTopic) {
+    case 'weave:service:ready':
+      this.initEngine();
+      break;
+    }
+  },
+
+  QueryInterface: XPCOMUtils.generateQI(
+      [Ci.nsIObserver, Ci.nsISupportsWeakReference]),
+};
+
+
+function ScriptRecord(aCollection, aId) {
+  gWeave.CryptoWrapper.call(this, aCollection, aId);
+}
+ScriptRecord.prototype = {
+  __proto__: gWeave.CryptoWrapper.prototype,
+  _logName: 'Record.GreasemonkeyScript',
+};
+gWeave.Utils.deferGetSet(
+    ScriptRecord, 'cleartext',
+    ['downloadURL', 'enabled', 'installed', 'values', 'valuesTooBig']);
+
+
+function ScriptStore(aName, aEngine) {
+  gWeave.Store.call(this, aName, aEngine);
+}
+ScriptStore.prototype = {
+  __proto__: gWeave.Store.prototype,
+
+  changeItemID: function(aOldId, aNewId) {
+    dump('>>> ScriptStore.changeItemID() ... '
+        + aOldId.substr(0, 8) + ' ' + aNewId.substr(0, 8) + '\n');
+  },
+
+  /// Incoming Sync record, create local version.
+  create: function(aRecord) {
+    if (aRecord.cleartext.installed) {
+      var rs = new RemoteScript(aRecord.cleartext.downloadURL);
+      rs.setSilent();
+      rs.download(GM_util.hitch(this, function(aSuccess, aType) {
+        if (aSuccess && 'dependencies' == aType) {
+          rs.install();
+          rs.script.enabled = aRecord.enabled;
+
+          setScriptValuesFromSyncRecord(rs.script, aRecord);
+        }
+      }));
+    } else {
+      var script = scriptForSyncId(aRecord.cleartext.id);
+      if (!script) return;
+      script.uninstall();
+    }
+  },
+
+  /// New local item, create sync record.
+  createRecord: function(aId, aCollection) {
+    var script = scriptForSyncId(aId);
+    if (script) {
+      var record = new ScriptRecord();
+      record.cleartext.id = aId;
+      record.cleartext.downloadURL = script.downloadURL;
+      record.cleartext.enabled = script.enabled;
+      record.cleartext.installed = !script.needsUninstall;
+
+      if (GM_prefRoot.getValue('sync.values')) {
+        var storage = new GM_ScriptStorage(script);
+        var totalSize = 0;
+        var maxSize = GM_prefRoot.getValue('sync.values_max_size_per_script');
+        record.cleartext.values = {};
+        record.cleartext.valuesTooBig = false;
+        var names = storage.listValues();
+        for (var i = 0, name = null; name = names[i]; i++) {
+          var val = storage.getValue(name);
+          record.cleartext.values[name] = val;
+          totalSize += name.length;
+          totalSize += val.length || 4;  // 4 for number / bool (no length).
+
+          if (totalSize > maxSize) {
+            record.cleartext.values = [];
+            record.cleartext.valuesTooBig = true;
+            break;
+          }
+        }
+      }
+
+      return record;
+    } else {
+      // Assume this is an uninstalled script.
+      var record = new ScriptRecord();
+      record.cleartext.enabled = false;
+      record.cleartext.installed = false;
+      return record;
+    }
+  },
+
+  getAllIDs: function() {
+    var syncIds = {};
+    var scripts = GM_util.getService().config.scripts;
+    for (var i = 0, script = null; script = scripts[i]; i++) {
+      if (!script.downloadURL) continue;
+      if (script.downloadURL.match(/^file:/)) continue;
+      syncIds[syncId(script)] = 1;
+    }
+    return syncIds;
+  },
+
+  itemExists: function(aId) {
+    var script = scriptForSyncId(aId);
+    return !!script;
+  },
+
+  remove: function(aRecord) {
+    var script = scriptForSyncId(aRecord.cleartext.id);
+    if (script) script.uninstall();
+  },
+
+  update: function(aRecord) {
+    var script = scriptForSyncId(aRecord.cleartext.id);
+    if (!script) {
+      dump('Could not find script for record ' + aRecord.cleartext + '\n');
+      return;
+    }
+    if (!aRecord.cleartext.installed) {
+      script.uninstall();
+    } else {
+      script.enabled = aRecord.cleartext.enabled;
+      setScriptValuesFromSyncRecord(script, aRecord);
+    }
+  },
+
+  wipe: function() {
+    dump('>>> ScriptStore.wipe() ...\n');
+    // Delete everything!
+  },
+};
+
+
+function ScriptTracker(aName, aEngine) {
+  gWeave.Tracker.call(this, aName, aEngine);
+  GM_util.getService().config.addObserver(this);
+}
+ScriptTracker.prototype = {
+  __proto__: gWeave.Tracker.prototype,
+
+  notifyEvent: function(aScript, aEvent, aData) {
+    if (aEvent in {'install': 1, 'modified': 1, 'edit-enabled': 1}) {
+      if (this.addChangedID(syncId(aScript))) {
+        this.score = Math.min(100, this.score + 5);
+      }
+    } else if (aEvent in {'val-set': 1, 'val-del': 1}) {
+      if (this.addChangedID(syncId(aScript))) {
+        this.score = Math.min(100, this.score + 1);
+      }
+    }
+  }
+};
+
+
+function ScriptEngine() {
+  gWeave.SyncEngine.call(this, 'Greasemonkey', gWeave.Service);
+
+  this.enabled = GM_prefRoot.getValue('sync.enabled');
+  GM_prefRoot.watch('sync.enabled', GM_util.hitch(this, function() {
+    this.enabled = GM_prefRoot.getValue('sync.enabled');
+  }));
+}
+ScriptEngine.prototype = {
+  __proto__: gWeave.SyncEngine.prototype,
+  _recordObj: ScriptRecord,
+  _storeObj: ScriptStore,
+  _trackerObj: ScriptTracker,
+};
+
+
+function scriptForSyncId(aSyncId) {
+  var scripts = GM_util.getService().config.scripts;
+  for (var i = 0, script = null; script = scripts[i]; i++) {
+    if (syncId(script) == aSyncId) {
+      return script;
+    }
+  }
+}
+
+
+// The sync ID for a given script.
+function syncId(aScript) {
+  // TODO: Salting?  e.g. btoa(CryptoUtils.generateRandomBytes(16));
+  return GM_util.sha1(aScript.id);
+}
+
+
+function setScriptValuesFromSyncRecord(aScript, aRecord) {
+  if (GM_prefRoot.getValue('sync.values')
+      && !aRecord.cleartext.valuesTooBig
+  ) {
+    // TODO: Clear any locally set values not in the sync record?
+    var storage = new GM_ScriptStorage(aScript);
+    for (name in aRecord.cleartext.values) {
+      storage.setValue(name, aRecord.cleartext.values[name]);
+    }
+  }
+}
+
+
+SyncServiceObserver.init()
diff --git a/modules/util/apiLeakCheck.js b/modules/util/apiLeakCheck.js
index c852c40..c76a416 100644
--- a/modules/util/apiLeakCheck.js
+++ b/modules/util/apiLeakCheck.js
@@ -27,13 +27,16 @@ function apiLeakCheck(apiName) {
     //  * Greasemonkey scripts.
     //  * Greasemonkey extension by path.
     //  * Greasemonkey modules.
-    //  * All of chrome.  (In the script update case, chrome will list values.)
+    //  * All of chrome.  (In the script update case, chrome will list values.
+    //        Including Sync modules.)
     // Anything else on the stack and we will reject the API, to make sure that
     // the content window (whose path would be e.g. http://...) has no access.
     if (2 == stack.language
         && stack.filename !== gComponentPath
         && stack.filename.substr(0, gScriptDirPath.length) !== gScriptDirPath
         && stack.filename.substr(0, 24) !== 'resource://greasemonkey/'
+        && stack.filename.substr(0, 25) !== 'resource://services-sync/'
+        && stack.filename.substr(0, 15) !== 'resource://gre/'
         && stack.filename.substr(0, 9) !== 'chrome://'
         ) {
       GM_util.logError(new Error(

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/greasemonkey.git



More information about the Pkg-mozext-commits mailing list