* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 2.9
*/
-// Disable no-restriced-properties because M.str is expected here:
-/* eslint-disable no-restricted-properties */
-define(['jquery', 'core/ajax', 'core/localstorage'], function($, ajax, storage) {
-
- var promiseCache = [];
-
- return /** @alias module:core/str */ {
- // Public variables and functions.
- /**
- * Return a promise object that will be resolved into a string eventually (maybe immediately).
- *
- * @method get_string
- * @param {string} key The language string key
- * @param {string} component The language string component
- * @param {string} param The param for variable expansion in the string.
- * @param {string} lang The users language - if not passed it is deduced.
- * @return {Promise}
- */
- // eslint-disable-next-line camelcase
- get_string: function(key, component, param, lang) {
- var request = this.get_strings([{
- key: key,
- component: component,
- param: param,
- lang: lang
- }]);
-
- return request.then(function(results) {
- return results[0];
- });
- },
-
- /**
- * Make a batch request to load a set of strings
- *
- * @method get_strings
- * @param {Object[]} requests Array of { key: key, component: component, param: param, lang: lang };
- * See get_string for more info on these args.
- * @return {Promise}
- */
- // eslint-disable-next-line camelcase
- get_strings: function(requests) {
-
- var deferred = $.Deferred();
- var results = [];
- var i = 0;
- var missing = false;
- var request;
-
- // Try from local storage. If it's there - put it in M.str and resolve it.
-
- for (i = 0; i < requests.length; i++) {
- request = requests[i];
- if (typeof request.lang === "undefined") {
- request.lang = $('html').attr('lang').replace(/-/g, '_');
- }
- request.cacheKey = 'core_str/' + request.key + '/' + request.component + '/' + request.lang;
- if (typeof M.str[request.component] === "undefined" ||
- typeof M.str[request.component][request.key] === "undefined") {
- // Try and revive it from local storage.
- var cached = storage.get(request.cacheKey);
- if (cached) {
- if (typeof M.str[request.component] === "undefined") {
- M.str[request.component] = [];
- }
- M.str[request.component][request.key] = cached;
- } else {
- // It's really not here.
- missing = true;
- }
- }
- }
+import $ from 'jquery';
+import Ajax from 'core/ajax';
+import LocalStorage from 'core/localstorage';
+
+// Module cache for the promises so that we don't make multiple
+// unnecessary requests.
+let promiseCache = [];
+
+/**
+ * Return a promise object that will be resolved into a string eventually (maybe immediately).
+ *
+ * @method get_string
+ * @param {string} key The language string key
+ * @param {string} component The language string component
+ * @param {string} param The param for variable expansion in the string.
+ * @param {string} lang The users language - if not passed it is deduced.
+ * @return {Promise}
+ */
+export const get_string = (key, component, param, lang) => {
+ return get_strings([{key, component, param, lang}])
+ .then(results => results[0]);
+};
+
+/**
+ * Make a batch request to load a set of strings
+ *
+ * @method get_strings
+ * @param {Object[]} requests Array of { key: key, component: component, param: param, lang: lang };
+ * See get_string for more info on these args.
+ * @return {Promise}
+ */
+export const get_strings = (requests) => {
+ let requestData = [];
+ const pageLang = $('html').attr('lang').replace(/-/g, '_');
+ // Helper function to construct the cache key.
+ const getCacheKey = ({key, component, lang = pageLang}) => `core_str/${key}/${component}/${lang}`;
+
+ const stringPromises = requests.map((request) => {
+ const cacheKey = getCacheKey(request);
+ const {component, key, lang} = request;
+ // Helper function to add the promise to cache.
+ const buildReturn = (promise) => {
+ // Make sure the promise cache contains our promise.
+ promiseCache[cacheKey] = promise;
+ return promise;
+ };
+
+ // Check if we can serve the string straight from M.str.
+ if (component in M.str && key in M.str[component]) {
+ return buildReturn(new Promise((resolve) => {
+ resolve(M.str[component][key]);
+ }));
+ }
+
+ // Check if the string is in the browser's local storage.
+ const cached = LocalStorage.get(cacheKey);
+ if (cached) {
+ M.str[component] = {...M.str[component], [key]: cached};
+ return buildReturn(new Promise((resolve) => {
+ resolve(M.str[component][key]);
+ }));
+ }
- if (!missing) {
- // We have all the strings already.
- for (i = 0; i < requests.length; i++) {
- request = requests[i];
-
- results[i] = M.util.get_string(request.key, request.component, request.param);
- }
- deferred.resolve(results);
- } else {
- var ajaxrequests = [];
- var fetchpromises = [];
-
- // Done handler for ajax call. Must be bound to the current fetchpromise. We do this
- // to avoid creating a function in a loop.
- var doneFunc = function(str) {
- this.resolve(str);
- };
-
- var failFunc = function(reason) {
- this.reject(reason);
- };
-
- for (i = 0; i < requests.length; i++) {
- request = requests[i];
-
- // If we ever fetched this string with a promise, reuse it.
- if (typeof promiseCache[request.cacheKey] !== 'undefined') {
- fetchpromises.push(promiseCache[request.cacheKey]);
- } else {
- // Add this to the list we need to really fetch.
- var fetchpromise = $.Deferred();
-
- ajaxrequests.push({
- methodname: 'core_get_string',
- args: {
- stringid: request.key,
- component: request.component,
- lang: request.lang,
- stringparams: []
- },
- done: doneFunc.bind(fetchpromise),
- fail: failFunc.bind(fetchpromise)
- });
-
- promiseCache[request.cacheKey] = fetchpromise.promise();
- fetchpromises.push(promiseCache[request.cacheKey]);
- }
- }
-
- // Everything might already be queued so we need to check if we have real ajax requests to run.
- if (ajaxrequests.length > 0) {
- ajax.call(ajaxrequests, true, false, false, 0, M.cfg.langrev);
- }
-
- $.when.apply(null, fetchpromises).done(
- function() {
- // Turn the list of arguments (unknown length) into a real array.
- var i = 0;
- for (i = 0; i < arguments.length; i++) {
- request = requests[i];
- // Cache all the string templates.
- if (typeof M.str[request.component] === "undefined") {
- M.str[request.component] = [];
- }
- M.str[request.component][request.key] = arguments[i];
- storage.set('core_str/' + request.key + '/' + request.component + '/' + request.lang, arguments[i]);
- // And set the results.
- results[i] = M.util.get_string(request.key, request.component, request.param).trim();
- }
- deferred.resolve(results);
- }
- ).fail(
- function(ex) {
- deferred.reject(ex);
- }
- );
+ // Check if we've already loaded this string from the server.
+ if (cacheKey in promiseCache) {
+ return buildReturn(promiseCache[cacheKey]);
+ } else {
+ // We're going to have to ask the server for the string so
+ // add this string to the list of requests to be sent.
+ return buildReturn(new Promise((resolve, reject) => {
+ requestData.push({
+ methodname: 'core_get_string',
+ args: {
+ stringid: key,
+ stringparams: [],
+ component,
+ lang,
+ },
+ done: (str) => {
+ // When we get the response from the server
+ // we should update M.str and the browser's
+ // local storage before resolving this promise.
+ M.str[component] = {...M.str[component], [key]: str};
+ LocalStorage.set(cacheKey, str);
+ resolve(str);
+ },
+ fail: reject
+ });
+ }));
+ }
+ });
+
+ if (requestData.length) {
+ // If we need to load any strings from the server then send
+ // off the request.
+ Ajax.call(requestData, true, false, false, 0, M.cfg.langrev);
+ }
+
+ // We need to use jQuery here because some calling code uses the
+ // .done handler instead of the .then handler.
+ return $.when.apply($, stringPromises)
+ .then((...strings) => strings);
+};
+
+/**
+ * Add a list of strings to the caches.
+ *
+ * @method cache_strings
+ * @param {Object[]} strings Array of { key: key, component: component, lang: lang, value: value }
+ */
+export const cache_strings = (strings) => {
+ const defaultLang = $('html').attr('lang').replace(/-/g, '_');
+
+ strings.forEach(({key, component, value, lang = defaultLang}) => {
+ const cacheKey = ['core_str', key, component, lang].join('/');
+
+ // Check M.str caching.
+ if (!(component in M.str) || !(key in M.str[component])) {
+ if (!(component in M.str)) {
+ M.str[component] = {};
}
- return deferred.promise();
- },
- /**
- * Add a list of strings to the caches.
- *
- * @method cache_strings
- * @param {Object[]} strings Array of { key: key, component: component, lang: lang, value: value }
- */
- // eslint-disable-next-line camelcase
- cache_strings: function(strings) {
- var defaultLang = $('html').attr('lang').replace(/-/g, '_');
- strings.forEach(function(string) {
- var lang = !(lang in string) ? defaultLang : string.lang;
- var key = string.key;
- var component = string.component;
- var value = string.value;
- var cacheKey = ['core_str', key, component, lang].join('/');
-
- // Check M.str caching.
- if (!(component in M.str) || !(key in M.str[component])) {
- if (!(component in M.str)) {
- M.str[component] = {};
- }
-
- M.str[component][key] = value;
- }
-
- // Check local storage.
- if (!storage.get(cacheKey)) {
- storage.set(cacheKey, value);
- }
-
- // Check the promises cache.
- if (!(cacheKey in promiseCache)) {
- promiseCache[cacheKey] = $.Deferred().resolve(value).promise();
- }
- });
+ M.str[component][key] = value;
+ }
+
+ // Check local storage.
+ if (!LocalStorage.get(cacheKey)) {
+ LocalStorage.set(cacheKey, value);
+ }
+
+ // Check the promises cache.
+ if (!(cacheKey in promiseCache)) {
+ promiseCache[cacheKey] = $.Deferred().resolve(value).promise();
}
- };
-});
+ });
+};