amend setting current tab + prepend + attrsync + varset & varsync

This commit is contained in:
a-Sansara 2015-12-28 18:45:07 +01:00
parent dfc6a08200
commit a2382c0a5a
5 changed files with 213 additions and 24 deletions

View File

@ -2,7 +2,12 @@
Manage commnunication between browser tabs. Manage commnunication between browser tabs.
this js lib can perform several actions on browser tabs like : this js lib can perform several actions on browser tabs like :
- (*new) search and kill zombies tabs (enable onload by default) - (*new) varset - set a stringifiable object on tabs
- (*new) varsync - synchro a object previously set with varset on an other tab
- (*new) prepend node
- (*new) synchro node attributes
- define custom before and after command functions
- search and kill zombies tabs (enable onload by default)
- append/rewrite/synchro node on all (other) tabs or a specific tab (and possibly on specific frame context) eventually with callback. - append/rewrite/synchro node on all (other) tabs or a specific tab (and possibly on specific frame context) eventually with callback.
- reload all tabs or a specific tab with specified url or tab 's current url - reload all tabs or a specific tab with specified url or tab 's current url
- perform your custom actions on all tabs or specific tab - perform your custom actions on all tabs or specific tab
@ -44,6 +49,15 @@
// perform a node synchro to specified browser tab on specific frame with callback // perform a node synchro to specified browser tab on specific frame with callback
$bt.sync('#test', 'frameName', 'callbackname', '1449974562012'); $bt.sync('#test', 'frameName', 'callbackname', '1449974562012');
// perform a node attr synchro to all browser tab
$bt.attr('#test', ['class', 'title']);
// perform a varset to all tabs
$bt.varset('myVar', { toto : tutu : { tata : "titi" }});
// perform a varsync from specific tab (for example after calling tab will reload)
$bt.varsync('myVar', '1449974562012');
// reload other browser tabs // reload other browser tabs
$bt.reload(); $bt.reload();

View File

