mullen-wee 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +127 -0
- data/Rakefile +25 -0
- data/aWee.gemspec +26 -0
- data/examples/ObjectSpaceBrowser.rb +191 -0
- data/examples/ajax.rb +73 -0
- data/examples/apotomo-webhunter/main.rb +75 -0
- data/examples/apotomo-webhunter/public/images/bear_trap_charged.png +0 -0
- data/examples/apotomo-webhunter/public/images/bear_trap_snapped.png +0 -0
- data/examples/apotomo-webhunter/public/images/cheese.png +0 -0
- data/examples/apotomo-webhunter/public/images/dark_forest.jpg +0 -0
- data/examples/apotomo-webhunter/public/images/mouse.png +0 -0
- data/examples/apotomo-webhunter/public/javascripts/jquery-1.3.2.min.js +19 -0
- data/examples/apotomo-webhunter/public/javascripts/wee-jquery.js +19 -0
- data/examples/apotomo-webhunter/public/stylesheets/forest.css +33 -0
- data/examples/arc_challenge.rb +42 -0
- data/examples/arc_challenge2.rb +46 -0
- data/examples/cheese_task.rb +27 -0
- data/examples/continuations.rb +28 -0
- data/examples/demo.rb +135 -0
- data/examples/demo/calculator.rb +63 -0
- data/examples/demo/calendar.rb +333 -0
- data/examples/demo/counter.rb +38 -0
- data/examples/demo/editable_counter.rb +36 -0
- data/examples/demo/example.rb +142 -0
- data/examples/demo/file_upload.rb +19 -0
- data/examples/demo/messagebox.rb +15 -0
- data/examples/demo/radio.rb +33 -0
- data/examples/demo/window.rb +71 -0
- data/examples/hw.rb +11 -0
- data/examples/i18n/app.rb +16 -0
- data/examples/i18n/locale/de/app.po +25 -0
- data/examples/i18n/locale/en/app.po +25 -0
- data/examples/pager.rb +102 -0
- data/lib/wee.rb +109 -0
- data/lib/wee/application.rb +89 -0
- data/lib/wee/callback.rb +109 -0
- data/lib/wee/component.rb +363 -0
- data/lib/wee/decoration.rb +251 -0
- data/lib/wee/dialog.rb +171 -0
- data/lib/wee/external_resource.rb +39 -0
- data/lib/wee/html_brushes.rb +795 -0
- data/lib/wee/html_canvas.rb +254 -0
- data/lib/wee/html_document.rb +52 -0
- data/lib/wee/html_writer.rb +71 -0
- data/lib/wee/id_generator.rb +81 -0
- data/lib/wee/jquery.rb +11 -0
- data/lib/wee/jquery/jquery-1.3.2.min.js +19 -0
- data/lib/wee/jquery/wee-jquery.js +19 -0
- data/lib/wee/locale.rb +56 -0
- data/lib/wee/lru_cache.rb +91 -0
- data/lib/wee/presenter.rb +44 -0
- data/lib/wee/renderer.rb +72 -0
- data/lib/wee/request.rb +56 -0
- data/lib/wee/response.rb +68 -0
- data/lib/wee/rightjs.rb +11 -0
- data/lib/wee/rightjs/rightjs-1.5.2.min.js +9 -0
- data/lib/wee/rightjs/wee-rightjs.js +18 -0
- data/lib/wee/root_component.rb +45 -0
- data/lib/wee/session.rb +366 -0
- data/lib/wee/state.rb +102 -0
- data/lib/wee/task.rb +16 -0
- data/test/bm_render.rb +34 -0
- data/test/component_spec.rb +40 -0
- data/test/stress/plotter.rb +84 -0
- data/test/stress/stress_client.rb +51 -0
- data/test/stress/stress_local.rb +86 -0
- data/test/stress/stress_server.rb +83 -0
- data/test/test_component.rb +106 -0
- data/test/test_html_canvas.rb +25 -0
- data/test/test_html_writer.rb +32 -0
- data/test/test_lru_cache.rb +51 -0
- data/test/test_request.rb +42 -0
- metadata +185 -0
data/lib/wee/rightjs.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
/**
|
2
|
+
* RightJS, http://rightjs.org
|
3
|
+
* Released under the MIT license
|
4
|
+
*
|
5
|
+
* Custom build with options: no-olds
|
6
|
+
*
|
7
|
+
* Copyright (C) 2008-2009 Nikolay Nemshilov
|
8
|
+
*/
|
9
|
+
var RightJS={version:"1.5.2",modules:["core","form","cookie","xhr","fx"]};var Browser=(function(a){return{IE:!!(window.attachEvent&&!window.opera),Opera:!!window.opera,WebKit:a.indexOf('AppleWebKit/')>-1,Gecko:a.indexOf('Gecko')>-1&&a.indexOf('KHTML')<0,MobileSafari:!!a.match(/Apple.*Mobile.*Safari/),Konqueror:a.indexOf('Konqueror')>-1,OLD:a.indexOf('MSIE 6')>-1||a.indexOf('MSIE 7')>-1,IE8:a.indexOf('MSIE 8')>-1}})(navigator.userAgent);function $ext(d,s,a){var s=s||{};for(var k in s)if(a===undefined||d[k]===undefined)d[k]=s[k];return d};function $try(){for(var i=0;i<arguments.length;i++)try{return arguments[i]()}catch(e){}};function $eval(t){if(!isString(t)||t.blank())return;if(window.execScript)window.execScript(t);else $E('script',{type:'text/javascript',text:t}).insertTo(document.body)}function $break(){throw new Break()};function $alias(o,n){for(var a in n)o[a]=o[n[a]];return o};function defined(v){return v!==undefined};function isHash(v){return typeof(v)==='object'&&v!==null&&v.constructor===Object};if(isHash(document.createElement('p')))eval(isHash.toString().replace(';','&&!(arguments[0] instanceof HTMLElement);'));function isFunction(v){return typeof(v)==='function'};function isString(v){return typeof(v)==='string'};function isArray(v){return v instanceof Array};function isNumber(v){return typeof(v)==='number'};function isElement(v){return v&&v.tagName};function isNode(v){return v&&v.nodeType};var $A=(function(s){return function(b){try{return s.call(b)}catch(e){for(var a=[],i=0,l=b.length;i<l;i++)a[i]=b[i];return a}}})(Array.prototype.slice);function $E(t,o){return new Element(t,o)};function $(e){return typeof(e)==='string'?document.getElementById(e):e};function $$(c){return $A(document.querySelectorAll(c))};function $w(s){return s.trim().split(/\s+/)}var $uid=(function(U){return function(i){return i.uid||(i.uid=U++)}})(1);$ext(Object,{keys:function(o){var a=[];for(var k in o)a.push(k);return a},values:function(o){var v=[];for(var k in o)v.push(o[k]);return v},empty:function(o){for(var k in o)break;return!k},without:function(){var f=$A(arguments),o=f.shift(),c={};for(var k in o)if(!f.includes(k))c[k]=o[k];return c},only:function(){var f=$A(arguments),o=f.shift(),c={};for(var i=0,l=f.length;i<l;i++)if(defined(o[f[i]]))c[f[i]]=o[f[i]];return c},merge:function(){var o={};for(var i=0,l=arguments.length;i<l;i++)if(isHash(arguments[i]))$ext(o,arguments[i]);return o},toQueryString:function(o){var t=[];for(var k in o)t.push(k+'='+encodeURIComponent(o[k]));return t.join('&')}});$ext(Math,{random:function(a,m){var r=this._random();if(arguments.length==0)return r;if(arguments.length==1)var m=a,a=0;return Math.floor(r*(m-a+1)+a)},_random:Math.random});$ext(Array.prototype,(function(A){var n=A.forEach||function(c,s){for(var i=0,l=this.length;i<l;i++)c.call(s,this[i],i,this)};var k=A.filter||function(c,s){for(var r=[],i=0,j=0,l=this.length;i<l;i++)if(c.call(s,this[i],i,this))r[j++]=this[i];return r};var u=A.map||function(c,s){for(var r=[],i=0,l=this.length;i<l;i++)r[i]=c.call(s,this[i],i,this);return r};var w=A.some||function(c,s){for(var i=0,l=this.length;i<l;i++)if(c.call(s,this[i],i,this))return true;return false};var h=A.every||function(c,s){for(var i=0,l=this.length;i<l;i++)if(!c.call(s,this[i],i,this))return false;return true};var m=function(c,s){for(var i=0,l=this.length;i<l;i++)if(c.call(s,this[i],i,this))return this[i];return undefined};var t=function(c,s){for(var i=this.length-1;i>-1;i--)if(c.call(s,this[i],i,this))return this[i];return undefined};var q=function(a,b){var d=a[0],a=A.slice.call(a,1),s=b;if(isString(d)){var c=d;if(b.length&&isFunction(b[0][c]))d=function(o){return o[c].apply(o,a)};else d=function(o){return o[c]}}else s=a[0];return[d,s]};var g=function(f,s,a){try{return f.apply(s,q(a,s))}catch(e){if(!(e instanceof Break))throw(e)}};return{indexOf:A.indexOf||function(v,f){for(var i=(f<0)?Math.max(0,this.length+f):f||0,l=this.length;i<l;i++)if(this[i]===v)return i;return-1},lastIndexOf:A.lastIndexOf||function(v){for(var i=this.length-1;i>-1;i--)if(this[i]===v)return i;return-1},first:function(){return arguments.length?g(m,this,arguments):this[0]},last:function(){return arguments.length?g(t,this,arguments):this[this.length-1]},random:function(){return this.length?this[Math.random(this.length-1)]:null},size:function(){return this.length},clean:function(){this.length=0;return this},empty:function(){return!this.length},clone:function(){return this.slice(0)},each:function(){g(n,this,arguments);return this},forEach:n,map:function(){return g(u,this,arguments)},filter:function(){return g(k,this,arguments)},some:function(){return g(w,this,arguments.length?arguments:[function(a){return!!a}])},every:function(){return g(h,this,arguments.length?arguments:[function(a){return!!a}])},walk:function(){this.map.apply(this,arguments).forEach(function(v,a){this[a]=v},this);return this},merge:function(){for(var c=this.clone(),a,i=0,l=arguments.length;i<l;i++){a=arguments[i];if(isArray(a)){for(var j=0;j<a.length;j++)if(c.indexOf(a[j])==-1)c.push(a[j])}else if(c.indexOf(a)==-1)c.push(a)}return c},flatten:function(){var c=[];this.forEach(function(v){if(isArray(v))c=c.concat(v.flatten());else c.push(v)});return c},compact:function(){return this.without(null,undefined)},uniq:function(){return[].merge(this)},includes:function(){for(var i=0,l=arguments.length;i<l;i++)if(this.indexOf(arguments[i])==-1)return false;return true},without:function(){var f=$A(arguments);return this.filter(function(v){return!f.includes(v)})},shuffle:function(){var s=this.clone();for(var j,x,i=s.length;i;j=Math.random(i-1),x=s[--i],s[i]=s[j],s[j]=x);return s},sortBy:function(){var p=q(arguments,this);return this.map(function(b,a){return{item:b,value:p[0].call(p[1],b,a,this)}}).sort(function(c,d){return c.value>d.value?1:c.value<d.value?-1:0}).map('item')}}})(Array.prototype));$alias(Array.prototype,{include:'includes',all:'every',any:'some'});$ext(String.prototype,{empty:function(){return this==''},blank:function(){return/^\s*$/.test(this)},trim:String.prototype.trim||function(){var a=this.replace(/^\s\s*/,''),i=a.length;while(/\s/.test(a.charAt(--i)));return a.slice(0,i+1)},stripTags:function(){return this.replace(/<\/?[^>]+>/ig,'')},stripScripts:function(o){var a='';var t=this.replace(/<script[^>]*>([\s\S]*?)<\/script>/img,function(m,s){a+=s.trim()+"\n";return ''});if(o===true)$eval(a);else if(isFunction(o))o(a,t);else if(isNumber(o))$eval.bind(a).delay(options);return t},extractScripts:function(){var s='';this.stripScripts(function(a){s=a});return s},evalScripts:function(){$eval(this.extractScripts());return this},camelize:function(){var p=this.match(/^(\-|_)+?/g)||'';return p+this.substr(p.length,this.length).replace(/(\-|_)+?(\D)/g,function(m){return m.replace(/\-|_/,'').toUpperCase()})},underscored:function(){return this.replace(/([a-z0-9])([A-Z]+)/g,function(m,f,s){return f+"_"+(s.length>1?s:s.toLowerCase())}).replace(/\-/g,'_')},capitalize:function(){return this.replace(/(^|\s|\-|_)[a-z\u00e0-\u00fe\u0430-\u045f]/g,function(m){return m.toUpperCase()})},includes:function(s){return this.indexOf(s)!=-1},startsWith:function(a,i){var s=this.substr(0,a.length);return i?s.toLowerCase()===a.toLowerCase():s===a},endsWith:function(s,i){var e=this.substring(this.length-s.length);return i?e.toLowerCase()===s.toLowerCase():e===s},toInt:function(b){return parseInt(this,b||10)},toFloat:function(s){return parseFloat(s?this:this.replace(',','.').replace(/(\d)-(\d)/g,'$1.$2'))}});$alias(String.prototype,{include:'includes'});$ext(Function.prototype,(function(){var A=Array.prototype.slice;return{bind:function(){if(arguments.length<2&&!arguments[0])return this;var b=A,a=b.call(arguments),s=a.shift(),f=this;return function(){return f.apply(s,(a.length!=0||arguments.length!=0)?a.concat(b.call(arguments)):a)}},bindAsEventListener:function(){var b=A,a=b.call(arguments),s=a.shift(),f=this;return function(e){return f.apply(s,[e||window.event].concat(a).concat(b.call(arguments)))}},curry:function(){return this.bind.apply(this,[this].concat(A.call(arguments)))},rcurry:function(){var c=A.call(arguments),f=this;return function(){return f.apply(f,A.call(arguments).concat(c))}},delay:function(){var a=A.call(arguments),t=a.shift();var b=new Number(window.setTimeout(this.bind.apply(this,[this].concat(a)),t));b.cancel=function(){window.clearTimeout(this)};return b},periodical:function(){var a=A.call(arguments),t=a.shift();var b=new Number(window.setInterval(this.bind.apply(this,[this].concat(a)),t));b.stop=function(){window.clearInterval(this)};return b},chain:function(){var a=A.call(arguments),f=a.shift(),c=this;return function(){var r=c.apply(c,arguments);f.apply(f,a);return r}}}})());$ext(Number.prototype,{times:function(c,s){for(var i=0;i<this;i++)c.call(s,i);return this},upto:function(n,c,s){for(var i=this+0;i<=n;i++)c.call(s,i);return this},downto:function(n,c,s){for(var i=this+0;i>=n;i--)c.call(s,i);return this},abs:function(){return Math.abs(this)},round:function(b){if(b){var b=Math.pow(10,b);return Math.round(this*b)/b}else return Math.round(this)},ceil:function(){return Math.ceil(this)},floor:function(){return Math.floor(this)}});$ext(RegExp,{escape:function(s){return String(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g,'\\$1')}});var Class=function(){var a=$A(arguments),b=a.pop()||{},p=a.pop();if(!a.length&&!isHash(b)){p=b;b={}}var k=function(){return this.initialize?this.initialize.apply(this,arguments):this};$ext(k,Class.Methods).inherit(p);$w('extend include').each(function(n){if(b[n]){var m=b[n];k[n].apply(k,isArray(m)?m:[m]);delete(b[n])}});return k.include(b)};Class.findSet=function(o,p){var u=p.toUpperCase(),b=p.capitalize(),c=[o,o.constructor].concat(o.constructor.ancestors),h=c.first(function(a){return a[u]||a[b]});return h?h[u]||h[b]:null};Class.Methods=(function(){var f=$w('selfExtended self_extended selfIncluded self_included');var g=f.concat($w('prototype parent extend include'));var i=f.concat(['constructor']);var e=function(m,w){return Object.without.apply(Object,[m].concat(w=='e'?g:i))};return{inherit:function(p){if(p&&p.prototype){var s=function(){};s.prototype=p.prototype;this.prototype=new s;this.parent=p}this.ancestors=[];while(p){this.ancestors.push(p);p=p.parent}return this.prototype.constructor=this},extend:function(){$A(arguments).filter(isHash).each(function(m){var c=m.selfExtended||m.self_extended;$ext(this,e(m,'e'));if(c)c.call(m,this)},this);return this},include:function(){var d=this.ancestors.map('prototype'),b;$A(arguments).filter(isHash).each(function(a){var c=a.selfIncluded||a.self_included;a=e(a,'i');for(var k in a){b=d.first(function(p){return isFunction(p[k])});this.prototype[k]=!b?a[k]:(function(n,m,s){return function(){this.$super=s;return m.apply(this,arguments)}})(k,a[k],b[k])}if(c)c.call(a,this)},this);return this}}})();var Options={setOptions:function(o){var o=this.options=Object.merge(Class.findSet(this,'options'),o);if(isFunction(this.on)){var m;for(var k in o)if(m=k.match(/on([A-Z][A-Za-z]+)/)){this.on(m[1].toLowerCase(),o[k]);delete(o[k])}}return this},cutOptions:function(a){var a=$A(a);this.setOptions(isHash(a.last())?a.pop():{});return a}};var Observer=new Class({include:Options,initialize:function(o){this.setOptions(o);Observer.createShortcuts(this,Class.findSet(this,'events'))},observe:function(){var a=$A(arguments),e=a.shift();if(isString(e)){if(!defined(this.$listeners))this.$listeners=[];var c=a.shift(),n;switch(typeof(c)){case "string":n=c;c=this[c];case "function":var h={};h.e=e;h.f=c;h.a=a;h.r=n;this.$listeners.push(h);break;default:if(isArray(c))c.each(function(p){this.observe.apply(this,[e].concat(isArray(p)?p:[p]).concat(a))},this)}}else for(var n in e)this.observe.apply(this,[n].concat(isArray(e[n])?e[n]:[e[n]]).concat(a));return this},observes:function(e,c){if(this.$listeners){if(!isString(e)){c=e;e=null}if(isString(c))c=this[c];return this.$listeners.some(function(a){return(e&&c)?a.e==e&&a.f==c:e?a.e==e:a.f==c})}return false},stopObserving:function(e,c){if(this.$listeners){if(!isString(e)){c=e;e=null}if(isString(c))c=this[c];this.$listeners=this.$listeners.filter(function(a){return(e&&c)?(a.e!==e||a.f!==c):(e?a.e!==e:a.f!==c)},this)}return this},listeners:function(e){return(this.$listeners||[]).filter(function(a){return!e||a.e===e}).map(function(a){return a.f}).uniq()},fire:function(){var b=$A(arguments),e=b.shift();(this.$listeners||[]).each(function(a){if(a.e===e)a.f.apply(this,a.a.concat(b))},this);return this},extend:{create:function(o,e){$ext(o,Object.without(this.prototype,'initialize','setOptions'),true);return this.createShortcuts(o,e||Class.findSet(o,'events'))},createShortcuts:function(o,a){(a||[]).each(function(n){var s={},m=n.replace(/:/g,'_').camelize();s[m]=function(){return this.fire.apply(this,[n].concat($A(arguments)))};s['on'+m.capitalize()]=function(){return this.on.apply(this,[n].concat($A(arguments)))};$ext(o,s,true)});return o}}});$alias(Observer.prototype,{on:'observe'});var Break=new Class(Error,{message:"Manual iterator break"});var Event=new Class(Event,{extend:{ext:function(e){if(!e.stop){$ext(e,this.Methods,true);if(Browser.IE){if(e.type=='click'||e.type=='dblclick')e.which=1;else if(e.type=='contextmenu')e.which=3;else e.which=e.button==2?3:e.button==4?2:1;var s=window.scrolls();e.pageX=e.clientX+s.x;e.pageY=e.clientY+s.y;e.relatedTarget=e.type=='mouseover'?e.fromEvent:e.type=='mouseout'?e.toEvent:null;e.target=e.srcElement}}if(e.target&&e.target.nodeType==3)e.target=e.target.parentNode;return e},cleanName:function(n){n=n.toLowerCase();n=n.substr(0,2)==='on'?n.slice(2):n;n=n==='rightclick'?'contextmenu':n;return n},realName:function(n){if(Browser.Gecko&&n==='mousewheel')n='DOMMouseScroll';if(Browser.Konqueror&&n==='contextmenu')n='rightclick';return n},addMethods:function(m){$ext(this.Methods,m);try{$ext(Event.parent.prototype,m,true)}catch(e){}},Methods:{}},initialize:function(n,o){return new Event.Custom(Event.cleanName(n),o)}});Event.addMethods({stopPropagation:function(){this.cancelBubble=true},preventDefault:function(){this.returnValue=false},stop:function(){this.stopPropagation();this.preventDefault();return this},position:function(){return{x:this.pageX,y:this.pageY}}});Event.Custom=function(n,o){this.type=n;this.stop=function(){};$ext(this,o||{})};self.Element=(function(a){var n=function(t,o){var e=document.createElement(t),o=o||{};if(o.id){e.id=o.id;delete(o.id)}if(o.html){e.innerHTML=o.html;delete(o.html)}if(o['class']){e.className=o['class'];delete(o['class'])}if(o.style){e.setStyle(o.style);delete(o.style)}if(o.observe){e.observe(o.observe);delete(o.observe)}for(var k in o)return e.set(o);return e};if(Browser.IE)n=eval('({f:'+n.toString().replace(/(\((\w+), (\w+)\) \{)/,'$1if($2=="input"&&$3&&$3.checked)$2="<input checked=true/>";')+'})').f;if(a){$ext(n,a);n.parent=a}return n})(self.Element);$ext(Element,{addMethods:function(m,d){$ext(this.Methods,m,d);try{$ext(HTMLElement.prototype,m,d)}catch(e){try{$ext(this.parent.prototype,m,d)}catch(e){}}return this},Methods:{}});Element.addMethods({parent:function(c){return c?this.parents(c)[0]:$(this.parentNode)},parents:function(c){return this.rCollect('parentNode',c)},subNodes:function(c){var f=this.firstChild;return f?(f.tagName?[$(f)]:[]).concat(this.rCollect.call(f,'nextSibling',c)):[]},siblings:function(c){return this.prevSiblings(c).reverse().concat(this.nextSiblings(c))},nextSiblings:function(c){return this.rCollect('nextSibling',c)},prevSiblings:function(c){return this.rCollect('previousSibling',c)},next:function(c){return this.nextSiblings(c)[0]},prev:function(c){return this.prevSiblings(c)[0]},remove:function(){if(this.parentNode)this.parentNode.removeChild(this);return this},insert:function(c,p){if(isHash(c))for(var p in c)this.insert(c[p],p);else{var s,i=Element.insertions;p=isString(p)?p.toLowerCase():'bottom';if(isString(c))c=c.stripScripts(function(a){s=a});i[p](this,c.tagName?c:i.createFragment.call((p==='bottom'||p==='top'||!this.parentNode)?this:this.parentNode,c));if(s)$eval(s)}return this},insertTo:function(e,p){$(e).insert(this,p);return this},replace:function(c){return this.insert(c,'instead')},update:function(c){if(isString(c)){var s;this.innerHTML=c.stripScripts(function(a){s=a});if(s)$eval(s)}else this.clean().insert(c);return this},wrap:function(e){if(this.parentNode){this.parentNode.replaceChild(e,this);e.appendChild(this)}return this},clean:function(){while(this.firstChild)this.removeChild(this.firstChild);return this},empty:function(){return this.innerHTML.blank()},rCollect:function(a,c){var n=this,r=[];while((n=n[a]))if(n.tagName&&(!c||$(n).match(c)))r.push(n);return r}});Element.insertions={bottom:function(t,c){t.appendChild(c)},top:function(t,c){t.firstChild?t.insertBefore(c,t.firstChild):t.appendChild(c)},after:function(t,c){var p=t.parentNode,s=t.nextSibling;if(p)s?p.insertBefore(c,s):p.appendChild(c)},before:function(t,c){if(t.parentNode)t.parentNode.insertBefore(c,t)},instead:function(t,c){if(t.parentNode)t.parentNode.replaceChild(c,t)},createFragment:function(c){var f;if(isString(c)){var t=document.createElement('div'),w=Element.insertions.wraps[this.tagName]||['','',0],d=w[2];t.innerHTML=w[0]+c+w[1];while(d>0){t=t.firstChild;d--}f=arguments.callee.call(this,t.childNodes)}else{f=document.createDocumentFragment();if(isNode(c))f.appendChild(c);else if(c&&c.length)for(var i=0,l=c.length;i<l;i++)f.appendChild(c[c.length==l?i:0])}return f},wraps:{TABLE:['<table>','</table>',1],TBODY:['<table><tbody>','</tbody></table>',2],TR:['<table><tbody><tr>','</tr></tbody></table>',3],TD:['<table><tbody><tr><td>','</td></tr></tbody></table>',4],SELECT:['<select>','</select>',1]}};$alias(Element.insertions.wraps,{THEAD:'TBODY',TFOOT:'TBODY',TH:'TD'});Element.addMethods({setStyle:function(h,v){if(v){var s={};s[h]=v;h=s}else if(isString(h)){var s={};h.split(';').each(function(o){var e=o.split(':').map('trim');if(e[0]&&e[1])s[e[0]]=e[1]});h=s}var c;for(var k in h){c=k.indexOf('-')!=-1?k.camelize():k;if(k==='opacity'){if(Browser.IE)this.style.filter='alpha(opacity='+v*100+')';else this.style.opacity=v}else if(k==='float')c=Browser.IE?'styleFloat':'cssFloat';this.style[c]=h[k]}return this},getStyle:function(k){return this._getStyle(this.style,k)||this._getStyle(this.computedStyles(),k)},computedStyles:function(){return this.currentStyle||this.runtimeStyle||this.ownerDocument.defaultView.getComputedStyle(this,null)||{}},_getStyle:function(s,k){var v,k=k.camelize();switch(k){case 'opacity':v=!Browser.IE?s[k]:((/opacity=(\d+)/i.exec(s.filter||'')||['','100'])[1].toInt()/100)+'';break;case 'float':k=Browser.IE?'styleFloat':'cssFloat';default:v=s[k];if(Browser.Opera&&/color/i.test(k)&&v)v=v.replace(/"/g,'')}return v?v:null},hasClass:function(n){return(' '+this.className+' ').indexOf(' '+n+' ')!=-1},setClass:function(c){this.className=c;return this},addClass:function(n){var t=' '+this.className+' ';if(t.indexOf(' '+n+' ')==-1)this.className+=(t===' '?'':' ')+n;return this},removeClass:function(n){this.className=(' '+this.className+' ').replace(' '+n+' ',' ').trim();return this},toggleClass:function(n){return this[this.hasClass(n)?'removeClass':'addClass'](n)},radioClass:function(n){this.siblings().each('removeClass',n);return this.addClass(n)}});Element.addMethods({set:function(h,a){if(a){var v={};v[h]=a;h=v}for(var k in h){if(this[k]===undefined)this.setAttribute(k,''+h[k]);this[k]=h[k]}return this},get:function(n){var v=this[n]||this.getAttribute(n);return v===''?null:v},has:function(n){return this.get(n)!==null},erase:function(n){this.removeAttribute(n);return this},hidden:function(){return this.getStyle('display')=='none'},visible:function(){return!this.hidden()},hide:function(e,o){this._$pd=this.getStyle('display');this.style.display='none';return this},show:function(e,o){var v=this.tagName=='DIV'?'block':'inline';this.style.display=this._$pd=='none'?v:this._$pd||v;return this},toggle:function(e,o){return this[this.hidden()?'show':'hide'](e,o)},radio:function(e,o){this.siblings().each('hide',e,o);return this.show()}});Element.addMethods({sizes:function(){return{x:this.offsetWidth,y:this.offsetHeight}},position:function(){var r=this.getBoundingClientRect(),d=this.ownerDocument.documentElement,s=window.scrolls();return{x:r.left+s.x-d.clientLeft,y:r.top+s.y-d.clientTop}},scrolls:function(){return{x:this.scrollLeft,y:this.scrollTop}},dimensions:function(){var a=this.sizes();var s=this.scrolls();var p=this.position();return{top:p.y,left:p.x,width:a.x,height:a.y,scrollLeft:s.x,scrollTop:s.y}},setWidth:function(w){var s=this.style,p='offsetWidth';s.width=w+'px';s.width=(2*w-this[p])+'px';return this},setHeight:function(h){var s=this.style,p='offsetHeight';s.height=h+'px';s.height=(2*h-this[p])+'px';return this},resize:function(w,h){if(isHash(w)){h=w.y;w=w.x}return this.setWidth(w).setHeight(h)},moveTo:function(l,t){if(isHash(l)){t=l.y;l=l.x}return this.setStyle({left:l+'px',top:t+'px'})},scrollTo:function(l,t){if(isHash(l)){t=l.y;l=l.x}this.scrollLeft=l;this.scrollTop=t;return this},scrollThere:function(){window.scrollTo(this);return this}});Element.addMethods((function(){var o=Observer.create({},$w('click rightclick contextmenu mousedown mouseup mouseover mouseout mousemove keypress keydown keyup'));o.observe=o.on=eval('({f:'+o.observe.toString().replace(/(\$listeners\.push\((\w+?)\);)/,'$1'+'$2.e=Event.cleanName($2.e);$2.n=Event.realName($2.e);'+'$2.w=function(){var a=$A(arguments),e=($2.r&&$2.r!=="stopEvent")?a.shift():Event.ext(a[0]);'+'return $2.f.apply(this,a.concat($2.a))};'+(self.attachEvent?'$2.w=$2.w.bind(this);this.attachEvent("on"+$2.n,$2.w);':'this.addEventListener($2.n,$2.w,false);'))+'})').f;o.stopObserving=eval('({f:'+o.stopObserving.toString().replace(/(function\s*\((\w+)\)\s*\{\s*)(return\s*)([^}]+)/m,'$1var r=$4;'+'if(!r)'+(self.attachEvent?'this.detachEvent("on"+$2.n,$2.w);':'this.removeEventListener($2.n,$2.w,false);')+'$3 r')+'})').f;o.fire=eval('({f:'+o.fire.toString().replace(/(\w+)\.f\.apply.*?\.concat\((\w+)\)[^}]/,'$1.f.apply(this,[new Event($1.e,$2.shift())].concat($1.a).concat($2))')+'})').f;o.stopEvent=function(a){a.stop()};$ext(window,o);$ext(document,o);return o})());Element.addMethods((function(){var s=function(c,t){return c?c.replace(/(^|,)/g,'$1'+t+' '):'*'};return{first:function(c){return this.querySelector(s(c,this.tagName))},select:function(c){return $A(this.querySelectorAll(s(c,this.tagName)))},match:function(c){if(!c||c=='*')return true;var f,r,p,a=this.parents();p=a.length?a.last():f=$E('div').insert(this);r=p.select(c).include(this);if(f)this.remove();return r}}})());$ext(document,{first:function(c){return this.querySelector(c||'*')},select:function(c){return $A(this.querySelectorAll(c||'*'))}});$ext(self,(function(){var e=window.scrollTo;return{sizes:function(){var d=document.documentElement;return this.innerWidth?{x:this.innerWidth,y:this.innerHeight}:{x:d.clientWidth,y:d.clientHeight}},scrolls:function(){var b=this.document.body,d=this.document.documentElement,o='pageXOffset',a='pageYOffset',s='scrollLeft',c='scrollTop';return(this[o]||this[a])?{x:this[o],y:this[a]}:(b[s]||b[c])?{x:b[s],y:b[c]}:{x:d[s],y:d[c]}},scrollTo:function(l,t){if(isElement(l)||(isString(l)&&$(l)))l=$(l).position();if(isHash(l)){t=l.y;l=l.x}e(l,t);return this}}})());[window,document].each(function(o){Observer.createShortcuts(o,['ready']);var r=o.ready.bind(o);if(document.readyState!==undefined)(function(){['loaded','complete'].includes(document.readyState)?r():arguments.callee.delay(50)})();else document.addEventListener('DOMContentLoaded',r,false)});var Form=function(o){var o=o||{},r=o.remote,f=new Element('form',Object.without(o,'remote'));if(r)f.remotize();return f};$ext(Form,{ext:function(e){return $ext(e,this.Methods)},Methods:{},addMethods:function(m,d){$ext(Form.Methods,m,d);try{$ext(HTMLFormElement.prototype,m,d)}catch(e){}}});Form.addMethods({getElements:function(){return this.select('input,select,textarea,button')},inputs:function(){return this.getElements().filter(function(i){return!['submit','button','reset','image',null].includes(i.type)})},focus:function(){var f=this.inputs().first(function(i){return i.type!='hidden'});if(f)f.focus();return this.fire('focus')},blur:function(){this.getElements().each('blur');return this.fire('blur')},disable:function(){this.getElements().each('disable');return this.fire('disable')},enable:function(){this.getElements().each('enable');return this.fire('enable')},values:function(){var v={};this.inputs().each(function(i){if(!i.disabled&&i.name&&(!['checkbox','radio'].includes(i.type)||i.checked))v[i.name]=i.getValue()});return v},serialize:function(){return Object.toQueryString(this.values())}});Form.addMethods(Observer.createShortcuts({},$w('submit reset focus')),true);(function(){try{var i=[HTMLInputElement,HTMLSelectElement,HTMLTextAreaElement,HTMLButtonElement]}catch(e){var i=[]}Form.Element={ext:function(e){e._blur=e.blur;e._focus=e.focus;e._select=e.select;return $ext(e,this.Methods)},Methods:{},addMethods:function(m,d){$ext(this.Methods,m,d);i.each(function(k){$ext(k.prototype,m,d)})}};i.each(function(k){$alias(k.prototype,{_blur:'blur',_focus:'focus',_select:'select'})})})();Form.Element.addMethods({getValue:function(){if(this.type=='select-multiple')return $A(this.getElementsByTagName('option')).map(function(o){return o.selected?o.value:null}).compact();else return this.value},setValue:function(v){if(this.type=='select-multiple'){v=(isArray(v)?v:[v]).map(String);$A(this.getElementsByTagName('option')).each(function(o){o.selected=v.includes(o.value)})}else this.value=v;return this},disable:function(){this.disabled=true;this.fire('disable');return this},enable:function(){this.disabled=false;this.fire('enable');return this},focus:function(){Browser.OLD?this._focus():this._focus.call(this);this.focused=true;this.fire('focus');return this},select:function(){this.focus();Browser.OLD?this._select():this._select.call(this);return this},blur:function(){Browser.OLD?this._blur():this._blur.call(this);this.focused=false;this.fire('blur');return this}});Form.Element.addMethods(Observer.createShortcuts({},$w('disable enable focus blur change')),true);var Cookie=new Class({include:Options,extend:{set:function(n,v,o){return new this(n,o).set(v)},get:function(n){return new this(n).get()},remove:function(n){return new this(n).remove()},enabled:function(){document.cookie="__t=1";return document.cookie.indexOf("__t=1")!=-1},Options:{secure:false,document:document}},initialize:function(n,o){this.name=n;this.setOptions(o)},set:function(v){var v=encodeURIComponent(v),o=this.options;if(o.domain)v+='; domain='+o.domain;if(o.path)v+='; path='+o.path;if(o.duration){var d=new Date();d.setTime(d.getTime()+o.duration*24*60*60*1000);v+='; expires='+d.toGMTString()}if(o.secure)v+='; secure';o.document.cookie=this.name+'='+v;return this},get:function(){var v=this.options.document.cookie.match('(?:^|;)\\s*'+RegExp.escape(this.name)+'=([^;]*)');return(v)?decodeURIComponent(v[1]):null},remove:function(){this.options.duration=-1;return this.set('')}});var Xhr=new Class(Observer,{extend:{EVENTS:$w('success failure complete request cancel create'),Options:{headers:{'X-Requested-With':'XMLHttpRequest','Accept':'text/javascript,text/html,application/xml,text/xml,*/*'},method:'post',encoding:'utf-8',async:true,evalScripts:false,evalResponse:false,evalJSON:true,secureJSON:true,urlEncoded:true,spinner:null,spinnerFx:'fade',params:null,iframed:false},load:function(u,o){return new this(u,Object.merge({method:'get'},o)).send()}},initialize:function(u,o){this.initCallbacks();this.url=u;this.$super(o);for(var k in Xhr.Options)this[k]=this.options[k];this.initSpinner()},setHeader:function(n,v){this.headers[n]=v;return this},getHeader:function(n){try{return this.xhr.getResponseHeader(n)}catch(e){}},successful:function(){return(this.status>=200)&&(this.status<300)},send:function(p){var a={},u=this.url,m=this.method.toLowerCase();if(m=='put'||m=='delete'){a['_method']=m;m='post'}var d=this.prepareData(this.params,this.prepareParams(p),a);if(this.urlEncoded&&m=='post'&&!this.headers['Content-type'])this.setHeader('Content-type','application/x-www-form-urlencoded;charset='+this.encoding);if(m=='get'){u+=(u.includes('?')?'&':'?')+d;d=null}this.xhr=this.createXhr();this.fire('create');this.xhr.open(m,u,this.async);this.xhr.onreadystatechange=this.stateChanged.bind(this);for(var k in this.headers)this.xhr.setRequestHeader(k,this.headers[k]);this.xhr.send(d);this.fire('request');if(!this.async)this.stateChanged();return this},update:function(e,p){return this.onSuccess(function(a){e.update(a.text)}).send(p)},cancel:function(){if(!this.xhr||this.xhr.canceled)return this;this.xhr.abort();this.xhr.onreadystatechange=function(){};this.xhr.canceled=true;return this.fire('cancel')},fire:function(n){return this.$super(n,this,this.xhr)},createXhr:function(){if(this.form&&this.form.getElements().map('type').includes('file'))return new Xhr.IFramed(this.form);else try{return new XMLHttpRequest()}catch(e){return new ActiveXObject('MSXML2.XMLHTTP')}},prepareParams:function(p){if(p&&p.tagName=='FORM'){this.form=p;p=p.values()}return p},prepareData:function(){return $A(arguments).map(function(p){if(!isString(p))p=Object.toQueryString(p);return p.blank()?null:p}).compact().join('&')},stateChanged:function(){if(this.xhr.readyState!=4||this.xhr.canceled)return;try{this.status=this.xhr.status}catch(e){this.status=0}this.text=this.responseText=this.xhr.responseText;this.xml=this.responseXML=this.xhr.responseXML;this.fire('complete').fire(this.successful()?'success':'failure')},tryScripts:function(r){if(this.evalResponse||(/(ecma|java)script/).test(this.getHeader('Content-type')))$eval(this.text);else if((/json/).test(this.getHeader('Content-type'))&&this.evalJSON)this.json=this.responseJSON=this.sanitizedJSON();else if(this.evalScripts)this.text.evalScripts()},sanitizedJSON:function(){if(!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(this.text.replace(/\\./g,'@').replace(/"[^"\\\n\r]*"/g,''))){if(this.secureJSON)throw "JSON parse error: "+this.text;else return null}return eval("("+this.text+")")},initCallbacks:function(){this.on({success:'tryScripts',create:'showSpinner',complete:'hideSpinner',cancel:'hideSpinner'});Xhr.EVENTS.each(function(n){this.on(n,function(){Xhr.fire(n,this,this.xhr)})},this)},initSpinner:function(){if(this.spinner)this.spinner=$(this.spinner);if(Xhr.Options.spinner&&this.spinner===$(Xhr.Options.spinner))this.spinner=null},showSpinner:function(){if(this.spinner)this.spinner.show(this.spinnerFx,{duration:100})},hideSpinner:function(){if(this.spinner)this.spinner.hide(this.spinnerFx,{duration:100})}});Observer.create(Xhr);$ext(Xhr,{counter:0,showSpinner:function(){if(this.Options.spinner)$(this.Options.spinner).show(this.Options.spinnerFx,{duration:100})},hideSpinner:function(){if(this.Options.spinner)$(this.Options.spinner).hide(this.Options.spinnerFx,{duration:100})}});Xhr.onCreate(function(){this.counter++;this.showSpinner()}).onComplete(function(){this.counter--;if(this.counter<1)this.hideSpinner()}).onCancel(function(){this.counter--;if(this.counter<1)this.hideSpinner()});Form.addMethods({send:function(o){o=o||{};o['method']=o['method']||this.method||'post';new Xhr(this.get('action')||document.location.href,o).onRequest(this.disable.bind(this)).onComplete(this.enable.bind(this)).send(this);return this},remotize:function(o){this.onsubmit=function(){this.send.bind(this,Object.merge({spinner:this.first('.spinner')},o)).delay(20);return false};this.remote=true;return this},unremotize:function(){this.onsubmit=function(){};this.remote=false;return this}});Element.addMethods({load:function(u,o){new Xhr(u,Object.merge({method:'get'},o)).update(this);return this}});Xhr.IFramed=new Class({initialize:function(f){this.form=f;var i='xhr_frame_'+Math.random().toString().split('.').last();$E('div').insertTo(document.body).update('<iframe name="'+i+'" id="'+i+'" width="0" height="0" frameborder="0" src="about:blank"></iframe>');this.iframe=$(i);this.iframe.on('load',this.onLoad.bind(this))},send:function(){var o=this.form.onsubmit,a=this.form.target;this.form.onsubmit=function(){};this.form.target=this.iframe.id;this.form.submit();this.form.onsubmit=o;this.form.target=a},onLoad:function(){this.status=200;this.readyState=4;var d=window[this.iframe.id].document.documentElement;this.responseText=d?d.innerHTML:null;this.onreadystatechange()},open:function(){},abort:function(){},setRequestHeader:function(){},onreadystatechange:function(){}});var Fx=new Class(Observer,{extend:{EVENTS:$w('start finish cancel'),Durations:{'short':200,'normal':400,'long':800},Options:{fps:Browser.IE?40:60,duration:'normal',transition:'Sin',queue:true},Transitions:{Sin:function(a){return-(Math.cos(Math.PI*a)-1)/2},Cos:function(a){return Math.asin((a-0.5)*2)/Math.PI+0.5},Exp:function(a){return Math.pow(2,8*(a-1))},Log:function(a){return 1-Math.pow(2,-8*a)},Lin:function(a){return a}}},initialize:function(e,o){this.$super(o);this.element=$(e)},start:function(){if(this.queue(arguments))return this;this.prepare.apply(this,arguments);var o=this.options,d=Fx.Durations[o.duration]||o.duration;this.transition=Fx.Transitions[o.transition]||o.transition;this.steps=(d/1000*this.options.fps).ceil();this.number=1;return this.fire('start',this).startTimer()},finish:function(){return this.stopTimer().fire('finish').next()},cancel:function(){return this.stopTimer().fire('cancel').next()},pause:function(){return this.stopTimer()},resume:function(){return this.startTimer()},prepare:function(v){},render:function(d){},step:function(t){if(t.number>t.steps)t.finish();else{if(!t.w){t.w=true;t.render(t.transition(t.number/t.steps));t.w=false}t.number++}},startTimer:function(){this.timer=this.step.periodical((1000/this.options.fps).round(),this);return this},stopTimer:function(){if(this.timer)this.timer.stop();return this},queue:function(a){if(!this.element)return false;if(this.$ch)return this.$ch=false;var u=$uid(this.element),c;Fx.$ch=Fx.$ch||[];c=(Fx.$ch[u]=Fx.$ch[u]||[]);if(this.options.queue)c.push([a,this]);this.next=function(){var n=c.shift();n=c[0];if(n){n[1].$ch=true;n[1].start.apply(n[1],n[0])}return this};return this.options.queue&&c[0][1]!==this},next:function(){return this}});String.COLORS={maroon:'#800000',red:'#ff0000',orange:'#ffA500',yellow:'#ffff00',olive:'#808000',purple:'#800080',fuchsia:'#ff00ff',white:'#ffffff',lime:'#00ff00',green:'#008000',navy:'#000080',blue:'#0000ff',aqua:'#00ffff',teal:'#008080',black:'#000000',silver:'#c0c0c0',gray:'#808080',brown:'#a52a2a'};$ext(String.prototype,{toHex:function(){var m=/^#(\w)(\w)(\w)$/.exec(this);if(m)m="#"+m[1]+m[1]+m[2]+m[2]+m[3]+m[3];else if(m=/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.exec(this))m="#"+m.slice(1).map(function(b){b=(b-0).toString(16);return b.length==1?'0'+b:b}).join('');else m=String.COLORS[this]||this;return m},toRgb:function(a){var m=/#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/i.exec(this.toHex()||'');if(m){m=m.slice(1).map('toInt',16);m=a?m:'rgb('+m+')'}return m}});Fx.Morph=new Class(Fx,(function(){var C='Color',S='Style',W='Width',B='background',o='border',P='Position',h=B+C,t=$w('Top Left Right Bottom');var p=function(a,k,v){for(var i=0;i<v.length;i++)a.push(k+v[i])};var q=function(e,a){for(var i=0;i<4;i++){var f=t[i],c=o+f+S,d=o+f+W,b=o+f+C;if(e[c]!=a[c]){var s=this.element.style;if(e[c]=='none')s[d]='0px';s[c]=a[c];if(this._transp(e[b]))s[b]=this.element.getStyle(C)}}};var u=function(b){var a={},r=/[\d\.\-]+/g,m;for(var k in b){m=b[k].match(r);var v=m.map('toFloat');v.t=b[k].split(r);v.r=v.t[0]==='rgb(';if(v.t[0]===''||v.r)v.t.shift();for(var i=0;i<v.length;i++)v.t.splice(i*2,0,v[i]);a[k]=v}return a};return{prepare:function(s){var k=this._styleKeys(s),b=this._cloneStyle(this.element,k),a=this._endStyle(s,k);this._cleanStyles(b,a);this.before=u(b);this.after=u(a)},render:function(d){var b,a,v,s=this.element.style;for(var k in this.after){b=this.before[k];a=this.after[k];for(var i=0;i<a.length;i++){v=b[i]+(a[i]-b[i])*d;if(a.r)v=Math.round(v);a.t[i*2]=v}v=a.t.join('');if(a.r)v='rgb('+v;s[k]=v}},_endStyle:function(s,k){var d=$(this.element.cloneNode(true)).setStyle('position:absolute;z-index:-1;visibility:hidden').insertTo(this.element,'before').setWidth(this.element.sizes().x).setStyle(s);var a=this._cloneStyle(d,k);d.remove();return a},_cloneStyle:function(e,k){for(var i=0,l=k.length,s=e.computedStyles(),c={};i<l;i++)c[k[i]]=s[k[i]];return c},_styleKeys:function(s){var a=[],b=[S,C,W];for(var k in s){if(k.startsWith(o))for(var i=0;i<b.length;i++)for(var j=0;j<t.length;j++)a.push(o+t[j]+b[i]);else if(k=='margin'||k=='padding')p(a,k,t);else if(k.startsWith(B))p(a,B,[C,P,P+'X',P+'Y']);else if(k=='opacity'&&Browser.IE)a.push('filter');else a.push(k)}return a},_cleanStyles:function(b,a){var r=[];for(var k in a)if((k=='width'||k=='height')&&b[k]=='auto')b[k]=this.element['offset'+k.capitalize()]+'px';if(a.filter&&!b.filter)b.filter='alpha(opacity=100)';q.call(this,b,a);for(var k in a){if(a[k]!==b[k]&&!r.includes(k)&&/color/i.test(k)){if(Browser.Opera){a[k]=a[k].replace(/"/g,'');b[k]=b[k].replace(/"/g,'')}if(!this._transp(a[k]))a[k]=a[k].toRgb();if(!this._transp(b[k]))b[k]=b[k].toRgb();if(!a[k]||!b[k])a[k]=b[k]=''}if(/\d/.test(a[k])&&!/\d/.test(b[k]))b[k]=a[k].replace(/[\d\.\-]+/g,'0');if(a[k]===b[k]||r.includes(k)||!/\d/.test(b[k])||!/\d/.test(a[k])){delete(a[k]);delete(b[k])}}},_getBGColor:function(e){return[e].concat(e.parents()).map(function(n){var b=n.getStyle(h);return(b&&!this._transp(b))?b:null},this).compact().first()||'#FFF'},_transp:function(c){return c==='transparent'||c==='rgba(0, 0, 0, 0)'}}})());Fx.Highlight=new Class(Fx.Morph,{extend:{Options:Object.merge(Fx.Options,{color:'#FF8',transition:'Exp'})},prepare:function(s,e){var a=e||this.element.getStyle('backgroundColor');if(this._transp(a)){this.onFinish(function(){this.element.style.backgroundColor='transparent'});a=this._getBGColor(this.element)}this.element.style.backgroundColor=(s||this.options.color);return this.$super({backgroundColor:a})}});Fx.Twin=new Class(Fx.Morph,{finish:function(){if(this.how=='out')this.element.hide();return this.$super()},setHow:function(h){this.how=h||'toggle';if(this.how=='toggle')this.how=this.element.visible()?'out':'in'}});Fx.Slide=new Class(Fx.Twin,{extend:{Options:Object.merge(Fx.Options,{direction:'top'})},prepare:function(h){this.setHow(h);var e=this.element;e.show();this.sizes=e.sizes();this.styles={};$w('overflow height width marginTop marginLeft').each(function(k){this.styles[k]=e.style[k]},this);e.style.overflow='hidden';this.onFinish('_getBack').onCancel('_getBack');return this.$super(this._getStyle(this.options.direction))},_getBack:function(){this.element.setStyle(this.styles)},_getStyle:function(d){var f={},s=this.sizes,m='marginLeft',a='marginTop',b=this.styles[m].toFloat()||0,c=this.styles[a].toFloat()||0;if(this.how=='out'){f[['top','bottom'].includes(d)?'height':'width']='0px';if(d=='right')f[m]=b+s.x+'px';else if(d=='bottom')f[a]=c+s.y+'px'}else if(this.how=='in'){var e=this.element.style;if(['top','bottom'].includes(d)){f.height=s.y+'px';e.height='0px'}else{f.width=s.x+'px';e.width='0px'}if(d=='right'){f[m]=b+'px';e[m]=b+s.x+'px'}else if(d=='bottom'){f[a]=c+'px';e[a]=c+s.y+'px'}}return f}});Fx.Fade=new Class(Fx.Twin,{prepare:function(h){this.setHow(h);if(this.how=='in')this.element.setStyle({opacity:0}).show();return this.$super({opacity:isNumber(h)?h:this.how=='in'?1:0})}});Fx.Scroll=new Class(Fx,{prepare:function(v){this.before={};this.after=v;if(defined(v.x))this.before.x=this.element.scrollLeft;if(defined(v.y))this.before.y=this.element.scrollTop},render:function(d){var b=this.before;for(var k in b)this.element['scroll'+(k=='x'?'Left':'Top')]=b[k]+(this.after[k]-b[k])*d}});Element.addMethods((function(m){var b=m.hide,d=m.show,c=m.scrollTo;return{hide:function(f,o){return f?this.fx(f,['out',o]):b.call(this)},show:function(f,o){return f?this.fx(f,['in',o]):d.call(this)},morph:function(s,o){return this.fx('morph',[s,o||{}])},highlight:function(){return this.fx('highlight',arguments)},fade:function(){return this.fx('fade',arguments)},slide:function(){return this.fx('slide',arguments)},scroll:function(v,o){return this.fx('scroll',[v,o||{}])},scrollTo:function(v,o){return isHash(o)?this.scroll(v,o):c.apply(this,arguments)},fx:function(n,a){var a=$A(a).compact(),o=isHash(a.last())?a.pop():{},f=new Fx[n.capitalize()](this,o);f.start.apply(f,a);return this}}})(Element.Methods));if(!document.querySelector)(function(){var r=/(\/right)([^\/]+)$/;var c=$A(document.getElementsByTagName('script')).map('src').compact().first('match',r);if(c)document.write('<scr'+'ipt src="'+c.replace(r,'$1-olds$2')+'"></scr'+'ipt>')})();
|
@@ -0,0 +1,18 @@
|
|
1
|
+
var wee = {};
|
2
|
+
|
3
|
+
wee._update_elements = function(e) {
|
4
|
+
var id = e.get('id');
|
5
|
+
if (id)
|
6
|
+
$(id).update(e);
|
7
|
+
else
|
8
|
+
e.insertTo(document.body);
|
9
|
+
};
|
10
|
+
|
11
|
+
wee._update_callback = function(r) {
|
12
|
+
new Element('div', {html: r.text}).subNodes().each(wee._update_elements);
|
13
|
+
};
|
14
|
+
|
15
|
+
wee.update = function(url) {
|
16
|
+
new Xhr(url, {method: 'get'}).onSuccess(wee._update_callback).send();
|
17
|
+
return false;
|
18
|
+
};
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'wee/component'
|
2
|
+
require 'wee/external_resource'
|
3
|
+
|
4
|
+
module Wee
|
5
|
+
|
6
|
+
#
|
7
|
+
# A RootComponent has a special instanciate class method that makes it more
|
8
|
+
# comfortable for root components.
|
9
|
+
#
|
10
|
+
class RootComponent < Component
|
11
|
+
|
12
|
+
def self.run(*params, &block)
|
13
|
+
Wee.run(self, *params, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def title
|
17
|
+
self.class.name.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Returns an array of ExternalResource objects required for this
|
22
|
+
# RootComponent.
|
23
|
+
#
|
24
|
+
def self.external_resources
|
25
|
+
self.depends.flatten.select {|cls| cls <= Wee::ExternalResource }.uniq.
|
26
|
+
map {|cls| cls.new }
|
27
|
+
end
|
28
|
+
|
29
|
+
def stylesheets
|
30
|
+
self.class.external_resources.map {|ext_res| ext_res.stylesheets}.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
def javascripts
|
34
|
+
self.class.external_resources.map {|ext_res| ext_res.javascripts}.flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.instanciate(*args, &block)
|
38
|
+
obj = new(*args, &block)
|
39
|
+
obj.add_decoration Wee::PageDecoration.new(obj.title, obj.stylesheets, obj.javascripts)
|
40
|
+
return obj
|
41
|
+
end
|
42
|
+
|
43
|
+
end # class RootComponent
|
44
|
+
|
45
|
+
end # module Wee
|
data/lib/wee/session.rb
ADDED
@@ -0,0 +1,366 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'wee/lru_cache'
|
3
|
+
require 'wee/id_generator'
|
4
|
+
require 'wee/renderer'
|
5
|
+
|
6
|
+
module Wee
|
7
|
+
|
8
|
+
class Session
|
9
|
+
|
10
|
+
include LRUCache::Item
|
11
|
+
|
12
|
+
#
|
13
|
+
# The default serializer, when no continuations are going to be used.
|
14
|
+
# Ensures that only one request of the same session is executed at
|
15
|
+
# the same time.
|
16
|
+
#
|
17
|
+
class MutexSerializer < Mutex
|
18
|
+
def call(env)
|
19
|
+
synchronize { env['wee.session'].call(env) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# This serializer ensures that all requests of a session are
|
25
|
+
# executed within the same thread. This is required if continuations
|
26
|
+
# are going to be used.
|
27
|
+
#
|
28
|
+
# You can run multiple sessions within the same ThreadSerializer, or
|
29
|
+
# allocate one ThreadSerializer (and as such one Thread) per session
|
30
|
+
# as you want.
|
31
|
+
#
|
32
|
+
class ThreadSerializer
|
33
|
+
def initialize
|
34
|
+
@in, @out = Queue.new, Queue.new
|
35
|
+
@thread = Thread.new {
|
36
|
+
Thread.abort_on_exception = true
|
37
|
+
while true
|
38
|
+
env = @in.pop
|
39
|
+
@out.push(env['wee.session'].call(env))
|
40
|
+
end
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def call(env)
|
45
|
+
@in.push(env)
|
46
|
+
@out.pop
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Page
|
51
|
+
attr_accessor :id, :state, :callbacks
|
52
|
+
include LRUCache::Item
|
53
|
+
def initialize(id=nil, state=nil, callbacks=nil)
|
54
|
+
@id, @state, @callbacks = id, state, callbacks
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class AbortProcessing < Exception
|
59
|
+
attr_reader :response
|
60
|
+
def initialize(response)
|
61
|
+
@response = response
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# The (application-wide) unique id of this session.
|
67
|
+
#
|
68
|
+
attr_accessor :id
|
69
|
+
|
70
|
+
#
|
71
|
+
# Points to the Wee::Application object this session belongs to.
|
72
|
+
#
|
73
|
+
attr_accessor :application
|
74
|
+
|
75
|
+
#
|
76
|
+
# Expire the session after this number of seconds of inactivity. If this
|
77
|
+
# value is +nil+, the Session will never expire due to inactivity.
|
78
|
+
# (but still may expire for example due to <i>max_lifetime</i>).
|
79
|
+
#
|
80
|
+
# Default: <tt>1800</tt> seconds (30 minutes)
|
81
|
+
#
|
82
|
+
attr_accessor :expire_after
|
83
|
+
|
84
|
+
#
|
85
|
+
# The maximum lifetime of this session in seconds. A value of +nil+ means
|
86
|
+
# infinite lifetime.
|
87
|
+
#
|
88
|
+
# Default: <tt>nil</tt> (infinite lifetime)
|
89
|
+
#
|
90
|
+
attr_accessor :max_lifetime
|
91
|
+
|
92
|
+
#
|
93
|
+
# The maximum number of requests this session is allowed to serve.
|
94
|
+
# A value of +nil+ means no limitation.
|
95
|
+
#
|
96
|
+
# Default: <tt>nil</tt> (infinite number of requests)
|
97
|
+
#
|
98
|
+
attr_accessor :max_requests
|
99
|
+
|
100
|
+
#
|
101
|
+
# Creates a new session.
|
102
|
+
#
|
103
|
+
def initialize(root_component, serializer=nil, page_cache_capacity=20)
|
104
|
+
@root_component = root_component
|
105
|
+
@page_cache = Wee::LRUCache.new(page_cache_capacity)
|
106
|
+
@page_ids = Wee::IdGenerator::Sequential.new
|
107
|
+
@current_page = nil
|
108
|
+
|
109
|
+
@running = true
|
110
|
+
|
111
|
+
@expire_after = 30*60
|
112
|
+
@max_lifetime = nil
|
113
|
+
@max_requests = nil
|
114
|
+
|
115
|
+
@last_access = @creation_time = Time.now
|
116
|
+
@request_count = 0
|
117
|
+
|
118
|
+
@serializer = serializer || MutexSerializer.new
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Terminates the session.
|
123
|
+
#
|
124
|
+
# This will usually not immediatly terminate the session from running, but
|
125
|
+
# further requests will not be answered.
|
126
|
+
#
|
127
|
+
def terminate
|
128
|
+
@running = false
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Queries whether the session is still alive.
|
133
|
+
#
|
134
|
+
def alive?
|
135
|
+
now = Time.now
|
136
|
+
return false if not @running
|
137
|
+
return false if @expire_after and now - @last_access > @expire_after
|
138
|
+
return false if @max_lifetime and now - @creation_time > @max_lifetime
|
139
|
+
return false if @max_requests and @request_count >= @max_requests
|
140
|
+
return true
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Queries whether the session is dead.
|
145
|
+
#
|
146
|
+
def dead?
|
147
|
+
not alive?
|
148
|
+
end
|
149
|
+
|
150
|
+
#
|
151
|
+
# Returns some statistics
|
152
|
+
#
|
153
|
+
def statistics
|
154
|
+
now = Time.now
|
155
|
+
{
|
156
|
+
:last_access => @last_access, # The time when this session was last accessed
|
157
|
+
:inactivity => now - @last_access, # The number of seconds of inactivity
|
158
|
+
:creation_time => @creation_time, # The time at which this session was created
|
159
|
+
:lifetime => now - @creation_time, # The lifetime of this session in seconds
|
160
|
+
:request_count => @request_count # The number of requests served by this session
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
#
|
165
|
+
# Returns the current session (thread-local).
|
166
|
+
#
|
167
|
+
def self.current
|
168
|
+
Thread.current[:wee_session] || (raise "Not in session")
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Handles a web request.
|
173
|
+
#
|
174
|
+
def call(env)
|
175
|
+
if env['wee.session']
|
176
|
+
# we are already serialized
|
177
|
+
raise if env['wee.session'] != self
|
178
|
+
begin
|
179
|
+
Thread.current[:wee_session] = self
|
180
|
+
@request_count += 1
|
181
|
+
@last_access = Time.now
|
182
|
+
awake
|
183
|
+
response = handle(env)
|
184
|
+
sleep
|
185
|
+
return response
|
186
|
+
ensure
|
187
|
+
Thread.current[:wee_session] = nil
|
188
|
+
end
|
189
|
+
else
|
190
|
+
env['wee.session'] = self
|
191
|
+
@serializer.call(env)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
# Send a premature response
|
197
|
+
#
|
198
|
+
def send_response(response)
|
199
|
+
raise AbortProcessing.new(response)
|
200
|
+
end
|
201
|
+
|
202
|
+
protected
|
203
|
+
|
204
|
+
#
|
205
|
+
# Is called before <i>process_request</i> is invoked.
|
206
|
+
#
|
207
|
+
# Can be used e.g. to setup a database connection.
|
208
|
+
#
|
209
|
+
def awake
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# Is called after <i>process_request</i> is run.
|
214
|
+
#
|
215
|
+
# Can be used e.g. to release a database connection.
|
216
|
+
#
|
217
|
+
def sleep
|
218
|
+
end
|
219
|
+
|
220
|
+
#
|
221
|
+
# The main routine where the request is processed.
|
222
|
+
#
|
223
|
+
def handle(env)
|
224
|
+
request = Wee::Request.new(env)
|
225
|
+
@request = request # CONTINUATIONS!
|
226
|
+
page = @page_cache.fetch(request.page_id)
|
227
|
+
|
228
|
+
if page
|
229
|
+
if page != @current_page
|
230
|
+
@current_page = nil
|
231
|
+
page.state.restore
|
232
|
+
@current_page = page
|
233
|
+
end
|
234
|
+
|
235
|
+
if request.render?
|
236
|
+
return render(request, page).finish
|
237
|
+
else # request.action?
|
238
|
+
return action(request, page).finish
|
239
|
+
end
|
240
|
+
else
|
241
|
+
#
|
242
|
+
# either no or invalid page_id specified. reset to initial state (or
|
243
|
+
# create initial state if no such exists yet)
|
244
|
+
#
|
245
|
+
@initial_state ||= take_snapshot()
|
246
|
+
new_page = Page.new(@page_ids.next, @initial_state, nil)
|
247
|
+
@page_cache.store(new_page.id, new_page)
|
248
|
+
|
249
|
+
url = request.build_url(:page_id => new_page.id)
|
250
|
+
if request.page_id
|
251
|
+
return Wee::RefreshResponse.new("Invalid or expired page", url).finish
|
252
|
+
else
|
253
|
+
return Wee::RedirectResponse.new(url).finish
|
254
|
+
end
|
255
|
+
end
|
256
|
+
ensure
|
257
|
+
@request = nil
|
258
|
+
end
|
259
|
+
|
260
|
+
def render_ajax_proc(block, component)
|
261
|
+
proc {
|
262
|
+
r = component.renderer_class.new
|
263
|
+
r.session = self
|
264
|
+
r.request = @request
|
265
|
+
r.response = Wee::Response.new
|
266
|
+
r.document = Wee::HtmlDocument.new
|
267
|
+
r.callbacks = @page.callbacks
|
268
|
+
r.current_component = component
|
269
|
+
|
270
|
+
begin
|
271
|
+
block.call(r)
|
272
|
+
ensure
|
273
|
+
r.close
|
274
|
+
end
|
275
|
+
|
276
|
+
r.response << r.document.to_s
|
277
|
+
send_response(r.response)
|
278
|
+
}
|
279
|
+
end
|
280
|
+
|
281
|
+
public :render_ajax_proc
|
282
|
+
|
283
|
+
def render(request, page)
|
284
|
+
r = Wee::Renderer.new
|
285
|
+
r.session = self
|
286
|
+
r.request = request
|
287
|
+
r.response = Wee::GenericResponse.new
|
288
|
+
r.document = Wee::HtmlDocument.new
|
289
|
+
r.callbacks = Wee::Callbacks.new
|
290
|
+
|
291
|
+
begin
|
292
|
+
@root_component.decoration.render!(r)
|
293
|
+
r.close
|
294
|
+
r.response << r.document.to_s
|
295
|
+
rescue AbortProcessing => abort
|
296
|
+
r.response = abort.response
|
297
|
+
end
|
298
|
+
|
299
|
+
page.callbacks = r.callbacks
|
300
|
+
return r.response
|
301
|
+
end
|
302
|
+
|
303
|
+
def action(request, page)
|
304
|
+
@current_page = nil
|
305
|
+
|
306
|
+
begin
|
307
|
+
@page = page # CONTINUATIONS!
|
308
|
+
action_callback = page.callbacks.with_triggered(request.fields) do
|
309
|
+
@root_component.decoration.process_callbacks(page.callbacks)
|
310
|
+
end
|
311
|
+
if action_callback
|
312
|
+
action_callback.call
|
313
|
+
elsif request.ajax?
|
314
|
+
#
|
315
|
+
# An action request with an action-id without a corresponding
|
316
|
+
# registered action callback is considered an invalid request.
|
317
|
+
#
|
318
|
+
# This can happen for AJAX update requests and indicates that
|
319
|
+
# two or more requests are send out too quickly; the first
|
320
|
+
# succeed, renders and updates a div-tag and registers
|
321
|
+
# a new callback (the old is unregistered). The following
|
322
|
+
# request still uses the old callback id, but now the
|
323
|
+
# callback id has already been unregistered by the previous
|
324
|
+
# request.
|
325
|
+
#
|
326
|
+
return NotFoundResponse.new
|
327
|
+
end
|
328
|
+
rescue AbortProcessing => abort
|
329
|
+
page = @page # CONTINUATIONS!
|
330
|
+
if abort.response
|
331
|
+
#
|
332
|
+
# replace the state of the current page
|
333
|
+
#
|
334
|
+
@current_page = page
|
335
|
+
page.state = take_snapshot()
|
336
|
+
@page_cache.store(page.id, page)
|
337
|
+
return abort.response
|
338
|
+
else
|
339
|
+
# pass on - this is a premature response from Component#call
|
340
|
+
end
|
341
|
+
end
|
342
|
+
request = @request # CONTINUATIONS!
|
343
|
+
|
344
|
+
#
|
345
|
+
# create new page (state)
|
346
|
+
#
|
347
|
+
new_page = Page.new(@page_ids.next, take_snapshot(), nil)
|
348
|
+
@page_cache.store(new_page.id, new_page)
|
349
|
+
@current_page = new_page
|
350
|
+
|
351
|
+
url = request.build_url(:page_id => new_page.id)
|
352
|
+
return Wee::RedirectResponse.new(url)
|
353
|
+
end
|
354
|
+
|
355
|
+
#
|
356
|
+
# This method takes a snapshot from the current state of the root component
|
357
|
+
# and returns it.
|
358
|
+
#
|
359
|
+
def take_snapshot
|
360
|
+
@root_component.decoration.state(s = Wee::State.new)
|
361
|
+
return s.freeze
|
362
|
+
end
|
363
|
+
|
364
|
+
end # class Session
|
365
|
+
|
366
|
+
end # module Wee
|