From 4226a18a6d068eb8ee9bc48ac21c1ed2e42babe9 Mon Sep 17 00:00:00 2001 From: ccd0 Date: Thu, 28 Sep 2017 10:51:08 -0700 Subject: [PATCH] Preliminary support for Greasemonkey 4. --- package.json | 7 +- src/meta/jshint.json | 7 +- src/platform/$.coffee | 259 ++++++++++++++++++-------------- src/platform/CrossOrigin.coffee | 4 +- 4 files changed, 163 insertions(+), 114 deletions(-) diff --git a/package.json b/package.json index a0d89c1c6..e4ee50baf 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,12 @@ "GM_listValues", "GM_addValueChangeListener", "GM_openInTab", - "GM_xmlhttpRequest" + "GM_xmlhttpRequest", + "GM.getValue", + "GM.setValue", + "GM.deleteValue", + "GM.listValues", + "GM.xmlHttpRequest" ], "min": { "chrome": "33", diff --git a/src/meta/jshint.json b/src/meta/jshint.json index 9c2d3e820..45f62a3eb 100644 --- a/src/meta/jshint.json +++ b/src/meta/jshint.json @@ -16,11 +16,14 @@ "globals": { "MediaError": false, "Set": false, + "Promise": false, + "BroadcastChannel": false, "GM_info": false, "cloneInto": false, "unsafeWindow": false, - "chrome": false<%= - meta.grants.map(x => `,\n "${x}": false`).join('') + "chrome": false, + "GM": false<%= + meta.grants.filter(x => !/\./.test(x)).map(x => `,\n "${x}": false`).join('') %><%= read('/tmp/declaration.js').match(/^var (.*);/)[1].split(', ').map(x => `,\n "${x}": true`).join('') %><%= diff --git a/src/platform/$.coffee b/src/platform/$.coffee index 014a70a14..f96ecb439 100644 --- a/src/platform/$.coffee +++ b/src/platform/$.coffee @@ -492,125 +492,166 @@ do -> # http://wiki.greasespot.net/Main_Page # https://tampermonkey.net/documentation.php -# workaround for Firefox 53 issue -$.currentValue = {} -$.GM_getValue = (key) -> - try - $.currentValue[key] = GM_getValue key - catch err - $.currentValue[key] -$.GM_setValue = (key, val) -> - $.currentValue[key] = val - GM_setValue key, val -$.GM_deleteValue = (key) -> - delete $.currentValue[key] - GM_deleteValue key +if GM?.deleteValue? -unless GM_deleteValue? - $.perProtocolSettings = true + $.syncChannel = new BroadcastChannel(g.NAMESPACE + 'sync') -if GM_deleteValue? - $.getValue = $.GM_getValue - $.listValues = -> GM_listValues() # error when called if missing -else if $.hasStorage - $.getValue = (key) -> localStorage[key] - $.listValues = -> - key for key of localStorage when key[...g.NAMESPACE.length] is g.NAMESPACE -else - $.getValue = -> - $.listValues = -> [] + $.on $.syncChannel, 'message', (e) -> + for key, val of e.data when (cb = $.syncing[key]) + cb val, key -if GM_addValueChangeListener? - $.setValue = $.GM_setValue - $.deleteValue = $.GM_deleteValue -else if GM_deleteValue? - $.oldValue = {} - $.setValue = (key, val) -> - $.GM_setValue key, val - if key of $.syncing - $.oldValue[key] = val - localStorage[key] = val if $.hasStorage # for `storage` events - $.deleteValue = (key) -> - $.GM_deleteValue key - if key of $.syncing - delete $.oldValue[key] - localStorage.removeItem key if $.hasStorage # for `storage` events - $.cantSync = true if !$.hasStorage -else if $.hasStorage - $.oldValue = {} - $.setValue = (key, val) -> - $.oldValue[key] = val if key of $.syncing - localStorage[key] = val - $.deleteValue = (key) -> - delete $.oldValue[key] if key of $.syncing - localStorage.removeItem key -else - $.setValue = -> - $.deleteValue = -> - $.cantSync = $.cantSet = true - -if GM_addValueChangeListener? $.sync = (key, cb) -> - $.syncing[key] = GM_addValueChangeListener g.NAMESPACE + key, (key2, oldValue, newValue, remote) -> - if remote - newValue = JSON.parse newValue unless newValue is undefined - cb newValue, key - $.forceSync = -> -else if GM_deleteValue? or $.hasStorage - $.sync = (key, cb) -> - key = g.NAMESPACE + key $.syncing[key] = cb - $.oldValue[key] = $.getValue key - do -> - onChange = ({key, newValue}) -> - return if not (cb = $.syncing[key]) - if newValue? - return if newValue is $.oldValue[key] - $.oldValue[key] = newValue - cb JSON.parse(newValue), key[g.NAMESPACE.length..] - else - return unless $.oldValue[key]? - delete $.oldValue[key] - cb undefined, key[g.NAMESPACE.length..] - $.on window, 'storage', onChange - - $.forceSync = (key) -> - # Storage events don't work across origins - # e.g. http://boards.4chan.org and https://boards.4chan.org - # so force a check for changes to avoid lost data. - key = g.NAMESPACE + key - onChange {key, newValue: $.getValue key} -else - $.sync = -> $.forceSync = -> -$.delete = (keys) -> - unless keys instanceof Array - keys = [keys] - for key in keys - $.deleteValue g.NAMESPACE + key - return + $.delete = (keys, cb) -> + unless keys instanceof Array + keys = [keys] + Promise.all(GM.deleteValue(g.NAMESPACE + key) for key in keys).then -> + items = {} + items[key] = undefined for key in keys + $.syncChannel.postMessage items + cb?() -$.get = $.oneItemSugar (items, cb) -> - $.queueTask $.getSync, items, cb + $.get = $.oneItemSugar (items, cb) -> + keys = Object.keys items + Promise.all(GM.getValue(g.NAMESPACE + key) for key in keys).then (values) -> + for val, i in values when val + items[keys[i]] = JSON.parse val + cb items -$.getSync = (items, cb) -> - for key of items when (val2 = $.getValue g.NAMESPACE + key) - items[key] = JSON.parse val2 - cb items + $.set = $.oneItemSugar (items, cb) -> + Promise.all(GM.setValue(g.NAMESPACE + key, JSON.stringify(val)) for key, val of items).then -> + $.syncChannel.postMessage items + cb?() -$.set = $.oneItemSugar (items, cb) -> - for key, value of items - $.setValue(g.NAMESPACE + key, JSON.stringify value) - cb?() + $.clear = (cb) -> + GM.listValues.then (keys) -> + $.delete keys.map((key) -> key.replace g.NAMESPACE, ''), cb + +else + + # workaround for Firefox 53 issue + $.currentValue = {} + $.GM_getValue = (key) -> + try + $.currentValue[key] = GM_getValue key + catch err + $.currentValue[key] + $.GM_setValue = (key, val) -> + $.currentValue[key] = val + GM_setValue key, val + $.GM_deleteValue = (key) -> + delete $.currentValue[key] + GM_deleteValue key + + unless GM_deleteValue? + $.perProtocolSettings = true + + if GM_deleteValue? + $.getValue = $.GM_getValue + $.listValues = -> GM_listValues() # error when called if missing + else if $.hasStorage + $.getValue = (key) -> localStorage[key] + $.listValues = -> + key for key of localStorage when key[...g.NAMESPACE.length] is g.NAMESPACE + else + $.getValue = -> + $.listValues = -> [] + + if GM_addValueChangeListener? + $.setValue = $.GM_setValue + $.deleteValue = $.GM_deleteValue + else if GM_deleteValue? + $.oldValue = {} + $.setValue = (key, val) -> + $.GM_setValue key, val + if key of $.syncing + $.oldValue[key] = val + localStorage[key] = val if $.hasStorage # for `storage` events + $.deleteValue = (key) -> + $.GM_deleteValue key + if key of $.syncing + delete $.oldValue[key] + localStorage.removeItem key if $.hasStorage # for `storage` events + $.cantSync = true if !$.hasStorage + else if $.hasStorage + $.oldValue = {} + $.setValue = (key, val) -> + $.oldValue[key] = val if key of $.syncing + localStorage[key] = val + $.deleteValue = (key) -> + delete $.oldValue[key] if key of $.syncing + localStorage.removeItem key + else + $.setValue = -> + $.deleteValue = -> + $.cantSync = $.cantSet = true + + if GM_addValueChangeListener? + $.sync = (key, cb) -> + $.syncing[key] = GM_addValueChangeListener g.NAMESPACE + key, (key2, oldValue, newValue, remote) -> + if remote + newValue = JSON.parse newValue unless newValue is undefined + cb newValue, key + $.forceSync = -> + else if GM_deleteValue? or $.hasStorage + $.sync = (key, cb) -> + key = g.NAMESPACE + key + $.syncing[key] = cb + $.oldValue[key] = $.getValue key + + do -> + onChange = ({key, newValue}) -> + return if not (cb = $.syncing[key]) + if newValue? + return if newValue is $.oldValue[key] + $.oldValue[key] = newValue + cb JSON.parse(newValue), key[g.NAMESPACE.length..] + else + return unless $.oldValue[key]? + delete $.oldValue[key] + cb undefined, key[g.NAMESPACE.length..] + $.on window, 'storage', onChange + + $.forceSync = (key) -> + # Storage events don't work across origins + # e.g. http://boards.4chan.org and https://boards.4chan.org + # so force a check for changes to avoid lost data. + key = g.NAMESPACE + key + onChange {key, newValue: $.getValue key} + else + $.sync = -> + $.forceSync = -> + + $.delete = (keys) -> + unless keys instanceof Array + keys = [keys] + for key in keys + $.deleteValue g.NAMESPACE + key + return + + $.get = $.oneItemSugar (items, cb) -> + $.queueTask $.getSync, items, cb + + $.getSync = (items, cb) -> + for key of items when (val2 = $.getValue g.NAMESPACE + key) + items[key] = JSON.parse val2 + cb items + + $.set = $.oneItemSugar (items, cb) -> + for key, value of items + $.setValue(g.NAMESPACE + key, JSON.stringify value) + cb?() + + $.clear = (cb) -> + # XXX https://github.com/greasemonkey/greasemonkey/issues/2033 + # Also support case where GM_listValues is not defined. + $.delete Object.keys(Conf) + $.delete ['previousversion', 'QR Size', 'captchas', 'QR.persona', 'hiddenPSA'] + try + $.delete $.listValues().map (key) -> key.replace g.NAMESPACE, '' + cb?() -$.clear = (cb) -> - # XXX https://github.com/greasemonkey/greasemonkey/issues/2033 - # Also support case where GM_listValues is not defined. - $.delete Object.keys(Conf) - $.delete ['previousversion', 'QR Size', 'captchas', 'QR.persona', 'hiddenPSA'] - try - $.delete $.listValues().map (key) -> key.replace g.NAMESPACE, '' - cb?() <% } %> diff --git a/src/platform/CrossOrigin.coffee b/src/platform/CrossOrigin.coffee index fdfa1cf65..6cfffaed7 100644 --- a/src/platform/CrossOrigin.coffee +++ b/src/platform/CrossOrigin.coffee @@ -63,7 +63,7 @@ CrossOrigin = options.overrideMimeType = 'text/plain; charset=x-user-defined' else options.responseType = 'arraybuffer' - GM_xmlhttpRequest options + (GM?.xmlHttpRequest or GM_xmlhttpRequest) options <% } %> file: (url, cb) -> @@ -99,7 +99,7 @@ CrossOrigin = return callbacks[url] = [cb] <% if (type === 'userscript') { %> - GM_xmlhttpRequest + (GM?.xmlHttpRequest or GM_xmlhttpRequest) method: "GET" url: url+'' onload: (xhr) ->