mullen-wee 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/README.rdoc +127 -0
  2. data/Rakefile +25 -0
  3. data/aWee.gemspec +26 -0
  4. data/examples/ObjectSpaceBrowser.rb +191 -0
  5. data/examples/ajax.rb +73 -0
  6. data/examples/apotomo-webhunter/main.rb +75 -0
  7. data/examples/apotomo-webhunter/public/images/bear_trap_charged.png +0 -0
  8. data/examples/apotomo-webhunter/public/images/bear_trap_snapped.png +0 -0
  9. data/examples/apotomo-webhunter/public/images/cheese.png +0 -0
  10. data/examples/apotomo-webhunter/public/images/dark_forest.jpg +0 -0
  11. data/examples/apotomo-webhunter/public/images/mouse.png +0 -0
  12. data/examples/apotomo-webhunter/public/javascripts/jquery-1.3.2.min.js +19 -0
  13. data/examples/apotomo-webhunter/public/javascripts/wee-jquery.js +19 -0
  14. data/examples/apotomo-webhunter/public/stylesheets/forest.css +33 -0
  15. data/examples/arc_challenge.rb +42 -0
  16. data/examples/arc_challenge2.rb +46 -0
  17. data/examples/cheese_task.rb +27 -0
  18. data/examples/continuations.rb +28 -0
  19. data/examples/demo.rb +135 -0
  20. data/examples/demo/calculator.rb +63 -0
  21. data/examples/demo/calendar.rb +333 -0
  22. data/examples/demo/counter.rb +38 -0
  23. data/examples/demo/editable_counter.rb +36 -0
  24. data/examples/demo/example.rb +142 -0
  25. data/examples/demo/file_upload.rb +19 -0
  26. data/examples/demo/messagebox.rb +15 -0
  27. data/examples/demo/radio.rb +33 -0
  28. data/examples/demo/window.rb +71 -0
  29. data/examples/hw.rb +11 -0
  30. data/examples/i18n/app.rb +16 -0
  31. data/examples/i18n/locale/de/app.po +25 -0
  32. data/examples/i18n/locale/en/app.po +25 -0
  33. data/examples/pager.rb +102 -0
  34. data/lib/wee.rb +109 -0
  35. data/lib/wee/application.rb +89 -0
  36. data/lib/wee/callback.rb +109 -0
  37. data/lib/wee/component.rb +363 -0
  38. data/lib/wee/decoration.rb +251 -0
  39. data/lib/wee/dialog.rb +171 -0
  40. data/lib/wee/external_resource.rb +39 -0
  41. data/lib/wee/html_brushes.rb +795 -0
  42. data/lib/wee/html_canvas.rb +254 -0
  43. data/lib/wee/html_document.rb +52 -0
  44. data/lib/wee/html_writer.rb +71 -0
  45. data/lib/wee/id_generator.rb +81 -0
  46. data/lib/wee/jquery.rb +11 -0
  47. data/lib/wee/jquery/jquery-1.3.2.min.js +19 -0
  48. data/lib/wee/jquery/wee-jquery.js +19 -0
  49. data/lib/wee/locale.rb +56 -0
  50. data/lib/wee/lru_cache.rb +91 -0
  51. data/lib/wee/presenter.rb +44 -0
  52. data/lib/wee/renderer.rb +72 -0
  53. data/lib/wee/request.rb +56 -0
  54. data/lib/wee/response.rb +68 -0
  55. data/lib/wee/rightjs.rb +11 -0
  56. data/lib/wee/rightjs/rightjs-1.5.2.min.js +9 -0
  57. data/lib/wee/rightjs/wee-rightjs.js +18 -0
  58. data/lib/wee/root_component.rb +45 -0
  59. data/lib/wee/session.rb +366 -0
  60. data/lib/wee/state.rb +102 -0
  61. data/lib/wee/task.rb +16 -0
  62. data/test/bm_render.rb +34 -0
  63. data/test/component_spec.rb +40 -0
  64. data/test/stress/plotter.rb +84 -0
  65. data/test/stress/stress_client.rb +51 -0
  66. data/test/stress/stress_local.rb +86 -0
  67. data/test/stress/stress_server.rb +83 -0
  68. data/test/test_component.rb +106 -0
  69. data/test/test_html_canvas.rb +25 -0
  70. data/test/test_html_writer.rb +32 -0
  71. data/test/test_lru_cache.rb +51 -0
  72. data/test/test_request.rb +42 -0
  73. metadata +185 -0
@@ -0,0 +1,11 @@
1
+ require 'wee/external_resource'
2
+
3
+ class Wee::RightJS < Wee::ExternalResource
4
+ def javascripts
5
+ mount_path_relative('rightjs-1.5.2.min.js', 'wee-rightjs.js')
6
+ end
7
+
8
+ def resource_dir
9
+ file_relative(__FILE__, 'rightjs')
10
+ end
11
+ end
@@ -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
@@ -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