216 строки
6.1 KiB
JavaScript
216 строки
6.1 KiB
JavaScript
|
/* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is Raindrop.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* Mozilla Messaging, Inc..
|
||
|
* Portions created by the Initial Developer are Copyright (C) 2009
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
* */
|
||
|
|
||
|
/*jslint indent: 2 */
|
||
|
/*global require: false, define: false, window: false, location: true,
|
||
|
localStorage: false, opener: false, setTimeout: false */
|
||
|
'use strict';
|
||
|
|
||
|
define([ 'storage', 'dispatch', 'rdapi'],
|
||
|
function (storage, dispatch, rdapi) {
|
||
|
|
||
|
var store = storage(), impl,
|
||
|
changeTypes = {
|
||
|
//localStorage is the most robust, since the change in localStorage
|
||
|
//can be listened to across windows.
|
||
|
|
||
|
'localStorage': {
|
||
|
|
||
|
accounts: function (ok, error) {
|
||
|
var accountCache = store.accountCache,
|
||
|
lastCheck = store.lastAccountCheck || 0,
|
||
|
currentTime = (new Date()).getTime(),
|
||
|
fetch = false;
|
||
|
|
||
|
if (!accountCache || (currentTime - lastCheck) > 3000) {
|
||
|
fetch = true;
|
||
|
}
|
||
|
|
||
|
//Set up accountCache as a real object.
|
||
|
if (accountCache) {
|
||
|
accountCache = JSON.parse(accountCache);
|
||
|
} else {
|
||
|
accountCache = [];
|
||
|
}
|
||
|
|
||
|
//Call ok callback with current knowledge. If there is a change in the
|
||
|
//account info, then the fetch will trigger changed event later.
|
||
|
if (ok) {
|
||
|
ok(accountCache);
|
||
|
}
|
||
|
|
||
|
if (fetch) {
|
||
|
impl.fetch(null, error);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
fetch: function (ok, error) {
|
||
|
rdapi('account/get', {
|
||
|
success: function (json) {
|
||
|
if (json.error) {
|
||
|
json = [];
|
||
|
}
|
||
|
|
||
|
store.lastAccountCheck = (new Date()).getTime();
|
||
|
|
||
|
if (ok) {
|
||
|
ok(json);
|
||
|
}
|
||
|
|
||
|
//Check for changes, and if so, then trigger accounts changed.
|
||
|
var accountCache = store.accountCache, same;
|
||
|
|
||
|
accountCache = accountCache ? JSON.parse(accountCache) : [];
|
||
|
same = json.length === accountCache.length;
|
||
|
|
||
|
if (same) {
|
||
|
same = !json.some(function (account, i) {
|
||
|
return account.identifier !== accountCache[i].identifier;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
if (!same) {
|
||
|
store.accountCache = JSON.stringify(json);
|
||
|
impl.changed();
|
||
|
}
|
||
|
},
|
||
|
error: error || function () {}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
changed: function () {
|
||
|
store.accountChanged = (new Date()).getTime();
|
||
|
//Force the onchange events to occur. Sometimes the storage
|
||
|
//events do not fire?
|
||
|
if (opener && !opener.closed) {
|
||
|
dispatch.pub('accountsChanged', null, opener);
|
||
|
}
|
||
|
dispatch.pub('accountsChanged');
|
||
|
},
|
||
|
|
||
|
onChange: function (action) {
|
||
|
//Listen to storage changes, and if a the accountChanged key
|
||
|
//changes, refresh.
|
||
|
var lastValue = store.accountChanged;
|
||
|
window.addEventListener('storage', function (evt) {
|
||
|
//Only refresh if the accounts were changed.
|
||
|
if (store.accountChanged !== lastValue) {
|
||
|
action();
|
||
|
}
|
||
|
}, false);
|
||
|
//Also use direct notification in case storage events fail.
|
||
|
dispatch.sub('accountsChanged', action);
|
||
|
}
|
||
|
},
|
||
|
//Some extensions mess with localStorage, so in that case, fall back to
|
||
|
//using dispatching.
|
||
|
'memory': {
|
||
|
|
||
|
accounts: function (ok, error) {
|
||
|
impl.fetch(ok, error);
|
||
|
},
|
||
|
|
||
|
fetch: function (ok, error) {
|
||
|
rdapi('account/get', {
|
||
|
success: function (json) {
|
||
|
if (json.error) {
|
||
|
json = [];
|
||
|
}
|
||
|
if (ok) {
|
||
|
ok(json);
|
||
|
}
|
||
|
},
|
||
|
error: error || function () {}
|
||
|
});
|
||
|
},
|
||
|
|
||
|
changed: function () {
|
||
|
//Use dispatching. Dispatch to current window, but also to an opener
|
||
|
//if available.
|
||
|
store.accountChanged = (new Date()).getTime();
|
||
|
|
||
|
if (opener) {
|
||
|
dispatch.pub('accountsChanged', null, opener);
|
||
|
}
|
||
|
dispatch.pub('accountsChanged');
|
||
|
},
|
||
|
|
||
|
onChange: function (action) {
|
||
|
dispatch.sub('accountsChanged', action);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
impl = changeTypes[storage.type];
|
||
|
|
||
|
/**
|
||
|
* Gets the accounts. Can use a cached value.
|
||
|
* @param {Function} ok function to receive the account info.
|
||
|
* @param {Function} error function to call if an error.
|
||
|
*/
|
||
|
function accounts(ok, error) {
|
||
|
return impl.accounts(ok, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets the accounts. Forces a call to the server.
|
||
|
* @param {Function} ok function to receive the account info.
|
||
|
* @param {Function} error function to call if an error.
|
||
|
*/
|
||
|
accounts.fetch = function (ok, error) {
|
||
|
impl.fetch(ok, error);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Clears the account data. Use this when it is known that the server
|
||
|
* info is no longer valid/expired.
|
||
|
*/
|
||
|
accounts.clear = function () {
|
||
|
delete store.accountCache;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Called when the cache of accounts has changed.
|
||
|
*/
|
||
|
accounts.changed = function () {
|
||
|
return impl.changed();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Default action is to just reload.
|
||
|
*/
|
||
|
function defaultAction() {
|
||
|
location.reload();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called to set up the action when accounts change.
|
||
|
* Call it with no args to get the default behavior, page reload.
|
||
|
*/
|
||
|
accounts.onChange = function (action) {
|
||
|
return impl.onChange(action || defaultAction);
|
||
|
};
|
||
|
|
||
|
return accounts;
|
||
|
});
|