1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-18 06:57:52 +00:00
seahub/media/aloha-0.22.7/lib/vendor/amplify.store.js

299 lines
7.5 KiB
JavaScript
Raw Normal View History

define(['util/json2'],function(){
var amplify = {};
/*!
* Amplify Store - Persistent Client-Side Storage 1.1.0
*
* Copyright 2011 appendTo LLC. (http://appendto.com/team)
* Dual licensed under the MIT or GPL licenses.
* http://appendto.com/open-source-licenses
*
* http://amplifyjs.com
*/
(function( amplify, undefined ) {
var store = amplify.store = function( key, value, options, type ) {
var type = store.type;
if ( options && options.type && options.type in store.types ) {
type = options.type;
}
return store.types[ type ]( key, value, options || {} );
};
store.types = {};
store.type = null;
store.addType = function( type, storage ) {
if ( !store.type ) {
store.type = type;
}
store.types[ type ] = storage;
store[ type ] = function( key, value, options ) {
options = options || {};
options.type = type;
return store( key, value, options );
};
}
store.error = function() {
return "amplify.store quota exceeded";
};
var rprefix = /^__amplify__/;
function createFromStorageInterface( storageType, storage ) {
store.addType( storageType, function( key, value, options ) {
var storedValue, parsed, i, remove,
ret = value,
now = (new Date()).getTime();
if ( !key ) {
ret = {};
remove = [];
i = 0;
try {
// accessing the length property works around a localStorage bug
// in Firefox 4.0 where the keys don't update cross-page
// we assign to key just to avoid Closure Compiler from removing
// the access as "useless code"
// https://bugzilla.mozilla.org/show_bug.cgi?id=662511
key = storage.length;
while ( key = storage.key( i++ ) ) {
if ( rprefix.test( key ) ) {
parsed = JSON.parse( storage.getItem( key ) );
if ( parsed.expires && parsed.expires <= now ) {
remove.push( key );
} else {
ret[ key.replace( rprefix, "" ) ] = parsed.data;
}
}
}
while ( key = remove.pop() ) {
storage.removeItem( key );
}
} catch ( error ) {}
return ret;
}
// protect against name collisions with direct storage
key = "__amplify__" + key;
if ( value === undefined ) {
storedValue = storage.getItem( key );
parsed = storedValue ? JSON.parse( storedValue ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
storage.removeItem( key );
} else {
return parsed.data;
}
} else {
if ( value === null ) {
storage.removeItem( key );
} else {
parsed = JSON.stringify({
data: value,
expires: options.expires ? now + options.expires : null
});
try {
storage.setItem( key, parsed );
// quota exceeded
} catch( error ) {
// expire old data and try again
store[ storageType ]();
try {
storage.setItem( key, parsed );
} catch( error ) {
throw store.error();
}
}
}
}
return ret;
});
}
// localStorage + sessionStorage
// IE 8+, Firefox 3.5+, Safari 4+, Chrome 4+, Opera 10.5+, iPhone 2+, Android 2+
for ( var webStorageType in { localStorage: 1, sessionStorage: 1 } ) {
// try/catch for file protocol in Firefox
try {
if ( window[ webStorageType ].getItem ) {
createFromStorageInterface( webStorageType, window[ webStorageType ] );
}
} catch( e ) {}
}
// globalStorage
// non-standard: Firefox 2+
// https://developer.mozilla.org/en/dom/storage#globalStorage
if ( window.globalStorage ) {
// try/catch for file protocol in Firefox
try {
createFromStorageInterface( "globalStorage",
window.globalStorage[ window.location.hostname ] );
// Firefox 2.0 and 3.0 have sessionStorage and globalStorage
// make sure we default to globalStorage
// but don't default to globalStorage in 3.5+ which also has localStorage
if ( store.type === "sessionStorage" ) {
store.type = "globalStorage";
}
} catch( e ) {}
}
// userData
// non-standard: IE 5+
// http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
(function() {
// IE 9 has quirks in userData that are a huge pain
// rather than finding a way to detect these quirks
// we just don't register userData if we have localStorage
if ( store.types.localStorage ) {
return;
}
// append to html instead of body so we can do this from the head
var div = document.createElement( "div" ),
attrKey = "amplify";
div.style.display = "none";
document.getElementsByTagName( "head" )[ 0 ].appendChild( div );
// we can't feature detect userData support
// so just try and see if it fails
// surprisingly, even just adding the behavior isn't enough for a failure
// so we need to load the data as well
try {
div.addBehavior( "#default#userdata" );
div.load( attrKey );
} catch( e ) {
div.parentNode.removeChild( div );
return;
}
store.addType( "userData", function( key, value, options ) {
div.load( attrKey );
var attr, parsed, prevValue, i, remove,
ret = value,
now = (new Date()).getTime();
if ( !key ) {
ret = {};
remove = [];
i = 0;
while ( attr = div.XMLDocument.documentElement.attributes[ i++ ] ) {
parsed = JSON.parse( attr.value );
if ( parsed.expires && parsed.expires <= now ) {
remove.push( attr.name );
} else {
ret[ attr.name ] = parsed.data;
}
}
while ( key = remove.pop() ) {
div.removeAttribute( key );
}
div.save( attrKey );
return ret;
}
// convert invalid characters to dashes
// http://www.w3.org/TR/REC-xml/#NT-Name
// simplified to assume the starting character is valid
// also removed colon as it is invalid in HTML attribute names
key = key.replace( /[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g, "-" );
if ( value === undefined ) {
attr = div.getAttribute( key );
parsed = attr ? JSON.parse( attr ) : { expires: -1 };
if ( parsed.expires && parsed.expires <= now ) {
div.removeAttribute( key );
} else {
return parsed.data;
}
} else {
if ( value === null ) {
div.removeAttribute( key );
} else {
// we need to get the previous value in case we need to rollback
prevValue = div.getAttribute( key );
parsed = JSON.stringify({
data: value,
expires: (options.expires ? (now + options.expires) : null)
});
div.setAttribute( key, parsed );
}
}
try {
div.save( attrKey );
// quota exceeded
} catch ( error ) {
// roll the value back to the previous value
if ( prevValue === null ) {
div.removeAttribute( key );
} else {
div.setAttribute( key, prevValue );
}
// expire old data and try again
store.userData();
try {
div.setAttribute( key, parsed );
div.save( attrKey );
} catch ( error ) {
// roll the value back to the previous value
if ( prevValue === null ) {
div.removeAttribute( key );
} else {
div.setAttribute( key, prevValue );
}
throw store.error();
}
}
return ret;
});
}() );
// in-memory storage
// fallback for all browsers to enable the API even if we can't persist data
(function() {
var memory = {},
timeout = {};
function copy( obj ) {
return obj === undefined ? undefined : JSON.parse( JSON.stringify( obj ) );
}
store.addType( "memory", function( key, value, options ) {
if ( !key ) {
return copy( memory );
}
if ( value === undefined ) {
return copy( memory[ key ] );
}
if ( timeout[ key ] ) {
clearTimeout( timeout[ key ] );
delete timeout[ key ];
}
if ( value === null ) {
delete memory[ key ];
return null;
}
memory[ key ] = value;
if ( options.expires ) {
timeout[ key ] = setTimeout(function() {
delete memory[ key ];
delete timeout[ key ];
}, options.expires );
}
return value;
});
}() );
}( amplify ) );
return amplify;
});