(function(){
|
if( !('ace' in window) ) window['ace'] = {}
|
|
ace.config = {
|
storage_method: 0, //0 means use localStorage if available otherwise cookies, 1 means localStorage, 2 means cookies
|
cookie_expiry : 604800, //(cookie only) 1 week duration for saved settings
|
cookie_path: ''//(cookie only)
|
}
|
if( !('vars' in window['ace']) ) window['ace'].vars = {}
|
ace.vars['very_old_ie'] = !('querySelector' in document.documentElement);
|
|
ace.settings = {
|
saveState : function(element, attrName, attrVal, append) {
|
if( !element || (typeof element == 'string' && !(element = document.getElementById(element))) || !element.hasAttribute('id') ) return false;
|
if( !ace.hasClass(element, 'ace-save-state') ) return false;
|
|
var attrName = attrName || 'class';
|
var id = element.getAttribute('id');
|
|
var attrList = ace.data.get('state', 'id-'+id) || {};
|
if(typeof attrList == 'string') {
|
try {
|
attrList = JSON.parse(attrList);
|
}
|
catch(e) {
|
attrList = {}
|
}
|
}
|
|
var newVal, hasCustomVal = typeof attrVal !== 'undefined', $delete = false;
|
|
var re1 = /class/i
|
var re2 = /checked|disabled|readonly|value/i
|
|
if(re2.test(attrName)) newVal = hasCustomVal ? attrVal : element[attrName];
|
else {
|
if(element.hasAttribute(attrName)) {
|
newVal = hasCustomVal ? attrVal : element.getAttribute(attrName);
|
}
|
else if(!hasCustomVal) $delete = true;
|
//delete this, because element has no such attribute and we haven't given a custom value! (no attrVal)
|
}
|
|
|
if($delete) {
|
delete attrList[attrName];
|
}
|
else {
|
//save class names as an object which indicated which classes should be included or excluded (true/false)
|
if( re1.test(attrName) ) {//class
|
|
|
if( !attrList.hasOwnProperty(attrName) ) attrList[attrName] = {}
|
if(append === true) {
|
//append to previous value
|
attrList[attrName][newVal] = 1;
|
}
|
else if(append === false) {
|
//remove from previous value
|
attrList[attrName][newVal] = -1;
|
}
|
else {
|
attrList[attrName]['className'] = newVal;
|
}
|
}
|
|
else {
|
attrList[attrName] = newVal;
|
}
|
}
|
|
ace.data.set('state', 'id-'+id , JSON.stringify(attrList));
|
},
|
|
loadState : function(element, attrName) {
|
if( !element || (typeof element == 'string' && !(element = document.getElementById(element))) || !element.hasAttribute('id') ) return false;
|
|
var id = element.getAttribute('id');
|
var attrList = ace.data.get('state', 'id-'+id) || {};
|
if(typeof attrList == 'string') {
|
try {
|
attrList = JSON.parse(attrList);
|
}
|
catch(e) {
|
attrList = {}
|
}
|
}
|
|
var setAttr = function(element, attr, val) {
|
var re1 = /class/i
|
var re2 = /checked|disabled|readonly|value/i
|
|
if(re1.test(attr)) {
|
if(typeof val === 'object') {
|
if('className' in val) element.setAttribute('class', val['className']);
|
for(var key in val) if(val.hasOwnProperty(key)) {
|
var append = val[key];
|
if(append == 1) ace.addClass(element, key);
|
else if(append == -1) ace.removeClass(element, key);
|
}
|
}
|
//else if(typeof ace.addClass(element, val);
|
}
|
else if(re2.test(attr)) element[attr] = val;
|
else element.setAttribute(attr, val);
|
}
|
|
if(attrName !== undefined) {
|
if(attrList.hasOwnProperty(attrName) && attrList[attrName] !== null) setAttr(element, attrName, attrList[attrName]);
|
}
|
else {
|
for(var name in attrList) {
|
if(attrList.hasOwnProperty(name) && attrList[name] !== null) setAttr(element, name, attrList[name]);
|
}
|
}
|
},
|
|
clearState : function(element) {
|
var id = null;
|
if(typeof element === 'string') {
|
id = element;
|
}
|
else if('hasAttribute' in element && element.hasAttribute('id')) {
|
id = element.getAttribute('id');
|
}
|
if(id) ace.data.remove('state', 'id-'+id);
|
}
|
};
|
|
|
|
|
(function() {
|
//detect if it is supported
|
//https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Detecting_CSS_animation_support
|
var animationSupport = function() {
|
var animation = false,
|
animationstring = 'animation',
|
keyframeprefix = '',
|
domPrefixes = 'Webkit Moz O ms Khtml'.split(' '),
|
pfx = '',
|
elm = document.createElement('div');
|
|
if( elm.style.animationName !== undefined ) { animation = true; }
|
|
if( animation === false ) {
|
for( var i = 0; i < domPrefixes.length; i++ ) {
|
if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
|
pfx = domPrefixes[ i ];
|
animationstring = pfx + 'Animation';
|
keyframeprefix = '-' + pfx.toLowerCase() + '-';
|
animation = true;
|
break;
|
}
|
}
|
}
|
|
return animation;
|
}
|
|
ace.vars['animation'] = animationSupport();
|
if( ace.vars['animation'] ) {
|
//based on http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
|
|
var animationCSS = "@keyframes nodeInserted{from{outline-color:#fff}to{outline-color:#000}}@-moz-keyframes nodeInserted{from{outline-color:#fff}to{outline-color:#000}}@-webkit-keyframes nodeInserted{from{outline-color:#fff}to{outline-color:#000}}@-ms-keyframes nodeInserted{from{outline-color:#fff}to{outline-color:#000}}@-o-keyframes nodeInserted{from{outline-color:#fff}to{outline-color:#000}}.ace-save-state{animation-duration:10ms;-o-animation-duration:10ms;-ms-animation-duration:10ms;-moz-animation-duration:10ms;-webkit-animation-duration:10ms;animation-delay:0s;-o-animation-delay:0s;-ms-animation-delay:0s;-moz-animation-delay:0s;-webkit-animation-delay:0s;animation-name:nodeInserted;-o-animation-name:nodeInserted;-ms-animation-name:nodeInserted;-moz-animation-name:nodeInserted;-webkit-animation-name:nodeInserted}";
|
var animationNode = document.createElement('style');
|
animationNode.innerHTML = animationCSS;
|
document.head.appendChild(animationNode);
|
|
var domInsertEvent = function(event) {
|
var element = event.target;
|
if( !element || !ace.hasClass(element, 'ace-save-state') ) return;
|
|
ace.settings.loadState(element);
|
}
|
|
document.addEventListener('animationstart', domInsertEvent, false);
|
document.addEventListener('MSAnimationStart', domInsertEvent, false);
|
document.addEventListener('webkitAnimationStart', domInsertEvent, false);
|
}
|
else {
|
//if animation events are not supported, wait for document ready event
|
var documentReady = function() {
|
var list = document.querySelectorAll('.ace-save-state');
|
for(var i = 0 ; i < list.length ; i++) ace.settings.loadState(list[i]);
|
}
|
|
if(document.readyState == 'complete') documentReady();
|
else if(document.addEventListener) document.addEventListener('DOMContentLoaded', documentReady, false);
|
else if(document.attachEvent) document.attachEvent('onreadystatechange', function(){
|
if (document.readyState == 'complete') documentReady();
|
});
|
}
|
})();
|
|
|
|
|
|
|
//save/retrieve data using localStorage or cookie
|
//method == 1, use localStorage
|
//method == 2, use cookies
|
//method not specified, use localStorage if available, otherwise cookies
|
ace.data_storage = function(method, undefined) {
|
var prefix = 'ace_';
|
|
var storage = null;
|
var type = 0;
|
|
if((method == 1 || method === undefined || method == 0) && 'localStorage' in window && window['localStorage'] !== null) {
|
storage = ace.storage;
|
type = 1;
|
}
|
else if(storage == null && (method == 2 || method === undefined) && 'cookie' in document && document['cookie'] !== null) {
|
storage = ace.cookie;
|
type = 2;
|
}
|
|
|
this.set = function(namespace, key, value, path, is_obj, undefined) {
|
if(!storage) return;
|
|
if(value === undefined) {//no namespace here?
|
value = key;
|
key = namespace;
|
|
if(value == null) storage.remove(prefix+key)
|
else {
|
if(type == 1)
|
storage.set(prefix+key, value)
|
else if(type == 2)
|
storage.set(prefix+key, value, ace.config.cookie_expiry, path || ace.config.cookie_path)
|
}
|
}
|
else {
|
if(type == 1) {//localStorage
|
if(value == null) storage.remove(prefix+namespace+'_'+key)
|
else {
|
if(is_obj && typeof value == 'object') {
|
value = JSON.stringify(value);
|
}
|
storage.set(prefix+namespace+'_'+key, value);
|
}
|
}
|
else if(type == 2) {//cookie
|
var val = storage.get(prefix+namespace);
|
var tmp = val ? JSON.parse(val) : {};
|
|
if(value == null) {
|
delete tmp[key];//remove
|
if(ace.sizeof(tmp) == 0) {//no other elements in this cookie, so delete it
|
storage.remove(prefix+namespace);
|
return;
|
}
|
}
|
|
else {
|
tmp[key] = value;
|
}
|
|
storage.set(prefix+namespace , JSON.stringify(tmp), ace.config.cookie_expiry, path || ace.config.cookie_path)
|
}
|
}
|
}
|
|
this.get = function(namespace, key, is_obj, undefined) {
|
if(!storage) return null;
|
|
if(key === undefined) {//no namespace here?
|
key = namespace;
|
return storage.get(prefix+key);
|
}
|
else {
|
if(type == 1) {//localStorage
|
var value = storage.get(prefix+namespace+'_'+key);
|
if(is_obj && value) {
|
try { value = JSON.parse(value) } catch(e) {}
|
}
|
return value;
|
}
|
else if(type == 2) {//cookie
|
var val = storage.get(prefix+namespace);
|
var tmp = val ? JSON.parse(val) : {};
|
return key in tmp ? tmp[key] : null;
|
}
|
}
|
}
|
|
|
this.remove = function(namespace, key, undefined) {
|
if(!storage) return;
|
|
if(key === undefined) {
|
key = namespace
|
this.set(key, null);
|
}
|
else {
|
this.set(namespace, key, null);
|
}
|
}
|
}
|
|
|
|
|
|
//cookie storage
|
ace.cookie = {
|
// The following settingFunction are from Cookie.js class in TinyMCE, Moxiecode, used under LGPL.
|
|
/**
|
* Get a cookie.
|
*/
|
get : function(name) {
|
var cookie = document.cookie, e, p = name + "=", b;
|
|
if ( !cookie )
|
return;
|
|
b = cookie.indexOf("; " + p);
|
|
if ( b == -1 ) {
|
b = cookie.indexOf(p);
|
|
if ( b != 0 )
|
return null;
|
|
} else {
|
b += 2;
|
}
|
|
e = cookie.indexOf(";", b);
|
|
if ( e == -1 )
|
e = cookie.length;
|
|
return decodeURIComponent( cookie.substring(b + p.length, e) );
|
},
|
|
/**
|
* Set a cookie.
|
*
|
* The 'expires' arg can be either a JS Date() object set to the expiration date (back-compat)
|
* or the number of seconds until expiration
|
*/
|
set : function(name, value, expires, path, domain, secure) {
|
var d = new Date();
|
|
if ( typeof(expires) == 'object' && expires.toGMTString ) {
|
expires = expires.toGMTString();
|
} else if ( parseInt(expires, 10) ) {
|
d.setTime( d.getTime() + ( parseInt(expires, 10) * 1000 ) ); // time must be in miliseconds
|
expires = d.toGMTString();
|
} else {
|
expires = '';
|
}
|
|
document.cookie = name + "=" + encodeURIComponent(value) +
|
((expires) ? "; expires=" + expires : "") +
|
((path) ? "; path=" + path : "") +
|
((domain) ? "; domain=" + domain : "") +
|
((secure) ? "; secure" : "");
|
},
|
|
/**
|
* Remove a cookie.
|
*
|
* This is done by setting it to an empty value and setting the expiration time in the past.
|
*/
|
remove : function(name, path) {
|
this.set(name, '', -1000, path);
|
}
|
};
|
|
|
//local storage
|
ace.storage = {
|
get: function(key) {
|
return window['localStorage'].getItem(key);
|
},
|
set: function(key, value) {
|
window['localStorage'].setItem(key , value);
|
},
|
remove: function(key) {
|
window['localStorage'].removeItem(key);
|
}
|
};
|
|
|
|
|
|
|
//count the number of properties in an object
|
//useful for getting the number of elements in an associative array
|
ace.sizeof = function(obj) {
|
var size = 0;
|
for(var key in obj) if(obj.hasOwnProperty(key)) size++;
|
return size;
|
}
|
|
//because jQuery may not be loaded at this stage, we use our own toggleClass
|
ace.hasClass = function(elem, className) { return (" " + elem.className + " ").indexOf(" " + className + " ") > -1; }
|
|
ace.addClass = function(elem, className) {
|
var parts = className.split(/\s+/);
|
for(var p = 0; p < parts.length; p++) {
|
if ( parts[p].length > 0 && !ace.hasClass(elem, parts[p]) ) {
|
var currentClass = elem.className;
|
elem.className = currentClass + (currentClass.length ? " " : "") + parts[p];
|
}
|
}
|
}
|
|
ace.removeClass = function(elem, className) {
|
var parts = className.split(/\s+/);
|
for(var p = 0; p < parts.length; p++) {
|
if( parts[p].length > 0 ) ace.replaceClass(elem, parts[p]);
|
}
|
ace.replaceClass(elem, className);
|
}
|
|
ace.replaceClass = function(elem, className, newClass) {
|
var classToRemove = new RegExp(("(^|\\s)" + className + "(\\s|$)"), "i");
|
elem.className = elem.className.replace(classToRemove, function (match, p1, p2) {
|
return newClass ? (p1 + newClass + p2) : " ";
|
}).replace(/^\s+|\s+$/g, "");
|
}
|
|
|
ace.toggleClass = function(elem, className) {
|
if(ace.hasClass(elem, className))
|
ace.removeClass(elem, className);
|
else ace.addClass(elem, className);
|
}
|
|
ace.isHTMlElement = function(elem) {
|
return window.HTMLElement ? elem instanceof HTMLElement : ('nodeType' in elem ? elem.nodeType == 1 : false);
|
}
|
|
|
//data_storage instance used inside ace.settings etc
|
ace.data = new ace.data_storage(ace.config.storage_method);
|
|
})();
|