@ -13,6 +13,7 @@
h2 { margin:5px 0 0 0; } h2 { margin:5px 0 0 0; }
textarea { padding:8px 5px; border-radius:10px; border-style:solid; width:100%; height:120px; font-size:1.2rem; } textarea { padding:8px 5px; border-radius:10px; border-style:solid; width:100%; height:120px; font-size:1.2rem; }
#test { margin:20px; background-color:white; padding:20px; border: 1px dashed #aaa; } #test { margin:20px; background-color:white; padding:20px; border: 1px dashed #aaa; }
.syncAttrName { color:#990000; }
</style> </style>
</head> </head>
<body> <body>
@ -21,17 +22,25 @@
<div> <div>
<p> Manage commnunication between browser tabs.</p> <p> Manage commnunication between browser tabs.</p>
<p> this js lib can perform several actions on browser tabs like :<br/> <p> this js lib can perform several actions on browser tabs like :<br/>
<ul><li>append/rewrite/synchro node on all (other) tabs or a specific tab (and possibly on specific frame context) eventually with callback.</li> <ul><li>append/rewrite/synchro node content on all (other) tabs or a specific tab (and possibly on specific frame context) eventually with callback.</li>
<li>reload all tabs or a specific tab with specified url or tab 's current url</li> <li>reload all tabs or a specific tab with specified url or tab 's current url</li>
<li>perform your custom actions on all tabs or specific tab</li> <li>perform your custom actions on all tabs or specific tab</li>
<li>kill zombies tabs onload</li> <li>kill zombies tabs onload</li>
<li>(*new) define custom before and after command functions</li> <li>define custom before and after command functions</li>
<li>(*new) sync node attributes</li>
<li>(*new) prepend node content</li>
<li>(*new) varset - set a stringifiable object on tabs</li>
<li>(*new) varsync - synchro a object previously set with varset on an other tab</li>
</ul> </ul>
</p> </p>
<h3>Static actions</h3> <h3>Static actions</h3>
<button class="cmd-sta-prepend" title="$bt.prepend('#test', '<b>it\'s cool to prepend</b><br/>');">static dom prepend</button>
<button class="cmd-sta-append" title="$bt.append('#test', '<b>it\'s cool to append</b><br/>');">static dom append</button> <button class="cmd-sta-append" title="$bt.append('#test', '<b>it\'s cool to append</b><br/>');">static dom append</button>
<button class="cmd-sta-html" title="$bt.html('#test', '<b>it\'s cool to rewrite</b><br/>')">static dom html</button> <button class="cmd-sta-html" title="$bt.html('#test', '<b>it\'s cool to rewrite</b><br/>')">static dom html</button>
<button class="cmd-zombkill" title="">cmd zombkill</button> <button class="cmd-zombkill" title="">cmd zombkill</button>
<button class="cmd-varset">cmd varset</button>
<button class="cmd-varget">varget</button>
<button class="cmd-varsync">varsync</button>
<h3>Dynamic actions</h3> <h3>Dynamic actions</h3>
enter txt or html : <br/> enter txt or html : <br/>
@ -42,6 +51,7 @@ enter txt or html : <br/>
<button class="cmd-html">dom html</button> <button class="cmd-html">dom html</button>
<button class="cmd-html">dom html with before</button> <button class="cmd-html">dom html with before</button>
<button class="cmd-sync">dom sync</button> <button class="cmd-sync">dom sync</button>
<button class="cmd-attr">dom attr sync</button>
<button class="cmd-tarsync">target dom sync</button> <button class="cmd-tarsync">target dom sync</button>
<button class="cmd-reload">tab reload</button> <button class="cmd-reload">tab reload</button>
<button class="cmd-custom">custom cmd</button> <button class="cmd-custom">custom cmd</button>
@ -65,6 +75,7 @@ $bt.on = function(cmd) {
break; break;
} }
} }
$bt.vars['myVar'] = "start";
// //
$(document).ready(function() { $(document).ready(function() {
$bt.init(function() { $bt.init(function() {
@ -113,9 +124,53 @@ $(document).ready(function() {
$('.cmd-tarsync').on('click', function(){ $('.cmd-tarsync').on('click', function(){
$bt.sync('#test'); $bt.sync('#test');
}); });
$('.cmd-attr').on('click', function(){
$(this).toggle('syncAttrName');
$(this).attr('title', 'i have '+($(this).hasClass('syncAttrName') ? '' : 'not ')+' the class syncAttrName');
$bt.attr('.cmd-attr', ['class', 'title']);
});
$('.cmd-sta-append').on('click', function(){ $('.cmd-sta-append').on('click', function(){
eval(this.title); eval(this.title);
}); });
$('.cmd-sta-prepend').on('click', function(){
eval(this.title);
});
$('.cmd-varset').on('click', function(){
var obj = {
toto : {
titi : {
tutu : 'cool',
tata : ['one', 2, 'three']
}
}
}
console.log(obj);
$('#test').html("varset : myVar<br/>json value : <br/>"+$j.str(obj));
$bt.varset('myVar', obj);
});
$('.cmd-varget').on('click', function(){
if (!$.isNone($bt.vars['myVar'])) {
$('#test').html("varget : myVar<br/>json value : <br/>"+$j.str($bt.vars['myVar']));
}
else {
$('#test').html("varget : myVar<br/>undefined");
$('#test').html("clic on varsync to sync myVar");
}
});
$('.cmd-varsync').on('click', function(){
if ($bt.list.length > 1) {
$bt.varsync('myVar', null, $bt.list[0] == $bt.id ? $bt.list[1] : $bt.list[0]);
if (!$.isNone($bt.vars['myVar'])) {
$('#test').html("varget : myVar<br/>json value : <br/>"+$j.str($bt.vars['myVar']));
}
else {
$('#test').html("varget : myVar<br/>undefined");
}
}
else {
$('#test').html("need one more tab to perform a bt varsync");
}
});
$('.cmd-sta-html').on('click', function(){ $('.cmd-sta-html').on('click', function(){
eval(this.title); eval(this.title);
}); });

2
src/bt-min.js vendored

File diff suppressed because one or more lines are too long

138
src/bt.js
View File

@ -3,7 +3,7 @@
* @contributors : * @contributors :
* @copyright : pluie.org * @copyright : pluie.org
* @date : 2015-12-10 22:22:34 * @date : 2015-12-10 22:22:34
* @version : 0.7 * @version : 0.8
* @license : MIT * @license : MIT
* @require : html5 localStorage svan (small vanilla jquery-like lib) * @require : html5 localStorage svan (small vanilla jquery-like lib)
* @desc : manage communication between browser tabs * @desc : manage communication between browser tabs
@ -45,6 +45,15 @@
* // perform a node synchro to specified browser tab on specific frame with callback * // perform a node synchro to specified browser tab on specific frame with callback
* $bt.sync('#test', 'frameName', 'callbackname', '1449974562012'); * $bt.sync('#test', 'frameName', 'callbackname', '1449974562012');
* *
* // perform a node attr synchro to all browser tab
* $bt.attr('#test', ['class', 'title']);
*
* // perform a varset to all tabs
* $bt.varset('myVar', { toto : tutu : { tata : "titi" }});
*
* // perform a varsync from specific tab (for example after calling tab will reload)
* $bt.varsync('myVar', '1449974562012');
*
* // reload other browser tabs * // reload other browser tabs
* $bt.reload(); * $bt.reload();
* *
@ -117,7 +126,7 @@ var $j = (function alias() {
}()); }());
var $bt = { var $bt = {
VERSION : 0.7, VERSION : 0.8,
TRACE : true && !$.isNone(console), TRACE : true && !$.isNone(console),
/*! @constant LS_TABS localStorage key for browsertabs list */ /*! @constant LS_TABS localStorage key for browsertabs list */
LS_TABS : 'bt.list', LS_TABS : 'bt.list',
@ -128,11 +137,15 @@ var $bt = {
/*! @constant CMD_SYNC internal command to perform a browser tab synchro */ /*! @constant CMD_SYNC internal command to perform a browser tab synchro */
CMD_SYNC : 'bt.sync', CMD_SYNC : 'bt.sync',
/*! @constant CMD_VAR_SET internal command to perform a browser tab var set */ /*! @constant CMD_VAR_SET internal command to perform a browser tab var set */
CMD_VAR_SET : 'bt.set', CMD_VAR_SET : 'bt.varset',
/*! @constant CMD_VAR_GET internal command to perform a browser tab var get */ /*! @constant CMD_VAR_SYNC internal command to perform a browser tab var sync */
CMD_VAR_GET : 'bt.get', CMD_VAR_SYNC : 'bt.varsync',
/*! @constant CMD_ATTR_SYNC internal command to perform a dom sync attribute */
CMD_ATTR_SYNC: 'bt.attr',
/*! @constant CMD_APPEND internal command to perform a dom append */ /*! @constant CMD_APPEND internal command to perform a dom append */
CMD_APPEND : 'bt.dom.append', CMD_APPEND : 'bt.dom.append',
/*! @constant CMD_PREPEND internal command to perform a dom append */
CMD_PREPEND : 'bt.dom.prepend',
/*! @constant CMD_HTML internal command to perform a dom html */ /*! @constant CMD_HTML internal command to perform a dom html */
CMD_HTML : 'bt.dom.rewrite', CMD_HTML : 'bt.dom.rewrite',
/*! @constant CMD_RELOAD internal command to perform a browser tab reload */ /*! @constant CMD_RELOAD internal command to perform a browser tab reload */
@ -215,6 +228,19 @@ var $bt = {
append : function(selector, data, ctx, callback, btid) { append : function(selector, data, ctx, callback, btid) {
this._dom(this.CMD_APPEND, ctx, selector, data, callback, btid); this._dom(this.CMD_APPEND, ctx, selector, data, callback, btid);
}, },
/*!
* @desc perform a dom prepend command on other tabs
* @public
* @method append
* @param string selector the selector wich target the node(s)
* @param string data the data to append
* @param string ctx context name of selector (frame name relative to document wich match specified selector) or if not defined or null current document
* @param string callback callback name to fire on command
* @param int btid target browser tab id (if not defined all target all tabs)
*/
prepend : function(selector, data, ctx, callback, btid) {
this._dom(this.CMD_PREPEND, ctx, selector, data, callback, btid);
},
/*! /*!
* @desc perform a dom html command on other tabs * @desc perform a dom html command on other tabs
* @public * @public
@ -296,6 +322,55 @@ var $bt = {
if ($.isFunc(callback)) callback(); if ($.isFunc(callback)) callback();
}, !timeout ? $bt.zombTimeout : timeout); }, !timeout ? $bt.zombTimeout : timeout);
}, },
/*!
* @desc perform a var set command on other tabs
* @public
* @method varset
* @param string varName the var identifier
* @param object data the data object (wich need to be stringifiable via json)
* @param string callback callback name to fire on command
* @param int btid target browser tab id (if not defined all target all tabs)
*/
varset : function(varName, data, callback, btid) {
try {
var djson = $j.str(data);
$bt.vars[varName] = data;
$bt.send({ name : $bt.CMD_VAR_SET, varName : varName, data : djson, callback : callback, to : !btid ? '*' : btid });
}
catch(e) {
console.log(e);
}
},
/*!
* @desc perform a var sync command on specified tab
* @public
* @method varset
* @param string varName the var identifier
* @param string callback callback name to fire on command
* @param int fromId target browser tab id (must be defined and uniq)
*/
varsync : function(varName, callback, toId) {
$bt.send({ name : $bt.CMD_VAR_SYNC, varName : varName, data : '', callback : callback, to : toId });
},
/*!
* @desc perform a dom attribute synchro command on other tabs
* @public
* @method sync
* @param string selector the selector wich target the node(s) to synchro
* @param string|[string] attrName attribute name to sync
* @param string ctx context name of selector (frame name relative to document wich match specified selector) or if not defined or null current document
* @param string callback callback name to fire on command
* @param int btid target browser tab id (if not defined all target all tabs)
*/
attr : function(selector, attrName, ctx, callback, btid) {
var context = !ctx ? document : window.parent.frames[ctx].document;
if ($.isStr(attrName)) attrName = [ attrName ];
var data = [];
attrName.forEach(function (attr, index) {
data.push(attr != "disabled" ? $(selector, context).attr(attr) : $(selector, context).first().disabled);
});
$bt.send({ name : $bt.CMD_ATTR_SYNC, attr : attrName, selector : selector, data : data, context : ctx, callback : callback, to : !btid ? '*' : btid });
},
_dontkill : function(askid, id) { _dontkill : function(askid, id) {
$bt.send({ name : $bt.CMD_DONTKILL, askid : askid, to : id }); $bt.send({ name : $bt.CMD_DONTKILL, askid : askid, to : id });
}, },
@ -317,7 +392,8 @@ var $bt = {
_init : function(fn) { _init : function(fn) {
$(window).on('beforeunload', $bt._unload); $(window).on('beforeunload', $bt._unload);
$(window).on('storage', $bt._cmd); $(window).on('storage', $bt._cmd);
$(window).on('focus', $bt._focus); $bt._defHandlerCurrentTab();
// $(window).on('focus', $bt._focus); replace by _defHandlerCurrentTab to fix frame context
$bt.id = (new Date).getTime(); $bt.id = (new Date).getTime();
var t = $l.get($bt.LS_TABS); var t = $l.get($bt.LS_TABS);
$bt.list = t==null ? [] : $j.obj(t); $bt.list = t==null ? [] : $j.obj(t);
@ -331,6 +407,27 @@ var $bt = {
} }
}, },
/*! @private */ /*! @private */
_defHandlerCurrentTab : function() {
var evcVal = "hidden";
var evcType = "visibilitychange";
if (!$.isNone(document.mozHidden)) {
evcVal = "mozHidden";
evcType = "mozvisibilitychange";
} else if (!$.isNone(document.msHidden)) {
evcVal = "msHidden";
evcType = "msvisibilitychange";
} else if (!$.isNone(document.webkitHidden)) {
evcVal = "webkitHidden";
evcType = "webkitvisibilitychange";
}
$(window).on(evcType, function() {
if (!document[evcVal]) {
$bt.log('SET CURRENT TAB : '+$bt.id);
$l.set($bt.LS_CURTAB, $bt.id);
}
}, false);
},
/*! @private */
_dom : function(n, c, s, d, cb, id) { _dom : function(n, c, s, d, cb, id) {
$bt.send({ name : n, context : c, selector : s, data : d, callback : cb, to : !id ? '*' : id }); $bt.send({ name : n, context : c, selector : s, data : d, callback : cb, to : !id ? '*' : id });
}, },
@ -343,9 +440,9 @@ var $bt = {
return null; return null;
}, },
/*! @private */ /*! @private */
_focus : function(e) { //~ _focus : function(e) {
$l.set($bt.LS_CURTAB, $bt.id); //~ $l.set($bt.LS_CURTAB, $bt.id);
}, //~ },
/*! @private */ /*! @private */
_cmd : function(e) { _cmd : function(e) {
if (!$.isNone(e.originalEvent)) e = e.originalEvent; if (!$.isNone(e.originalEvent)) e = e.originalEvent;
@ -380,6 +477,10 @@ var $bt = {
$(cmd.selector, cmd.context).html(cmd.data); $(cmd.selector, cmd.context).html(cmd.data);
break; break;
case $bt.CMD_PREPEND :
$(cmd.selector, cmd.context).prepend(cmd.data);
break;
case $bt.CMD_RELOAD : case $bt.CMD_RELOAD :
window.location = !$.isNone(cmd.url) ? cmd.url : window.location; window.location = !$.isNone(cmd.url) ? cmd.url : window.location;
break; break;
@ -394,6 +495,25 @@ var $bt = {
$bt.zomblist[''+cmd.askid]['ping'+cmd.from] = 'pong'; $bt.zomblist[''+cmd.askid]['ping'+cmd.from] = 'pong';
break; break;
case $bt.CMD_VAR_SET :
$bt.vars[cmd.varName] = cmd.data;
break;
case $bt.CMD_VAR_SYNC :
$bt.varset(cmd.varName, $bt.vars[cmd.varName]);
break;
case $bt.CMD_ATTR_SYNC :
cmd.attr.forEach(function(attr, index) {
if (cmd.attr != "disabled") {
$(cmd.selector, cmd.context).attr(attr, cmd.data[index]);
}
else {
$(cmd.selector, cmd.context).first().disabled = cmd.data[index];
}
});
break;
default : default :
// do your stuff here // do your stuff here
if ($.isFunc($bt.on)) $bt.on(cmd); if ($.isFunc($bt.on)) $bt.on(cmd);

2
src/svan-min.js vendored
View File

@ -1 +1 @@
/* by a-sansara - v 0.4 - https://github.com/pluie-org/svan */!function(){var t=function(t,n){return typeof t==n},n=function(t,i){return new n.init(t,i)},i=n.isNone=function(n){return t(n,"undefined")},e=n.isStr=function(n){return t(n,"string")},s=n.isFunc=function(n){return t(n,"function")},o=n.isObj=function(n){return t(n,"object")},a=n.isNode=function(t){return o(t)&&!i(t.nodeType)},c=n.isWin=function(t){return!i(t.window)&&t.window==t};n.prototype={regsan:function(t){return t.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},first:function(){return this.found?this.list[0]:null},last:function(){return this.found?this.list[this.list.length-1]:b},index:function(t){return this.found&&t>0&&t<this.list.length?this.list[t]:b},all:function(){return this.list},find:function(t){return this.found?[].slice.call(this.list[0].querySelectorAll(t)):[]},foreach:function(t){this.found&&this.list.forEach(t)},html:function(t){return t?void this.foreach(function(n){n.innerHTML=t}):this.found?this.list[0].innerHTML:""},append:function(t){this.foreach(function(n){n.innerHTML+=t})},on:function(t,n,i){this.foreach(function(e){e.addEventListener(t,n,i===!0)})},val:function(t){return t?void this.foreach(function(n){n.value=t}):this.found?this.list[0].value:null},attr:function(t,n){return 1==arguments.length?this.found?this.list[0].getAttribute(t):null:void this.foreach(function(i){i.setAttribute(t,n)})},toggle:function(t){this.foreach(function(n){n.classList.toggle(t)})},hasClass:function(t){return this.found?this.list[0].contains(t):this.found},removeClass:function(t){this.foreach(function(n){n.classList.contains(t)&&n.classList.toggle(t)})},addClass:function(t){this.foreach(function(n){n.classList.contains(t)||n.classList.toggle(t)})},fadeIn:function(t,n,i){if(this.found){t||(t=this.FADE_DURATION);var e=parseFloat(1/t*20),s=this.first();s.style.opacity=0,s.style.display=i||"block",function t(){var i=parseFloat(s.style.opacity);(i+=e)<1?(s.style.opacity=i,requestAnimationFrame(t)):"function"==typeof n&&n.call(s)}(t)}},fadeOut:function(t,n){if(this.found){t||(t=this.FADE_DURATION);var i=parseFloat(1/t*20),e=this.first();e.style.opacity=1,function t(){var s=parseFloat(e.style.opacity);(s-=i)<0?(e.style.display="none","function"==typeof n&&n.call(e)):(e.style.opacity=s,requestAnimationFrame(t))}(t)}},ready:function(t){this.context.addEventListener("DOMContentLoaded",t)}},n.eachObj=function(t,n,i){for(var e in t)t.hasOwnProperty(e)&&n.call(i,e,t[e])},n.ajax=function(t){this.eachObj(t,function(t,n){console.log(t),console.log(n)});var n=new XMLHttpRequest;n.onreadystatechange=function(n){4==this.readyState&&(200==this.status?s(t.done)&&t.done.call(t.context,n,this.responseText,this.statusText):s(t.fail)&&t.fail.call(t.context,n,this.responseText,this.statusText),s(t.always)&&t.always.call(t.context,n,this.responseText,this.statusText))},!i(t.timeout)&&t.async&&(n.timeout=t.timeout),s(t.before)&&t.before.call(n),n.open(t.method,t.url,t.async),n.setRequestHeader("Content-Type","application/x-www-form-urlencoded");var e="";o(t.data)&&this.eachObj(t.data,function(t,n){e+=t+"="+encodeURIComponent(n)}),n.send(e)};var u=n.init=function(t,n){return this.FADE_DURATION=700,this.VERSION=.4,this.context=i(n)?document:n,this.list=e(t)?[].slice.call(this.context.querySelectorAll(t)):a(t)||c(t)?[t]:[],this.found=this.list.length>0,this};u.prototype=n.prototype,window.Svan=n,i(window.$)&&(window.$=n)}(); /* by a-sansara - v 0.5 - https://github.com/pluie-org/svan */!function(){var n=function(n,i){return typeof n==i},i=function(n,o){return new i.init(n,o)},o=i.isNone=function(i){return n(i,"undefined")},l=i.isStr=function(i){return n(i,"string")},r=i.isFunc=function(i){return n(i,"function")},c=i.isObj=function(i){return n(i,"object")},u=i.isNode=function(n){return c(n)&&!o(n.nodeType)},f=i.isWin=function(n){return c(n)&&!o(n.window)&&n.window==n};i.prototype={regsan:function(n){return n.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")},first:function(){return this.found?this.list[0]:null},last:function(){return this.found?this.list[this.list.length-1]:b},index:function(n){return this.found&&n>0&&n<this.list.length?this.list[n]:b},all:function(){return this.list},find:function(s){return this.found?new i.init(s,this.list[0]):new i.init("")},each:function(n){this.found&&this.list.forEach(n)},html:function(n){return n?void this.each(function(i){i.innerHTML=n}):this.found?this.list[0].innerHTML:""},append:function(n){this.each(function(i){i.innerHTML+=n})},prepend:function(n){if(this.found)if(l(n)){var i=document.createElement("div");for(i.innerHTML=n;null!=i.lastChild;)this.first().insertBefore(i.lastChild,this.first().firstChild)}else{var i=l(n)?document.createElement("div"):n;this.first().insertBefore(n,this.first().firstChild)}},on:function(n,i,o){this.each(function(l){l.addEventListener(n,i,o===!0)})},val:function(n){return n?void this.each(function(i){if("select"==i.nodeName.toLowerCase()){for(var o=0,l=i.options.length;l>o;o++)if(i.options[o].value==n){i.options[o].selected=!0;break}}else i.value=n}):this.found?"select"==this.list[0].nodeName.toLowerCase()?this.list[0].options[this.list[0].selectedIndex].value:this.list[0].value:null},attr:function(n,i){return 1==arguments.length?this.found?"disabled"==n?this.list[0].disabled:this.list[0].getAttribute(n):null:void this.each(function(o){"disabled"==n?o.disabled=i:o.setAttribute(n,i)})},toggle:function(n){this.each(function(i){i.classList.toggle(n)})},hasClass:function(n){return this.found?this.list[0].classList.contains(n):this.found},removeClass:function(n){this.each(function(i){i.classList.contains(n)&&i.classList.toggle(n)})},addClass:function(n){this.each(function(i){i.classList.contains(n)||i.classList.toggle(n)})},fadeIn:function(n,i,o){if(this.found){n||(n=this.FADE_DURATION);var l=parseFloat(1/n*20),r=this.first();r.style.opacity=0,r.style.display=o||"block",function n(){var o=parseFloat(r.style.opacity);(o+=l)<1?(r.style.opacity=o,requestAnimationFrame(n)):"function"==typeof i&&i.call(r)}(n)}},fadeOut:function(n,i){if(this.found){n||(n=this.FADE_DURATION);var o=parseFloat(1/n*20),l=this.first();l.style.opacity=1,function n(){var r=parseFloat(l.style.opacity);(r-=o)<0?(l.style.display="none","function"==typeof i&&i.call(l)):(l.style.opacity=r,requestAnimationFrame(n))}(n)}},ready:function(n){this.context.addEventListener("DOMContentLoaded",n)}},i.eachObj=function(n,i,o){for(var l in n)n.hasOwnProperty(l)&&i.call(o,l,n[l])},i.ajax=function(n){this.eachObj(n,function(n,i){console.log(n),console.log(i)});var i=new XMLHttpRequest;i.onreadystatechange=function(){4==this.readyState&&(200==this.status?r(n.done)&&n.done.call(n.context,this.responseText,this.status):r(n.fail)&&n.fail.call(n.context,this.responseText,this.status),r(n.always)&&n.always.call(n.context,this.responseText,this.status))},!o(n.timeout)&&n.async&&(i.timeout=n.timeout),r(n.before)&&n.before.call(i),i.open(n.method,n.url,n.async),i.setRequestHeader("Content-Type","application/x-www-form-urlencoded");var l="";c(n.data)&&this.eachObj(n.data,function(n,i){l+=n+"="+encodeURIComponent(i)}),i.send(l)};var h=i.init=function(n,i){return this.FADE_DURATION=700,this.VERSION=.5,this.context=o(i)?document:i,this.list=l(n)?[].slice.call(this.context.querySelectorAll(n)):u(n)||f(n)?[n]:[],this.found=this.list.length>0,this};h.prototype=i.prototype,window.Svan=i,o(window.$)&&(window.$=i)}();