From 4d3e46e178dbee32be406e98904172e60aef4aaf Mon Sep 17 00:00:00 2001 From: supahgreg Date: Sat, 22 Sep 2012 22:10:06 -0500 Subject: [PATCH] Implementing GM_watchValue and GM_unwatchValue --- extension/locale/de/scriptish.properties | 2 + extension/locale/en-US/scriptish.properties | 2 + extension/locale/es-ES/scriptish.properties | 2 + extension/locale/he/scriptish.properties | 2 + extension/locale/hu/scriptish.properties | 2 + extension/locale/ja-JP/scriptish.properties | 2 + extension/locale/pl/scriptish.properties | 2 + extension/locale/pt-BR/scriptish.properties | 2 + extension/locale/ru-RU/scriptish.properties | 2 + extension/locale/sv-SE/scriptish.properties | 2 + extension/locale/zh-CN/scriptish.properties | 2 + extension/locale/zh-TW/scriptish.properties | 2 + extension/modules/api.js | 16 ++- extension/modules/api/GM_ScriptStorage.js | 104 +++++++++++++++++++- 14 files changed, 138 insertions(+), 6 deletions(-) diff --git a/extension/locale/de/scriptish.properties b/extension/locale/de/scriptish.properties index b7e48c5a..e3a0bd2f 100644 --- a/extension/locale/de/scriptish.properties +++ b/extension/locale/de/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Bitte erst den bevorzugten Texteditor wählen editor.useScratchpad= editor.useScratchpad.no= editor.useScratchpad.yes= +error.api.badArguments= error.api.clipboard.type=ist kein von GM_setClipboard unterstützter Typ. error.api.noResourceWithName=Keine Resource mit dem Namen error.api.noSecondArgValue=Zweites Argument nicht spezifiziert: Value +error.api.prefNotFound= error.api.reqURL=Ungültige URL error.api.reqURL.scheme=Verbotenes Schema (Protokoll) in URL error.api.safeHTMLParser.url= diff --git a/extension/locale/en-US/scriptish.properties b/extension/locale/en-US/scriptish.properties index 758b2b38..cc823400 100644 --- a/extension/locale/en-US/scriptish.properties +++ b/extension/locale/en-US/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Please choose your preferred text editor first editor.useScratchpad=Do you want to use Scratchpad as your editor? editor.useScratchpad.no=No (I will pick my own) editor.useScratchpad.yes=Yes +error.api.badArguments=Invalid or insufficient arguments were passed to a GM_ function. error.api.clipboard.type=is not a type that is supported by GM_setClipboard. error.api.noResourceWithName=No resource with name error.api.noSecondArgValue=Second argument not specified: Value +error.api.prefNotFound=An invalid or non-existent preference name was passed to a GM_ function. error.api.reqURL=Invalid URL error.api.reqURL.scheme=Disallowed scheme in URL error.api.safeHTMLParser.url=The "URL" argument of GM_safeHTMLParser could not be parsed diff --git a/extension/locale/es-ES/scriptish.properties b/extension/locale/es-ES/scriptish.properties index b768bb31..a668aba9 100644 --- a/extension/locale/es-ES/scriptish.properties +++ b/extension/locale/es-ES/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Por favor, elija antes su editor de texto favorito editor.useScratchpad=¿Desea usar Scratchpad como su editor? editor.useScratchpad.no=No (yo seleccionaré el mío) editor.useScratchpad.yes=Sí +error.api.badArguments= error.api.clipboard.type=no es un tipo soportado por GM_setClipboard. error.api.noResourceWithName=No hay recursos con ese nombre error.api.noSecondArgValue=Segundo argumento no especificado: Valor +error.api.prefNotFound= error.api.reqURL=URL no válido error.api.reqURL.scheme=Esquema no permitido en URL error.api.safeHTMLParser.url= diff --git a/extension/locale/he/scriptish.properties b/extension/locale/he/scriptish.properties index be93bfc5..86401bc3 100644 --- a/extension/locale/he/scriptish.properties +++ b/extension/locale/he/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=אנא בחר תחילה את עורך הטקסט המועדף ע editor.useScratchpad=האם ברצונך להשתמש ב־Scratchpad כעורך הטקסט שלך? editor.useScratchpad.no=לא (אני אבחר בעצמי) editor.useScratchpad.yes=כן +error.api.badArguments= error.api.clipboard.type=אינו מסוג שנתמך ע"י GM_setClipboard. error.api.noResourceWithName=לא קיים משאב בעל שם error.api.noSecondArgValue=לא צוין ערך שני: ערך +error.api.prefNotFound= error.api.reqURL=כתובת URL לא חוקית error.api.reqURL.scheme=ערכה לא מורשת בכתובת URL error.api.safeHTMLParser.url= diff --git a/extension/locale/hu/scriptish.properties b/extension/locale/hu/scriptish.properties index bdf6a48e..feb93a22 100644 --- a/extension/locale/hu/scriptish.properties +++ b/extension/locale/hu/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Kérem először válassza ki az Ön által preferált szerkesztő editor.useScratchpad=A Scratchpad-et szeretné használni szerkesztőként? editor.useScratchpad.no=Nem (kiválasztok egy sajátot) editor.useScratchpad.yes=Igen +error.api.badArguments= error.api.clipboard.type=a GM_setClipboard által nem támogatott típus. error.api.noResourceWithName=Nincs erőforrás ezen a néven: error.api.noSecondArgValue=Második argumentum nincs meghatározva: Érték +error.api.prefNotFound= error.api.reqURL=Érvénytelen URL error.api.reqURL.scheme=Az URL formátuma érvénytelen error.api.safeHTMLParser.url= diff --git a/extension/locale/ja-JP/scriptish.properties b/extension/locale/ja-JP/scriptish.properties index 1712093d..eca6ffe7 100644 --- a/extension/locale/ja-JP/scriptish.properties +++ b/extension/locale/ja-JP/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=エディタを選択してください editor.useScratchpad=エディタとしてスクラッチパッドを使用しますか? editor.useScratchpad.no=No(自分でエディタを指定) editor.useScratchpad.yes=Yes +error.api.badArguments= error.api.clipboard.type=は GM_setClipboard がサポートしていない型(type)です error.api.noResourceWithName=名前付きリソースが見つかりません error.api.noSecondArgValue=2番目の引数が指定されていません:Value +error.api.prefNotFound= error.api.reqURL=不正な URL です error.api.reqURL.scheme=許可されていないスキーム(scheme)を URL で指定しています error.api.safeHTMLParser.url=GM_safeHTMLParser の引数 "URL" をパース(parse)できません diff --git a/extension/locale/pl/scriptish.properties b/extension/locale/pl/scriptish.properties index 66c29c3c..197cf2ff 100644 --- a/extension/locale/pl/scriptish.properties +++ b/extension/locale/pl/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Najpierw proszę wybrać swój preferowany edytor tekstu editor.useScratchpad=Czy chcesz użyć Scratchpad-a jako edytor? editor.useScratchpad.no=Nie ( sam wybiorę ) editor.useScratchpad.yes=Tak +error.api.badArguments= error.api.clipboard.type=nie jest to typ wspierany przez GM_setClipboard. error.api.noResourceWithName=Brak źródeł z nazwą error.api.noSecondArgValue=Drugi argument nie został określony: Wartość +error.api.prefNotFound= error.api.reqURL=Błędny URL error.api.reqURL.scheme=Niedozwolony schemat URL error.api.safeHTMLParser.url= diff --git a/extension/locale/pt-BR/scriptish.properties b/extension/locale/pt-BR/scriptish.properties index e9ecb6fc..0e5a60d2 100644 --- a/extension/locale/pt-BR/scriptish.properties +++ b/extension/locale/pt-BR/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Escolha seu editor de texto preferido editor.useScratchpad=Você gostaria de usar o Scratchpad como seu editor? editor.useScratchpad.no=Não (eu vou escolher outro) editor.useScratchpad.yes=Sim +error.api.badArguments= error.api.clipboard.type=não é um tipo suportado por GM_setClipboard. error.api.noResourceWithName=Nenhum recurso com o nome error.api.noSecondArgValue=Segundo argumento não especificado: Valor +error.api.prefNotFound= error.api.reqURL=Endereço inválido error.api.reqURL.scheme=Esquema não permitido em URL error.api.safeHTMLParser.url= diff --git a/extension/locale/ru-RU/scriptish.properties b/extension/locale/ru-RU/scriptish.properties index 5f6322d9..ee3eb4bd 100644 --- a/extension/locale/ru-RU/scriptish.properties +++ b/extension/locale/ru-RU/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Пожалуйста, выберите ваш любимый ре editor.useScratchpad=Вы хотите использовать Scratchpad в качестве редактора? editor.useScratchpad.no=Нет (я выберу свой​​) editor.useScratchpad.yes=Да +error.api.badArguments= error.api.clipboard.type=Тип данных не подходит для GM_setClipboard. error.api.noResourceWithName=Нет ресурса с таким именем error.api.noSecondArgValue=Второй аргумент - значение - не задан +error.api.prefNotFound= error.api.reqURL=Неверный URL error.api.reqURL.scheme=Запрещённая схема в URL error.api.safeHTMLParser.url=Не удалось разобрать аргумент «URL» из GM_safeHTMLParser diff --git a/extension/locale/sv-SE/scriptish.properties b/extension/locale/sv-SE/scriptish.properties index b69c02a5..37d4688f 100644 --- a/extension/locale/sv-SE/scriptish.properties +++ b/extension/locale/sv-SE/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=Var vänlig välj först det textredigeringsprogram du föredrar editor.useScratchpad=Vill du använda Scratchpad som din textredigerare? editor.useScratchpad.no=Nej, jag väljer min egen editor.useScratchpad.yes=Ja +error.api.badArguments= error.api.clipboard.type=är inte en typ som stöds av GM_setClipboard. error.api.noResourceWithName=Det finns ingen resurs med namnet error.api.noSecondArgValue=Det andra argumentet har inte angivits: Värde +error.api.prefNotFound= error.api.reqURL=Ogiltig URL error.api.reqURL.scheme=Otillåtet schema i URL error.api.safeHTMLParser.url=Argumentet "URL" för GM_safeHTMLParser kunde inte parsas diff --git a/extension/locale/zh-CN/scriptish.properties b/extension/locale/zh-CN/scriptish.properties index 48c098ed..af5972bc 100644 --- a/extension/locale/zh-CN/scriptish.properties +++ b/extension/locale/zh-CN/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=请选择您喜欢的文本编辑器 editor.useScratchpad=您想使用暂存器作为您的编辑器吗? editor.useScratchpad.no=不(我要选择我自己喜欢的) editor.useScratchpad.yes=是 +error.api.badArguments= error.api.clipboard.type=不是 GM_setClipboard 所支持的类型。 error.api.noResourceWithName=没有该名称的资源 error.api.noSecondArgValue=第二个参数未指定:值 +error.api.prefNotFound= error.api.reqURL=无效的 URL error.api.reqURL.scheme=不允许在 URL 中出现 scheme error.api.safeHTMLParser.url=无法解释 GM_safeHTMLParser 函数的中的 URL参数 diff --git a/extension/locale/zh-TW/scriptish.properties b/extension/locale/zh-TW/scriptish.properties index ce8077a9..8df9d7b6 100644 --- a/extension/locale/zh-TW/scriptish.properties +++ b/extension/locale/zh-TW/scriptish.properties @@ -9,9 +9,11 @@ editor.prompt=請先選擇您常用的文字編輯器 editor.useScratchpad=您想使用程式碼片段速記本作為您的編輯器嗎? editor.useScratchpad.no=不(我要自己選擇) editor.useScratchpad.yes=是 +error.api.badArguments= error.api.clipboard.type=不是 GM_setClipboard 所支援的類型。 error.api.noResourceWithName=沒有該名稱的資源 error.api.noSecondArgValue=第二個參數未指定:值 +error.api.prefNotFound= error.api.reqURL=無效的網址 error.api.reqURL.scheme=網址中有不支援的協定 error.api.safeHTMLParser.url= diff --git a/extension/modules/api.js b/extension/modules/api.js index a793d89e..92e06468 100644 --- a/extension/modules/api.js +++ b/extension/modules/api.js @@ -78,7 +78,7 @@ function GM_API(options) { return new GM_xmlhttpRequester(aUnsafeContentWin, aURL, aScript); }); lazy(lazyLoaders, "storage", function() { - return new GM_ScriptStorage(aScript); + return new GM_ScriptStorage(aScript, aSafeWin); }); lazy(lazyLoaders, "resources", function() { return new GM_Resources(aScript); @@ -152,6 +152,20 @@ function GM_API(options) { if (!GM_apiLeakCheck("GM_deleteValue")) return; return lazyLoaders.storage.deleteValue.apply(lazyLoaders.storage, arguments); }; + this.GM_watchValue = function GM_watchValue(aName, aListener) { + if (!GM_apiLeakCheck("GM_watchValue")) return; + let listener = null; + if ("function" === typeof aListener) { + listener = function(aEvent) { + GM_apiSafeCallback(aSafeWin, aScript, null, aListener, [aEvent]); + }; + } + return lazyLoaders.storage.watchValue.call(lazyLoaders.storage, aName, listener); + } + this.GM_unwatchValue = function GM_unwatchValue() { + if (!GM_apiLeakCheck("GM_unwatchValue")) return; + return lazyLoaders.storage.unwatchValue.apply(lazyLoaders.storage, arguments); + } this.GM_listValues = function GM_listValues() { if (!GM_apiLeakCheck("GM_listValues")) return; return lazyLoaders.storage.listValues.apply(lazyLoaders.storage, arguments); diff --git a/extension/modules/api/GM_ScriptStorage.js b/extension/modules/api/GM_ScriptStorage.js index 4ee668bb..b278c230 100644 --- a/extension/modules/api/GM_ScriptStorage.js +++ b/extension/modules/api/GM_ScriptStorage.js @@ -1,11 +1,26 @@ var EXPORTED_SYMBOLS = ["GM_ScriptStorage"]; -const Cu = Components.utils; -Cu.import("resource://scriptish/prefmanager.js"); -Cu.import("resource://scriptish/utils/Scriptish_stringBundle.js"); +Components.utils.import("resource://scriptish/constants.js"); -function GM_ScriptStorage(script) { - this.prefMan = new Scriptish_PrefManager(script.prefroot); +lazyImport(this, "resource://scriptish/prefmanager.js", ["Scriptish_PrefManager"]); + +lazyUtil(this, "getWindowIDs"); +lazyUtil(this, "stringBundle"); +lazyUtil(this, "windowUnloader"); + +function GM_ScriptStorage(aScript, aSafeWin) { + this.prefMan = new Scriptish_PrefManager(aScript.prefroot); + this._watchedPrefs = Object.create(null); + + // Be sure to remove any watchers when the window unloads + let winID = Scriptish_getWindowIDs(aSafeWin).innerID; + Scriptish_windowUnloader(function() { + let prefChanged = this._prefChanged.bind(this); + for (let name in this._watchedPrefs) { + this.prefMan.unwatch(name, prefChanged); + delete this._watchedPrefs[name]; + } + }.bind(this), winID); } GM_ScriptStorage.prototype.setValue = function(name, val) { @@ -24,6 +39,85 @@ GM_ScriptStorage.prototype.deleteValue = function(name) { return this.prefMan.remove(name); }; +// Notifies any script watchers of a preference change +GM_ScriptStorage.prototype._prefChanged = function(aName) { + if (!(aName in this._watchedPrefs)) { + return; + } + let newValue = this.getValue(aName); + let watchers = this._watchedPrefs[aName].watchers; + for (let i = 0, e = watchers.length; i < e; ++i) { + watchers[i].notify({ + __exposedProps__: { + name: "r", + oldValue: "r", + newValue: "r" + }, + "name": aName, + "oldValue": this._watchedPrefs[aName].currentValue, + "newValue": newValue + }); + } + this._watchedPrefs[aName].currentValue = newValue; +} + +GM_ScriptStorage.prototype.watchValue = function(aName, aListener) { + // Make sure we were passed everything + if (!(aName && aListener && "function" === typeof aListener)) { + throw new Error(Scriptish_stringBundle("error.api.badArguments")); + } + + // Nothing to do if the preference doesn't exist + if (!this.prefMan.exists(aName)) { + throw new Error(Scriptish_stringBundle("error.api.prefNotFound")); + } + + // Generate a UUID for the watcher so it can be unwatched by the user + let uuid = Services.uuid.generateUUID().toString(); + let watcher = {"notify": aListener, "uuid": uuid}; + + // Add to existing watchers, or set up a new pref watcher + if (aName in this._watchedPrefs) { + this._watchedPrefs[aName].watchers.push(watcher); + } + else { + this._watchedPrefs[aName] = { + "currentValue": this.getValue(aName), + "watchers": [watcher] + }; + + // Start watching the pref + this.prefMan.watch(aName, this._prefChanged.bind(this)); + } + + // Return the watcher's UUID so it can be unwatched by the user + return uuid; +}; + +GM_ScriptStorage.prototype.unwatchValue = function(aName, aUUID) { + // Nothing to do if the preference doesn't exist or isn't watched + if (!(aName in this._watchedPrefs && this.prefMan.exists(aName))) { + return false; + } + + let watchers = this._watchedPrefs[aName].watchers; + + // If given a UUID, only remove the specified watcher + if (aUUID) { + for (let i = 0, e = watchers.length; i < e; ++i) { + if (aUUID === watchers[i].uuid) { + watchers.splice(i, 1); + return true; + } + } + return false; + } + + // Otherwise remove all watchers for the preference + watchers.length = 0; + return true; +} + GM_ScriptStorage.prototype.listValues = function() { return this.prefMan.listValues(); };