From bf2c18fddb081fc6f051298d0202e0a019519593 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 1 Sep 2015 13:29:47 -0400 Subject: [PATCH] Migrate `KeyValueStore` to ES6 modules --- .../components/discourse-banner.js.es6 | 7 +-- .../discourse/initializers/logout.js.es6 | 7 ++- .../discourse/initializers/message-bus.js.es6 | 1 - .../discourse/lib/key-value-store.js.es6 | 49 +++++++++++++++ .../discourse/lib/key_value_store.js | 63 ------------------- .../javascripts/discourse/lib/logout.js.es6 | 4 +- .../discourse/models/composer.js.es6 | 5 +- .../javascripts/discourse/models/rest.js.es6 | 5 +- .../inject-discourse-objects.js.es6 | 7 ++- .../discourse/routes/application.js.es6 | 2 +- app/assets/javascripts/main_include.js | 1 + .../lib/key-value-store-test.js.es6 | 20 +++--- test/javascripts/models/composer-test.js.es6 | 10 ++- 13 files changed, 89 insertions(+), 92 deletions(-) create mode 100644 app/assets/javascripts/discourse/lib/key-value-store.js.es6 delete mode 100644 app/assets/javascripts/discourse/lib/key_value_store.js diff --git a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 index a3f8f07d67c..56374168e6c 100644 --- a/app/assets/javascripts/discourse/components/discourse-banner.js.es6 +++ b/app/assets/javascripts/discourse/components/discourse-banner.js.es6 @@ -5,7 +5,7 @@ export default VisibleComponent.extend({ visible: function () { var bannerKey = this.get("banner.key"), dismissedBannerKey = this.get("user.dismissed_banner_key") || - Discourse.KeyValueStore.get("dismissed_banner_key"); + this.keyValueStore.get("dismissed_banner_key"); if (bannerKey) { bannerKey = parseInt(bannerKey, 10); } if (dismissedBannerKey) { dismissedBannerKey = parseInt(dismissedBannerKey, 10); } @@ -19,10 +19,9 @@ export default VisibleComponent.extend({ this.get("user").dismissBanner(this.get("banner.key")); } else { this.set("visible", false); - Discourse.KeyValueStore.set({ key: "dismissed_banner_key", value: this.get("banner.key") }); + this.keyValueStore.set({ key: "dismissed_banner_key", value: this.get("banner.key") }); } } - }, - + } }); diff --git a/app/assets/javascripts/discourse/initializers/logout.js.es6 b/app/assets/javascripts/discourse/initializers/logout.js.es6 index bc3fe49e86f..dc0ff59c81d 100644 --- a/app/assets/javascripts/discourse/initializers/logout.js.es6 +++ b/app/assets/javascripts/discourse/initializers/logout.js.es6 @@ -6,11 +6,12 @@ export default { after: "message-bus", initialize: function (container) { - const messageBus = container.lookup('message-bus:main'), - siteSettings = container.lookup('site-settings:main'); + const messageBus = container.lookup('message-bus:main'); + const siteSettings = container.lookup('site-settings:main'); + const keyValueStore = container.lookup('key-value-store:main'); if (!messageBus) { return; } - const callback = () => logout(siteSettings); + const callback = () => logout(siteSettings, keyValueStore); messageBus.subscribe("/logout", function () { bootbox.dialog(I18n.t("logout"), {label: I18n.t("refresh"), callback}, {onEscape: callback, backdrop: 'static'}); diff --git a/app/assets/javascripts/discourse/initializers/message-bus.js.es6 b/app/assets/javascripts/discourse/initializers/message-bus.js.es6 index 4b355ea0547..be9de5c3263 100644 --- a/app/assets/javascripts/discourse/initializers/message-bus.js.es6 +++ b/app/assets/javascripts/discourse/initializers/message-bus.js.es6 @@ -21,7 +21,6 @@ export default { messageBus.alwaysLongPoll = Discourse.Environment === "development"; messageBus.start(); - Discourse.KeyValueStore.init("discourse_", messageBus); messageBus.callbackInterval = siteSettings.anon_polling_interval; messageBus.backgroundCallbackInterval = siteSettings.background_polling_interval; diff --git a/app/assets/javascripts/discourse/lib/key-value-store.js.es6 b/app/assets/javascripts/discourse/lib/key-value-store.js.es6 new file mode 100644 index 00000000000..112da6de7f0 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/key-value-store.js.es6 @@ -0,0 +1,49 @@ +// A simple key value store that uses LocalStorage +let safeLocalStorage; + +try { + safeLocalStorage = localStorage; + if (localStorage["disableLocalStorage"] === "true") { + safeLocalStorage = null; + } +} catch(e){ + // cookies disabled, we don't care + safeLocalStorage = null; +} + + +const KeyValueStore = function(ctx) { + this.context = ctx; +} + +KeyValueStore.prototype = { + abandonLocal() { + if (!safeLocalStorage) { return; } + + let i = safeLocalStorage.length - 1; + while (i >= 0) { + let k = safeLocalStorage.key(i); + if (k.substring(0, this.context.length) === this.context) { + safeLocalStorage.removeItem(k); + } + i--; + } + return true; + }, + + remove(key) { + return safeLocalStorage.removeItem(this.context + key); + }, + + set(opts) { + if (!safeLocalStorage) { return false; } + safeLocalStorage[this.context + opts.key] = opts.value; + }, + + get(key) { + if (!safeLocalStorage) { return null; } + return safeLocalStorage[this.context + key]; + } +}; + +export default KeyValueStore; diff --git a/app/assets/javascripts/discourse/lib/key_value_store.js b/app/assets/javascripts/discourse/lib/key_value_store.js deleted file mode 100644 index 2ae20f5e6e5..00000000000 --- a/app/assets/javascripts/discourse/lib/key_value_store.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - A simple key value store that uses LocalStorage - - @class KeyValueStore - @namespace Discourse - @module Discourse -**/ -var safeLocalStorage; - -try { - safeLocalStorage = localStorage; - if (localStorage["disableLocalStorage"] === "true") { - safeLocalStorage = null; - } -} catch(e){ - // cookies disabled, we don't care - safeLocalStorage = null; -} - -Discourse.KeyValueStore = { - initialized: false, - context: "", - - init: function(ctx) { - this.initialized = true; - this.context = ctx; - }, - - abandonLocal: function() { - var i, k; - if (!(safeLocalStorage && this.initialized)) { - return; - } - i = safeLocalStorage.length - 1; - while (i >= 0) { - k = safeLocalStorage.key(i); - if (k.substring(0, this.context.length) === this.context) { - safeLocalStorage.removeItem(k); - } - i--; - } - return true; - }, - - remove: function(key) { - return safeLocalStorage.removeItem(this.context + key); - }, - - set: function(opts) { - if (!safeLocalStorage && this.initialized) { - return false; - } - safeLocalStorage[this.context + opts.key] = opts.value; - }, - - get: function(key) { - if (!safeLocalStorage) { - return null; - } - return safeLocalStorage[this.context + key]; - } -}; - diff --git a/app/assets/javascripts/discourse/lib/logout.js.es6 b/app/assets/javascripts/discourse/lib/logout.js.es6 index 8dc0539b898..2fe4078a69f 100644 --- a/app/assets/javascripts/discourse/lib/logout.js.es6 +++ b/app/assets/javascripts/discourse/lib/logout.js.es6 @@ -1,5 +1,5 @@ -export default function logout(siteSettings) { - Discourse.KeyValueStore.abandonLocal(); +export default function logout(siteSettings, keyValueStore) { + keyValueStore.abandonLocal(); const redirect = siteSettings.logout_redirect; if (Ember.isEmpty(redirect)) { diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 9317bb183bf..ad4115c8bbf 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -281,7 +281,7 @@ const Composer = RestModel.extend({ }.property('reply'), _setupComposer: function() { - const val = (Discourse.Mobile.mobileView ? false : (Discourse.KeyValueStore.get('composer.showPreview') || 'true')); + const val = (Discourse.Mobile.mobileView ? false : (this.keyValueStore.get('composer.showPreview') || 'true')); this.set('showPreview', val === 'true'); this.set('archetypeId', this.site.get('default_archetype')); }.on('init'), @@ -336,7 +336,7 @@ const Composer = RestModel.extend({ togglePreview() { this.toggleProperty('showPreview'); - Discourse.KeyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); + this.keyValueStore.set({ key: 'composer.showPreview', value: this.get('showPreview') }); }, applyTopicTemplate: function() { @@ -731,6 +731,7 @@ Composer.reopenClass({ } }, + // TODO: Replace with injection create(args) { args = args || {}; args.user = args.user || Discourse.User.current(); diff --git a/app/assets/javascripts/discourse/models/rest.js.es6 b/app/assets/javascripts/discourse/models/rest.js.es6 index 0c595bb7359..60d011bfc31 100644 --- a/app/assets/javascripts/discourse/models/rest.js.es6 +++ b/app/assets/javascripts/discourse/models/rest.js.es6 @@ -78,10 +78,13 @@ RestModel.reopenClass({ create(args) { args = args || {}; - if (!args.store) { + if (!args.store || !args.keyValueStore) { const container = Discourse.__container__; // Ember.warn('Use `store.createRecord` to create records instead of `.create()`'); args.store = container.lookup('store:main'); + + // TODO: Remove this when composer is using the store fully + args.keyValueStore = container.lookup('key-value-store:main'); } args.__munge = this.munge; diff --git a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 index 736f630f7cd..44559b6d2f1 100644 --- a/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 +++ b/app/assets/javascripts/discourse/pre-initializers/inject-discourse-objects.js.es6 @@ -1,4 +1,5 @@ import Session from 'discourse/models/session'; +import KeyValueStore from 'discourse/lib/key-value-store'; import AppEvents from 'discourse/lib/app-events'; import Store from 'discourse/models/store'; import DiscourseURL from 'discourse/lib/url'; @@ -8,7 +9,7 @@ import SearchService from 'discourse/services/search'; function inject() { const app = arguments[0], name = arguments[1], - singletonName = Ember.String.underscore(name).replace(/_/, '-') + ':main'; + singletonName = Ember.String.underscore(name).replace(/_/g, '-') + ':main'; Array.prototype.slice.call(arguments, 2).forEach(dest => app.inject(dest, name, singletonName)); } @@ -49,5 +50,9 @@ export default { injectAll(app, 'messageBus'); app.register('location:discourse-location', DiscourseLocation); + + const keyValueStore = new KeyValueStore("discourse_"); + app.register('key-value-store:main', keyValueStore, { instantiate: false }); + injectAll(app, 'keyValueStore'); } }; diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 443d0e9c8b8..3a05163f601 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -19,7 +19,7 @@ const ApplicationRoute = Discourse.Route.extend(OpenComposer, { actions: { logout() { - this.currentUser.destroySession().then(() => logout(this.siteSettings)); + this.currentUser.destroySession().then(() => logout(this.siteSettings, this.keyValueStore)); }, _collectTitleTokens(tokens) { diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 69396e6c98e..25238bf9235 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -18,6 +18,7 @@ //= require ./discourse/lib/url //= require ./discourse/lib/debounce //= require ./discourse/lib/quote +//= require ./discourse/lib/key-value-store //= require ./discourse/helpers/i18n //= require ./discourse/helpers/fa-icon //= require ./discourse/helpers/register-unbound diff --git a/test/javascripts/lib/key-value-store-test.js.es6 b/test/javascripts/lib/key-value-store-test.js.es6 index 0ddf9652db0..8f1b0ae4003 100644 --- a/test/javascripts/lib/key-value-store-test.js.es6 +++ b/test/javascripts/lib/key-value-store-test.js.es6 @@ -1,20 +1,18 @@ -var store = Discourse.KeyValueStore; +import KeyValueStore from "discourse/lib/key-value-store"; -module("Discourse.KeyValueStore", { - setup: function() { - store.init("test"); - } -}); +module("lib:key-value-store"); -test("it's able to get the result back from the store", function() { +test("it's able to get the result back from the store", (assert) => { + const store = new KeyValueStore("_test"); store.set({ key: "bob", value: "uncle" }); - equal(store.get("bob"), "uncle"); + assert.equal(store.get("bob"), "uncle"); }); -test("is able to nuke the store", function() { +test("is able to nuke the store", (assert) => { + const store = new KeyValueStore("_test"); store.set({ key: "bob1", value: "uncle" }); store.abandonLocal(); localStorage.a = 1; - equal(store.get("bob1"), void 0); - equal(localStorage.a, "1"); + assert.equal(store.get("bob1"), void 0); + assert.equal(localStorage.a, "1"); }); diff --git a/test/javascripts/models/composer-test.js.es6 b/test/javascripts/models/composer-test.js.es6 index e6bb0d74d1c..08559b8bca8 100644 --- a/test/javascripts/models/composer-test.js.es6 +++ b/test/javascripts/models/composer-test.js.es6 @@ -1,14 +1,18 @@ import { blank } from 'helpers/qunit-helpers'; import { currentUser } from 'helpers/qunit-helpers'; +import KeyValueStore from 'discourse/lib/key-value-store'; module("model:composer"); +const keyValueStore = new KeyValueStore("_test_composer"); + function createComposer(opts) { opts = opts || {}; opts.user = opts.user || currentUser(); opts.site = Discourse.Site.current(); opts.siteSettings = Discourse.SiteSettings; - return Discourse.Composer.create(opts); + opts.keyValueStore = keyValueStore; +; return Discourse.Composer.create(opts); } test('replyLength', function() { @@ -184,9 +188,9 @@ test('showPreview', function() { Discourse.Mobile.mobileView = true; equal(newComposer().get('showPreview'), false, "Don't show preview in mobile view"); - Discourse.KeyValueStore.set({ key: 'composer.showPreview', value: 'true' }); + keyValueStore.set({ key: 'composer.showPreview', value: 'true' }); equal(newComposer().get('showPreview'), false, "Don't show preview in mobile view even if KeyValueStore wants to"); - Discourse.KeyValueStore.remove('composer.showPreview'); + keyValueStore.remove('composer.showPreview'); Discourse.Mobile.mobileView = false; equal(newComposer().get('showPreview'), true, "Show preview by default in desktop view");