Files
moodle/lib/amd/src/str.js
T
Ryan Wyllie fbbed5c603 MDL-64348 javascript: add cache_strings to str.js
Added a function to allow a set of strings to be added to the
str.js caches if they've been loaded outside of that module.
2019-01-07 09:03:06 +08:00

218 lines
8.7 KiB
JavaScript

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Fetch and render language strings.
* Hooks into the old M.str global - but can also fetch missing strings on the fly.
*
* @module core/str
* @class str
* @package core
* @copyright 2015 Damyon Wiese <damyon@moodle.com>
* @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;
}
}
}
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);
}
$.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);
}
);
}
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();
}
});
}
};
});