Create MemoryStorage wrapper around mw.SafeStorage

This means we can guarantee we will be able to recover
auto-saves if we don't reload the page.

Change-Id: Ic867ae6df0c949f35cb32ec4b835688778db29ef
This commit is contained in:
Ed Sanders 2022-02-01 22:55:57 +00:00
parent 7381d9d963
commit dd9d37b555
4 changed files with 72 additions and 3 deletions

View file

@ -70,6 +70,7 @@
"CommentItem.js", "CommentItem.js",
"HeadingItem.js", "HeadingItem.js",
"CommentDetails.js", "CommentDetails.js",
"MemoryStorage.js",
"lib/moment-timezone/moment-timezone-with-data-1970-2030.js", "lib/moment-timezone/moment-timezone-with-data-1970-2030.js",
{ {
"name": "parser/data.json", "name": "parser/data.json",

66
modules/MemoryStorage.js Normal file
View file

@ -0,0 +1,66 @@
/**
* MemoryStorage creates a wrapper around mw.SafeStorage objects, duplicating
* their contents in memory, so that even if the underlying storage mechanism
* fails (e.g. quote exceeded), the storage can be relied on before the
* page has been reloaded.
*
* @example
* var sessionStorage = new MemoryStorage( mw.storage.session.store );
* var localStorage = new MemoryStorage( mw.storage.store );
*
* @class
* @extends mw.SafeStorage
* @param {Object} store
*/
function MemoryStorage() {
// Parent constructor
MemoryStorage.super.apply( this, arguments );
this.data = {};
}
// HACK: SafeStorage is not exposed as a public API, but we can
// access it as the constructor of mw.storage.
var SafeStorage = mw.storage.constructor;
/* Inheritance */
OO.inheritClass( MemoryStorage, SafeStorage );
/* Methods */
/**
* @inheritdoc
*/
MemoryStorage.prototype.get = function ( key ) {
if ( Object.prototype.hasOwnProperty.call( this.data, key ) ) {
return this.data[ key ];
} else {
// Parent method
return MemoryStorage.super.prototype.get.apply( this, arguments );
}
};
/**
* @inheritdoc
*/
MemoryStorage.prototype.set = function ( key, value ) {
// Parent method
MemoryStorage.super.prototype.set.apply( this, arguments );
this.data[ key ] = value;
return true;
};
/**
* @inheritdoc
*/
MemoryStorage.prototype.remove = function ( key ) {
// Parent method
MemoryStorage.super.prototype.remove.apply( this, arguments );
delete this.data[ key ];
return true;
};
module.exports = MemoryStorage;

View file

@ -5,7 +5,8 @@ var
$pageContainer, linksController, lastHighlightComment, $pageContainer, linksController, lastHighlightComment,
featuresEnabled = mw.config.get( 'wgDiscussionToolsFeaturesEnabled' ) || {}, featuresEnabled = mw.config.get( 'wgDiscussionToolsFeaturesEnabled' ) || {},
seenAutoTopicSubPopup = !!+mw.user.options.get( 'discussiontools-seenautotopicsubpopup' ), seenAutoTopicSubPopup = !!+mw.user.options.get( 'discussiontools-seenautotopicsubpopup' ),
storage = mw.storage.session, MemoryStorage = require( './MemoryStorage.js' ),
storage = new MemoryStorage( mw.storage.session.store ),
Parser = require( './Parser.js' ), Parser = require( './Parser.js' ),
ThreadItem = require( './ThreadItem.js' ), ThreadItem = require( './ThreadItem.js' ),
CommentItem = require( './CommentItem.js' ), CommentItem = require( './CommentItem.js' ),
@ -1030,5 +1031,6 @@ module.exports = {
update: update, update: update,
checkThreadItemOnPage: checkThreadItemOnPage, checkThreadItemOnPage: checkThreadItemOnPage,
getCheckboxesPromise: getCheckboxesPromise, getCheckboxesPromise: getCheckboxesPromise,
getApi: getApi getApi: getApi,
storage: storage
}; };

View file

@ -45,7 +45,7 @@ function ReplyWidget( commentController, commentDetails, config ) {
this.context = contextNode ? contextNode.nodeName.toLowerCase() : 'dl'; this.context = contextNode ? contextNode.nodeName.toLowerCase() : 'dl';
// TODO: Should storagePrefix include pageName? // TODO: Should storagePrefix include pageName?
this.storagePrefix = 'reply/' + threadItem.id; this.storagePrefix = 'reply/' + threadItem.id;
this.storage = mw.storage.session; this.storage = controller.storage;
// eslint-disable-next-line no-jquery/no-global-selector // eslint-disable-next-line no-jquery/no-global-selector
this.contentDir = $( '#mw-content-text' ).css( 'direction' ); this.contentDir = $( '#mw-content-text' ).css( 'direction' );