303 lines
25 KiB
JavaScript
303 lines
25 KiB
JavaScript
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// This is a generated file. You can view the original //
|
||
|
// source in your browser if your browser supports source maps. //
|
||
|
// //
|
||
|
// If you are using Chrome, open the Developer Tools and click the gear //
|
||
|
// icon in its lower right corner. In the General Settings panel, turn //
|
||
|
// on 'Enable source maps'. //
|
||
|
// //
|
||
|
// If you are using Firefox 23, go to `about:config` and set the //
|
||
|
// `devtools.debugger.source-maps-enabled` preference to true. //
|
||
|
// (The preference should be on by default in Firefox 24; versions //
|
||
|
// older than 23 do not support source maps.) //
|
||
|
// //
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
(function () {
|
||
|
|
||
|
/* Imports */
|
||
|
var Meteor = Package.meteor.Meteor;
|
||
|
var _ = Package.underscore._;
|
||
|
var Log = Package.logging.Log;
|
||
|
var JSON = Package.json.JSON;
|
||
|
|
||
|
/* Package-scope variables */
|
||
|
var Reload;
|
||
|
|
||
|
(function () {
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// packages/reload/reload.js //
|
||
|
// //
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
/** // 1
|
||
|
* This code does _NOT_ support hot (session-restoring) reloads on // 2
|
||
|
* IE6,7. It only works on browsers with sessionStorage support. // 3
|
||
|
* // 4
|
||
|
* There are a couple approaches to add IE6,7 support: // 5
|
||
|
* // 6
|
||
|
* - use IE's "userData" mechanism in combination with window.name. // 7
|
||
|
* This mostly works, however the problem is that it can not get to the // 8
|
||
|
* data until after DOMReady. This is a problem for us since this API // 9
|
||
|
* relies on the data being ready before API users run. We could // 10
|
||
|
* refactor using Meteor.startup in all API users, but that might slow // 11
|
||
|
* page loads as we couldn't start the stream until after DOMReady. // 12
|
||
|
* Here are some resources on this approach: // 13
|
||
|
* https://github.com/hugeinc/USTORE.js // 14
|
||
|
* http://thudjs.tumblr.com/post/419577524/localstorage-userdata // 15
|
||
|
* http://www.javascriptkit.com/javatutors/domstorage2.shtml // 16
|
||
|
* // 17
|
||
|
* - POST the data to the server, and have the server send it back on // 18
|
||
|
* page load. This is nice because it sidesteps all the local storage // 19
|
||
|
* compatibility issues, however it is kinda tricky. We can use a unique // 20
|
||
|
* token in the URL, then get rid of it with HTML5 pushstate, but that // 21
|
||
|
* only works on pushstate browsers. // 22
|
||
|
* // 23
|
||
|
* This will all need to be reworked entirely when we add server-side // 24
|
||
|
* HTML rendering. In that case, the server will need to have access to // 25
|
||
|
* the client's session to render properly. // 26
|
||
|
*/ // 27
|
||
|
// 28
|
||
|
// XXX when making this API public, also expose a flag for the app // 29
|
||
|
// developer to know whether a hot code push is happening. This is // 30
|
||
|
// useful for apps using `window.onbeforeunload`. See // 31
|
||
|
// https://github.com/meteor/meteor/pull/657 // 32
|
||
|
// 33
|
||
|
Reload = {}; // 34
|
||
|
// 35
|
||
|
var KEY_NAME = 'Meteor_Reload'; // 36
|
||
|
// 37
|
||
|
var old_data = {}; // 38
|
||
|
// read in old data at startup. // 39
|
||
|
var old_json; // 40
|
||
|
// 41
|
||
|
// This logic for sessionStorage detection is based on browserstate/history.js // 42
|
||
|
var safeSessionStorage = null; // 43
|
||
|
try { // 44
|
||
|
// This throws a SecurityError on Chrome if cookies & localStorage are // 45
|
||
|
// explicitly disabled // 46
|
||
|
// // 47
|
||
|
// On Firefox with dom.storage.enabled set to false, sessionStorage is null // 48
|
||
|
// // 49
|
||
|
// We can't even do (typeof sessionStorage) on Chrome, it throws. So we rely // 50
|
||
|
// on the throw if sessionStorage == null; the alternative is browser // 51
|
||
|
// detection, but this seems better. // 52
|
||
|
safeSessionStorage = window.sessionStorage; // 53
|
||
|
// 54
|
||
|
// Check we can actually use it // 55
|
||
|
if (safeSessionStorage) { // 56
|
||
|
safeSessionStorage.setItem('__dummy__', '1'); // 57
|
||
|
safeSessionStorage.removeItem('__dummy__'); // 58
|
||
|
} else { // 59
|
||
|
// Be consistently null, for safety // 60
|
||
|
safeSessionStorage = null; // 61
|
||
|
} // 62
|
||
|
} catch(e) { // 63
|
||
|
// Expected on chrome with strict security, or if sessionStorage not supported // 64
|
||
|
safeSessionStorage = null; // 65
|
||
|
} // 66
|
||
|
// 67
|
||
|
// Exported for test. // 68
|
||
|
Reload._getData = function () { // 69
|
||
|
return safeSessionStorage && safeSessionStorage.getItem(KEY_NAME); // 70
|
||
|
}; // 71
|
||
|
// 72
|
||
|
if (safeSessionStorage) { // 73
|
||
|
old_json = Reload._getData(); // 74
|
||
|
safeSessionStorage.removeItem(KEY_NAME); // 75
|
||
|
} else { // 76
|
||
|
// Unsupported browser (IE 6,7) or locked down security settings. // 77
|
||
|
// No session resumption. // 78
|
||
|
// Meteor._debug("XXX UNSUPPORTED BROWSER/SETTINGS"); // 79
|
||
|
} // 80
|
||
|
// 81
|
||
|
if (!old_json) old_json = '{}'; // 82
|
||
|
var old_parsed = {}; // 83
|
||
|
try { // 84
|
||
|
old_parsed = JSON.parse(old_json); // 85
|
||
|
if (typeof old_parsed !== "object") { // 86
|
||
|
Meteor._debug("Got bad data on reload. Ignoring."); // 87
|
||
|
old_parsed = {}; // 88
|
||
|
} // 89
|
||
|
} catch (err) { // 90
|
||
|
Meteor._debug("Got invalid JSON on reload. Ignoring."); // 91
|
||
|
} // 92
|
||
|
// 93
|
||
|
if (old_parsed.reload && typeof old_parsed.data === "object") { // 94
|
||
|
// Meteor._debug("Restoring reload data."); // 95
|
||
|
old_data = old_parsed.data; // 96
|
||
|
} // 97
|
||
|
// 98
|
||
|
// 99
|
||
|
var providers = []; // 100
|
||
|
// 101
|
||
|
////////// External API ////////// // 102
|
||
|
// 103
|
||
|
// Packages that support migration should register themselves by calling // 104
|
||
|
// this function. When it's time to migrate, callback will be called // 105
|
||
|
// with one argument, the "retry function," and an optional 'option' // 106
|
||
|
// argument (containing a key 'immediateMigration'). If the package // 107
|
||
|
// is ready to migrate, it should return [true, data], where data is // 108
|
||
|
// its migration data, an arbitrary JSON value (or [true] if it has // 109
|
||
|
// no migration data this time). If the package needs more time // 110
|
||
|
// before it is ready to migrate, it should return false. Then, once // 111
|
||
|
// it is ready to migrating again, it should call the retry // 112
|
||
|
// function. The retry function will return immediately, but will // 113
|
||
|
// schedule the migration to be retried, meaning that every package // 114
|
||
|
// will be polled once again for its migration data. If they are all // 115
|
||
|
// ready this time, then the migration will happen. name must be set if there // 116
|
||
|
// is migration data. If 'immediateMigration' is set in the options // 117
|
||
|
// argument, then it doesn't matter whether the package is ready to // 118
|
||
|
// migrate or not; the reload will happen immediately without waiting // 119
|
||
|
// (used for OAuth redirect login). // 120
|
||
|
// // 121
|
||
|
Reload._onMigrate = function (name, callback) { // 122
|
||
|
if (!callback) { // 123
|
||
|
// name not provided, so first arg is callback. // 124
|
||
|
callback = name; // 125
|
||
|
name = undefined; // 126
|
||
|
} // 127
|
||
|
providers.push({name: name, callback: callback}); // 128
|
||
|
}; // 129
|
||
|
// 130
|
||
|
// Called by packages when they start up. // 131
|
||
|
// Returns the object that was saved, or undefined if none saved. // 132
|
||
|
// // 133
|
||
|
Reload._migrationData = function (name) { // 134
|
||
|
return old_data[name]; // 135
|
||
|
}; // 136
|
||
|
// 137
|
||
|
// Options are the same as for `Reload._migrate`. // 138
|
||
|
var pollProviders = function (tryReload, options) { // 139
|
||
|
tryReload = tryReload || function () {}; // 140
|
||
|
options = options || {}; // 141
|
||
|
// 142
|
||
|
var migrationData = {}; // 143
|
||
|
var remaining = _.clone(providers); // 144
|
||
|
var allReady = true; // 145
|
||
|
while (remaining.length) { // 146
|
||
|
var p = remaining.shift(); // 147
|
||
|
var status = p.callback(tryReload, options); // 148
|
||
|
if (!status[0]) // 149
|
||
|
allReady = false; // 150
|
||
|
if (status.length > 1 && p.name) // 151
|
||
|
migrationData[p.name] = status[1]; // 152
|
||
|
}; // 153
|
||
|
if (allReady || options.immediateMigration) // 154
|
||
|
return migrationData; // 155
|
||
|
else // 156
|
||
|
return null; // 157
|
||
|
}; // 158
|
||
|
// 159
|
||
|
// Options are: // 160
|
||
|
// - immediateMigration: true if the page will be reloaded immediately // 161
|
||
|
// regardless of whether packages report that they are ready or not. // 162
|
||
|
Reload._migrate = function (tryReload, options) { // 163
|
||
|
// Make sure each package is ready to go, and collect their // 164
|
||
|
// migration data // 165
|
||
|
var migrationData = pollProviders(tryReload, options); // 166
|
||
|
if (migrationData === null) // 167
|
||
|
return false; // not ready yet.. // 168
|
||
|
// 169
|
||
|
try { // 170
|
||
|
// Persist the migration data // 171
|
||
|
var json = JSON.stringify({ // 172
|
||
|
data: migrationData, reload: true // 173
|
||
|
}); // 174
|
||
|
} catch (err) { // 175
|
||
|
Meteor._debug("Couldn't serialize data for migration", migrationData); // 176
|
||
|
throw err; // 177
|
||
|
} // 178
|
||
|
// 179
|
||
|
if (safeSessionStorage) { // 180
|
||
|
try { // 181
|
||
|
safeSessionStorage.setItem(KEY_NAME, json); // 182
|
||
|
} catch (err) { // 183
|
||
|
// We should have already checked this, but just log - don't throw // 184
|
||
|
Meteor._debug("Couldn't save data for migration to sessionStorage", err); // 185
|
||
|
} // 186
|
||
|
} else { // 187
|
||
|
Meteor._debug("Browser does not support sessionStorage. Not saving migration state."); // 188
|
||
|
} // 189
|
||
|
// 190
|
||
|
return true; // 191
|
||
|
}; // 192
|
||
|
// 193
|
||
|
// Allows tests to isolate the list of providers. // 194
|
||
|
Reload._withFreshProvidersForTest = function (f) { // 195
|
||
|
var originalProviders = _.clone(providers); // 196
|
||
|
providers = []; // 197
|
||
|
try { // 198
|
||
|
f(); // 199
|
||
|
} finally { // 200
|
||
|
providers = originalProviders; // 201
|
||
|
} // 202
|
||
|
}; // 203
|
||
|
// 204
|
||
|
// Migrating reload: reload this page (presumably to pick up a new // 205
|
||
|
// version of the code or assets), but save the program state and // 206
|
||
|
// migrate it over. This function returns immediately. The reload // 207
|
||
|
// will happen at some point in the future once all of the packages // 208
|
||
|
// are ready to migrate. // 209
|
||
|
// // 210
|
||
|
var reloading = false; // 211
|
||
|
Reload._reload = function (options) { // 212
|
||
|
options = options || {}; // 213
|
||
|
// 214
|
||
|
if (reloading) // 215
|
||
|
return; // 216
|
||
|
reloading = true; // 217
|
||
|
// 218
|
||
|
var tryReload = function () { _.defer(function () { // 219
|
||
|
if (Reload._migrate(tryReload, options)) { // 220
|
||
|
// Tell the browser to shut down this VM and make a new one // 221
|
||
|
window.location.reload(); // 222
|
||
|
} // 223
|
||
|
}); }; // 224
|
||
|
// 225
|
||
|
tryReload(); // 226
|
||
|
}; // 227
|
||
|
// 228
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
}).call(this);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
(function () {
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
// //
|
||
|
// packages/reload/deprecated.js //
|
||
|
// //
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Reload functionality used to live on Meteor._reload. Be nice and try not to // 1
|
||
|
// break code that uses it, even though it's internal. // 2
|
||
|
// XXX COMPAT WITH 0.6.4 // 3
|
||
|
Meteor._reload = { // 4
|
||
|
onMigrate: Reload._onMigrate, // 5
|
||
|
migrationData: Reload._migrationData, // 6
|
||
|
reload: Reload._reload // 7
|
||
|
}; // 8
|
||
|
// 9
|
||
|
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
}).call(this);
|
||
|
|
||
|
|
||
|
/* Exports */
|
||
|
if (typeof Package === 'undefined') Package = {};
|
||
|
Package.reload = {
|
||
|
Reload: Reload
|
||
|
};
|
||
|
|
||
|
})();
|