Merge branch 'MDL-44707-master' of git://github.com/marinaglancy/moodle
[moodle.git] / lib / amd / src / localstorage.js
1 // This file is part of Moodle - http://moodle.org/
2 //
3 // Moodle is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // Moodle is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16 /**
17  * Simple API for set/get to localstorage, with cacherev expiration.
18  *
19  * @module     core/localstorage
20  * @package    core
21  * @class      localstorage
22  * @copyright  2015 Damyon Wiese <damyon@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @since      2.9
25  */
26 define(['core/config'], function(config) {
28     // Private functions and variables.
29     /** @var {boolean} supported - Is localstorage supported in this browser? */
30     var supported = false;
31     /** @var {string} prefix - Prefix to use on all cache keys */
32     var prefix = '';
33     /** @var {jsrevPrefix} jsrevPrefix - Key to store the current jsrev version for the cache */
34     var jsrevPrefix = '';
35     /** @var {Object} localStorage - Browsers localStorage object */
36     var localStorage = null;
38     /**
39      * Check if the browser supports local storage.
40      *
41      * @method detectSupport
42      * @return {boolean} True if the browser supports local storage.
43      */
44     var detectSupport = function() {
45         if (config.jsrev == -1) {
46             // Disable cache if debugging.
47             return false;
48         }
49         if (typeof(window.localStorage) !== "undefined") {
50             try {
51                 localStorage = window.localStorage;
52                 return localStorage !== null;
53             } catch (ex) {
54                 return false;
55             }
56         }
57     };
59     /**
60      * Add a unique prefix to all keys so multiple moodle sites do not share caches.
61      *
62      * @method prefixKey
63      * @param {string} key The cache key to prefix.
64      * @return {string} The new key
65      */
66     var prefixKey = function(key) {
67         return prefix + key;
68     };
70     /**
71      * Check the current jsrev version and clear the cache if it has been bumped.
72      *
73      * @method validateCache
74      */
75     var validateCache = function() {
76         var cacheVersion = localStorage.getItem(jsrevPrefix);
77         if (cacheVersion === null) {
78             localStorage.setItem(jsrevPrefix, config.jsrev);
79             return;
80         }
81         var moodleVersion = config.jsrev;
83         if (moodleVersion != cacheVersion) {
84             localStorage.clear();
85             localStorage.setItem(jsrevPrefix, config.jsrev);
86         }
87     };
89     /**
90      * Hash a string, used to make shorter key prefixes.
91      *
92      * @method hashString
93      * @param string source The string to hash
94      * @return int The int hash
95      */
96     var hashString = function(source) {
97         // From http://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript-jquery.
98         /* jshint bitwise: false */
99         var hash = 0, i, chr, len;
100         if (source.length === 0) {
101             return hash;
102         }
103         for (i = 0, len = source.length; i < len; i++) {
104             chr   = source.charCodeAt(i);
105             hash  = ((hash << 5) - hash) + chr;
106             hash |= 0; // Convert to 32bit integer
107         }
108         return hash;
109     };
111     /**
112      * Init this module.
113      *
114      * This computes the hash prefixes from jsrev and friends.
115      */
116     var init = function() {
117         supported = detectSupport();
118         var hashSource = config.wwwroot + '/' + config.jsrev;
120         var hash = hashString(hashSource);
121         prefix = hash + '/';
122         hashSource = config.wwwroot + '/';
123         hash = hashString(hashSource);
124         jsrevPrefix = hash + '/jsrev';
125     };
127     // Run the module init.
128     init();
130     return /** @alias module:core/localstorage */ {
131         /**
132          * Get a value from local storage. Remember - all values must be strings.
133          *
134          * @method get
135          * @param {string} key The cache key to check.
136          * @return {boolean|string} False if the value is not in the cache, or some other error - a string otherwise.
137          */
138         get: function(key) {
139             if (!supported) {
140                 return false;
141             }
142             validateCache();
143             key = prefixKey(key);
145             return localStorage.getItem(key);
146         },
148         /**
149          * Set a value to local storage. Remember - all values must be strings.
150          *
151          * @method set
152          * @param {string} key The cache key to set.
153          * @param {string} value The value to set.
154          * @return {boolean} False if the value can't be saved in the cache, or some other error - true otherwise.
155          */
156         set: function(key, value) {
157             if (!supported) {
158                 return false;
159             }
160             validateCache();
161             key = prefixKey(key);
162             // This can throw exceptions when the storage limit is reached.
163             try {
164                 localStorage.setItem(key, value);
165             } catch (e) {
166                 return false;
167             }
168             return true;
169         }
171     };
172 });