500 lines
10 KiB
JavaScript
500 lines
10 KiB
JavaScript
;(function(window){
|
|
if (window.BX.localStorage) return;
|
|
|
|
var
|
|
BX = window.BX,
|
|
localStorageInstance = null,
|
|
_prefix = null,
|
|
_key = '_bxCurrentKey',
|
|
_support = false;
|
|
|
|
BX.localStorage = function()
|
|
{
|
|
this.keyChanges = {}; // flag to skip self changes in IE
|
|
BX.bind(
|
|
(BX.browser.IsIE() && !BX.browser.IsIE9()) ? document : window, // HATE!
|
|
'storage',
|
|
BX.proxy(this._onchange, this)
|
|
);
|
|
|
|
setInterval(BX.delegate(this._clear, this), 5000);
|
|
};
|
|
|
|
/* localStorage public interface */
|
|
|
|
BX.localStorage.checkBrowser = function()
|
|
{
|
|
return _support;
|
|
};
|
|
|
|
BX.localStorage.set = function(key, value, ttl)
|
|
{
|
|
return BX.localStorage.instance().set(key, value, ttl);
|
|
};
|
|
|
|
BX.localStorage.get = function(key)
|
|
{
|
|
return BX.localStorage.instance().get(key);
|
|
};
|
|
|
|
BX.localStorage.remove = function(key)
|
|
{
|
|
return BX.localStorage.instance().remove(key);
|
|
};
|
|
|
|
BX.localStorage.instance = function()
|
|
{
|
|
if (!localStorageInstance)
|
|
{
|
|
var support = BX.localStorage.checkBrowser();
|
|
if (support == 'native')
|
|
localStorageInstance = new BX.localStorage();
|
|
else if (support == 'ie8')
|
|
localStorageInstance = new BX.localStorageIE8();
|
|
else if (support == 'ie7')
|
|
localStorageInstance = new BX.localStorageIE7();
|
|
else
|
|
{
|
|
localStorageInstance = {
|
|
'set' : BX.DoNothing,
|
|
'get' : function(){return null},
|
|
'remove' : BX.DoNothing
|
|
};
|
|
}
|
|
}
|
|
return localStorageInstance;
|
|
};
|
|
|
|
/* localStorage prototype */
|
|
BX.localStorage.prototype.prefix = function()
|
|
{
|
|
if (!_prefix)
|
|
{
|
|
_prefix = 'bx' + BX.message('USER_ID') + '-' + (BX.message.SITE_ID? BX.message('SITE_ID'): 'admin') + '-';
|
|
}
|
|
|
|
return _prefix;
|
|
};
|
|
|
|
BX.localStorage.prototype._onchange = function(e)
|
|
{
|
|
e = e || window.event;
|
|
|
|
if (!e.key)
|
|
return;
|
|
|
|
if (BX.browser.DetectIeVersion() > 0 && this.keyChanges[e.key])
|
|
{
|
|
this.keyChanges[e.key] = false;
|
|
return;
|
|
}
|
|
|
|
if (!!e.key && e.key.substring(0,this.prefix().length) == this.prefix())
|
|
{
|
|
var d = {
|
|
key: e.key.substring(this.prefix().length, e.key.length),
|
|
value: !!e.newValue? this._decode(e.newValue.substring(11, e.newValue.length)): null,
|
|
oldValue: !!e.oldValue? this._decode(e.oldValue.substring(11, e.oldValue.length)): null
|
|
};
|
|
|
|
switch(d.key)
|
|
{
|
|
case 'BXGCE': // BX Global Custom Event
|
|
if (d.value)
|
|
{
|
|
BX.onCustomEvent(d.value.e, d.value.p);
|
|
}
|
|
break;
|
|
default:
|
|
// normal event handlers
|
|
if (e.newValue)
|
|
BX.onCustomEvent(window, 'onLocalStorageSet', [d]);
|
|
if (e.oldValue && !e.newValue)
|
|
BX.onCustomEvent(window, 'onLocalStorageRemove', [d]);
|
|
|
|
BX.onCustomEvent(window, 'onLocalStorageChange', [d]);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
BX.localStorage.prototype._clear = function()
|
|
{
|
|
var curDate = +new Date(), key, i;
|
|
|
|
for (i=0; i<localStorage.length; i++)
|
|
{
|
|
key = localStorage.key(i);
|
|
if (key.substring(0,2) == 'bx')
|
|
{
|
|
var ttl = localStorage.getItem(key).split(':', 1)*1000;
|
|
if (curDate >= ttl)
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
};
|
|
|
|
BX.localStorage.prototype._encode = function(value)
|
|
{
|
|
if (typeof(value) == 'object')
|
|
value = JSON.stringify(value);
|
|
else
|
|
value = value.toString();
|
|
return value;
|
|
};
|
|
|
|
BX.localStorage.prototype._decode = function(value)
|
|
{
|
|
var answer = null;
|
|
if (!!value)
|
|
{
|
|
try {answer = JSON.parse(value);}
|
|
catch(e) { answer = value; }
|
|
}
|
|
return answer;
|
|
};
|
|
|
|
BX.localStorage.prototype._trigger_error = function(e, key, value, ttl)
|
|
{
|
|
BX.onCustomEvent(this, 'onLocalStorageError', [e, {key: key, value: value, ttl: ttl}]);
|
|
};
|
|
|
|
BX.localStorage.prototype.set = function(key, value, ttl)
|
|
{
|
|
if (!ttl || ttl <= 0)
|
|
ttl = 60;
|
|
|
|
if (key == undefined || key == null || value == undefined)
|
|
return false;
|
|
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
try
|
|
{
|
|
localStorage.setItem(
|
|
this.prefix()+key,
|
|
(Math.round((+new Date())/1000)+ttl)+':'+this._encode(value)
|
|
);
|
|
}
|
|
catch (e)
|
|
{
|
|
this._trigger_error(e, key, value, ttl);
|
|
}
|
|
};
|
|
|
|
BX.localStorage.prototype.get = function(key)
|
|
{
|
|
var storageAnswer = localStorage.getItem(this.prefix()+key);
|
|
|
|
if (storageAnswer)
|
|
{
|
|
var ttl = storageAnswer.split(':', 1)*1000;
|
|
if ((+new Date()) <= ttl)
|
|
{
|
|
storageAnswer = storageAnswer.substring(11, storageAnswer.length);
|
|
return this._decode(storageAnswer);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
BX.localStorage.prototype.remove = function(key)
|
|
{
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
localStorage.removeItem(this.prefix()+key);
|
|
};
|
|
|
|
/************** IE 7 ******************/
|
|
|
|
BX.localStorageIE7 = function()
|
|
{
|
|
this.NS = 'BXLocalStorage';
|
|
this.__current_state = {};
|
|
this.keyChanges = {};
|
|
|
|
BX.ready(BX.delegate(this._Init, this));
|
|
};
|
|
|
|
BX.extend(BX.localStorageIE7, BX.localStorage);
|
|
|
|
BX.localStorageIE7.prototype._Init = function()
|
|
{
|
|
this.storage_element = document.body.appendChild(BX.create('DIV'));
|
|
this.storage_element.addBehavior('#default#userData');
|
|
this.storage_element.load(this.NS);
|
|
|
|
var doc = this.storage_element.xmlDocument,
|
|
len = doc.firstChild.attributes.length;
|
|
|
|
for (var i = 0; i<len; i++)
|
|
{
|
|
if (!!doc.firstChild.attributes[i])
|
|
{
|
|
var k = doc.firstChild.attributes[i].nodeName;
|
|
if (k.substring(0,this.prefix().length) == this.prefix())
|
|
{
|
|
this.__current_state[k] = doc.firstChild.attributes[i].nodeValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
setInterval(BX.delegate(this._Listener, this), 500);
|
|
setInterval(BX.delegate(this._clear, this), 5000);
|
|
};
|
|
|
|
BX.localStorageIE7.prototype._Listener = function(bInit)
|
|
{
|
|
this.storage_element.load(this.NS);
|
|
|
|
var doc = this.storage_element.xmlDocument,
|
|
len = doc.firstChild.attributes.length,
|
|
i,k,v;
|
|
|
|
var new_state = {}, arChanges = [];
|
|
|
|
for (i = 0; i<len; i++)
|
|
{
|
|
if (!!doc.firstChild.attributes[i])
|
|
{
|
|
k = doc.firstChild.attributes[i].nodeName;
|
|
if (k.substring(0,this.prefix().length) == this.prefix())
|
|
{
|
|
v = doc.firstChild.attributes[i].nodeValue;
|
|
|
|
if (this.__current_state[k] != v)
|
|
{
|
|
arChanges.push({
|
|
key: k, newValue: v, oldValue: this.__current_state[k]
|
|
});
|
|
}
|
|
|
|
new_state[k] = v;
|
|
delete this.__current_state[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i in this.__current_state)
|
|
{
|
|
if(this.__current_state.hasOwnProperty(i))
|
|
{
|
|
arChanges.push({
|
|
key: i, newValue: undefined, oldValue: this.__current_state[i]
|
|
});
|
|
}
|
|
}
|
|
|
|
this.__current_state = new_state;
|
|
|
|
for (i=0; i<arChanges.length; i++)
|
|
{
|
|
this._onchange(arChanges[i]);
|
|
}
|
|
};
|
|
|
|
BX.localStorageIE7.prototype._clear = function()
|
|
{
|
|
this.storage_element.load(this.NS);
|
|
|
|
var doc = this.storage_element.xmlDocument,
|
|
len = doc.firstChild.attributes.length,
|
|
curDate = +new Date(),
|
|
i,k,v,ttl;
|
|
|
|
for (i = 0; i<len; i++)
|
|
{
|
|
if (!!doc.firstChild.attributes[i])
|
|
{
|
|
k = doc.firstChild.attributes[i].nodeName;
|
|
if (k.substring(0,2) == 'bx')
|
|
{
|
|
v = doc.firstChild.attributes[i].nodeValue;
|
|
ttl = v.split(':', 1)*1000;
|
|
if (curDate >= ttl)
|
|
{
|
|
doc.firstChild.removeAttribute(k)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.storage_element.save(this.NS);
|
|
};
|
|
|
|
BX.localStorageIE7.prototype.set = function(key, value, ttl)
|
|
{
|
|
if (!ttl || ttl <= 0)
|
|
ttl = 60;
|
|
|
|
try
|
|
{
|
|
this.storage_element.load(this.NS);
|
|
|
|
var doc = this.storage_element.xmlDocument;
|
|
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
|
|
doc.firstChild.setAttribute(
|
|
this.prefix()+key,
|
|
(Math.round((+new Date())/1000)+ttl)+':'+this._encode(value)
|
|
);
|
|
|
|
this.storage_element.save(this.NS);
|
|
}
|
|
catch(e)
|
|
{
|
|
this._trigger_error(e, key, value, ttl);
|
|
}
|
|
};
|
|
|
|
BX.localStorageIE7.prototype.get = function(key)
|
|
{
|
|
this.storage_element.load(this.NS);
|
|
var doc = this.storage_element.xmlDocument;
|
|
|
|
var storageAnswer = doc.firstChild.getAttribute(this.prefix()+key);
|
|
|
|
if (storageAnswer)
|
|
{
|
|
var ttl = storageAnswer.split(':', 1)*1000;
|
|
if ((+new Date()) <= ttl)
|
|
{
|
|
storageAnswer = storageAnswer.substring(11, storageAnswer.length);
|
|
return this._decode(storageAnswer);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
BX.localStorageIE7.prototype.remove = function(key)
|
|
{
|
|
this.storage_element.load(this.NS);
|
|
|
|
var doc = this.storage_element.xmlDocument;
|
|
doc.firstChild.removeAttribute(this.prefix()+key);
|
|
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
this.storage_element.save(this.NS);
|
|
};
|
|
|
|
/************** IE 8 & FF 3.6 ***************/
|
|
|
|
BX.localStorageIE8 = function()
|
|
{
|
|
this.key = _key;
|
|
|
|
this.currentKey = null;
|
|
this.currentValue = null;
|
|
|
|
BX.localStorageIE8.superclass.constructor.apply(this);
|
|
};
|
|
BX.extend(BX.localStorageIE8, BX.localStorage);
|
|
|
|
BX.localStorageIE8.prototype._onchange = function(e)
|
|
{
|
|
if (null == this.currentKey)
|
|
{
|
|
this.currentKey = localStorage.getItem(this.key);
|
|
if (this.currentKey)
|
|
{
|
|
this.currentValue = localStorage.getItem(this.prefix() + this.currentKey);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
e = {
|
|
key: this.prefix() + this.currentKey,
|
|
newValue: localStorage.getItem(this.prefix() + this.currentKey),
|
|
oldValue: this.currentValue
|
|
};
|
|
|
|
this.currentKey = null;
|
|
this.currentValue = null;
|
|
|
|
// especially for FF3.6
|
|
if (this.keyChanges[e.key])
|
|
{
|
|
this.keyChanges[e.key] = false;
|
|
return;
|
|
}
|
|
|
|
BX.localStorageIE8.superclass._onchange.apply(this, [e]);
|
|
}
|
|
};
|
|
|
|
BX.localStorageIE8.prototype.set = function(key, value, ttl)
|
|
{
|
|
this.currentKey = null;
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
|
|
try
|
|
{
|
|
localStorage.setItem(this.key, key);
|
|
BX.localStorageIE8.superclass.set.apply(this, arguments);
|
|
}
|
|
catch(e)
|
|
{
|
|
this._trigger_error(e, key, value, ttl);
|
|
}
|
|
};
|
|
|
|
BX.localStorageIE8.prototype.remove = function(key)
|
|
{
|
|
this.currentKey = null;
|
|
this.keyChanges[this.prefix()+key] = true;
|
|
|
|
localStorage.setItem(this.key, key);
|
|
BX.localStorageIE8.superclass.remove.apply(this, arguments);
|
|
};
|
|
|
|
/* additional functions */
|
|
|
|
BX.onGlobalCustomEvent = function(eventName, arEventParams, bSkipSelf)
|
|
{
|
|
if (!!BX.localStorage.checkBrowser())
|
|
BX.localStorage.set('BXGCE', {e:eventName,p:arEventParams}, 1);
|
|
|
|
if (!bSkipSelf)
|
|
BX.onCustomEvent(eventName, arEventParams);
|
|
};
|
|
|
|
/***************** initialize *********************/
|
|
|
|
try {
|
|
_support = !!localStorage.setItem;
|
|
} catch(e) {}
|
|
|
|
if (_support)
|
|
{
|
|
_support = 'native';
|
|
|
|
// hack to check FF3.6 && IE8
|
|
var _target = (BX.browser.IsIE() && !BX.browser.IsIE9()) ? document : window,
|
|
_checkFFnIE8 = function(e) {
|
|
if (typeof(e||window.event).key == 'undefined')
|
|
_support = 'ie8';
|
|
BX.unbind(_target, 'storage', _checkFFnIE8);
|
|
BX.localStorage.instance();
|
|
};
|
|
BX.bind(_target, 'storage', _checkFFnIE8);
|
|
|
|
try
|
|
{
|
|
localStorage.setItem(_key, null);
|
|
}
|
|
catch(e)
|
|
{
|
|
_support = false;
|
|
BX.localStorage.instance();
|
|
}
|
|
}
|
|
else if (BX.browser.IsIE7())
|
|
{
|
|
_support = 'ie7';
|
|
BX.localStorage.instance();
|
|
}
|
|
|
|
})(window);
|
|
|