From 0b34258466c58a805a2cbfe7ef134385b26fed94 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Thu, 1 May 2008 11:08:20 +0000 Subject: [PATCH 01/16] =?utf8?q?FIX=20probl=C3=A8me=20de=20l'encapsulation?= =?utf8?q?=20de=20JSON=20dans=20de=20l'xml.=20jQuery.js=20a=20=C3=A9t?= =?utf8?q?=C3=A9=20modifi=C3=A9...=20pas=20top.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- doc/TODO.txt | 6 +- js/euphorik.js | 3 +- js/jquery.js | 3420 ++++++++++++++++++++++++++++- js/pageMinichat.js | 10 +- modules/erl/euphorik_requests.erl | 22 +- 5 files changed, 3416 insertions(+), 45 deletions(-) diff --git a/doc/TODO.txt b/doc/TODO.txt index 4528683..91d9bda 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -153,7 +153,6 @@ 3 : Peu grave [1] Lors de l'extraction d'une conv il arrive que la conv extracté soit bien créée mais vide, le bouton ne ferme pas la conv (très étrange, bug de firefox?) -[1] Comme le json du client est encapsulé dans de l'xml il faut utiliser des xml entities pour les charactères <, > et &. Il faudrait, absolument éviter cette encapsulation moisie. [2] Quand on revient en arrière dans firefox le message en rédaction est perdu [2] En changeant de page puis en revenant sur la page principale les smiles ne sont plus highlightés lorsque le curseur les survol [2] Dans certains cas (à déterminer) les message-box (message d'information affiché tout en haut de la page) ne s'affiche plus (on ne voit que un petit bout dépassé) @@ -161,6 +160,8 @@ [2] cliquer sur les smiles ne marche pas sous IE [2] le return ne marche pas sous IE [2] Lors d'un login ou d'un logout il faut faire un full refresh +[2] jQuery définit l'option "X-Requested-With" à "XMLHttpRequest dans l'entête HTTP. De ce fait Yaws exige absolument de l'xml... + Solution actuelle : jquery.js est modifié pour ne plus définir cette option. Trouver un autre moyen plus élégant. [3] Un message envoyé sans être authentifié ne sera pas taggé comme appartenant à l'utilisateur. a) L'utilisateur attend des messages SANS donné de cookie car il n'est pas authentifié b) L'utilisateur envoie un message @@ -172,7 +173,8 @@ [3] Amélioration des requêtes MNESIA, voir : http://mail.google.com/mail/#label/Erlang+mailing-list/117f688280569a58 [3] la page est completement rechargé après avoir submité le profile dans opera [3] après le login un '?' s'ajoute à l'adresse (opera, firefox) - + +[ok] Comme le json du client est encapsulé dans de l'xml il faut utiliser des xml entities pour les charactères <, > et &. Il faudrait, absolument éviter cette encapsulation moisie. [ok] Au bout d'un moment opera n'écoute plus rien... et donc n'affiche plus les nouveaux messages.. [ok] La méthod traiterSmiles est très lourde ! (4 secondes pour 80 appels (une page normale)) [ok] Utiliser Alpha truc à la place d'opacity sous explorer diff --git a/js/euphorik.js b/js/euphorik.js index 99a461f..45b3cbd 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -106,8 +106,7 @@ var messageType = {informatif: 0, question: 1, erreur: 2} */ Util.prototype.jsonVersAction = function(json) { - // FIXME : ne plus encapsuler json dans de l'xml (problème avec yaws) - return {action: "" + JSON.stringify(json) + "" } + return {action : JSON.stringify(json) } } Util.prototype.md5 = function(chaine) diff --git a/js/jquery.js b/js/jquery.js index 3747929..b03c3fb 100755 --- a/js/jquery.js +++ b/js/jquery.js @@ -1,3 +1,4 @@ +(function(){ /* * jQuery 1.2.3 - New Wave Javascript * @@ -8,25 +9,3400 @@ * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $ * $Rev: 4663 $ */ -(function(){if(window.jQuery)var _jQuery=window.jQuery;var jQuery=window.jQuery=function(selector,context){return new jQuery.prototype.init(selector,context);};if(window.$)var _$=window.$;window.$=jQuery;var quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;var isSimple=/^.[^:#\[\.]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;return this;}else if(typeof selector=="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1])selector=jQuery.clean([match[1]],context);else{var elem=document.getElementById(match[3]);if(elem)if(elem.id!=match[3])return jQuery().find(selector);else{this[0]=elem;this.length=1;return this;}else -selector=[];}}else -return new jQuery(context).find(selector);}else if(jQuery.isFunction(selector))return new jQuery(document)[jQuery.fn.ready?"ready":"load"](selector);return this.setArray(selector.constructor==Array&&selector||(selector.jquery||selector.length&&selector!=window&&!selector.nodeType&&selector[0]!=undefined&&selector[0].nodeType)&&jQuery.makeArray(selector)||[selector]);},jquery:"1.2.3",size:function(){return this.length;},length:0,get:function(num){return num==undefined?jQuery.makeArray(this):this[num];},pushStack:function(elems){var ret=jQuery(elems);ret.prevObject=this;return ret;},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this;},each:function(callback,args){return jQuery.each(this,callback,args);},index:function(elem){var ret=-1;this.each(function(i){if(this==elem)ret=i;});return ret;},attr:function(name,value,type){var options=name;if(name.constructor==String)if(value==undefined)return this.length&&jQuery[type||"attr"](this[0],name)||undefined;else{options={};options[name]=value;}return this.each(function(i){for(name in options)jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name));});},css:function(key,value){if((key=='width'||key=='height')&&parseFloat(value)<0)value=undefined;return this.attr(key,value,"curCSS");},text:function(text){if(typeof text!="object"&&text!=null)return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text));var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8)ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this]);});});return ret;},wrapAll:function(html){if(this[0])jQuery(html,this[0].ownerDocument).clone().insertBefore(this[0]).map(function(){var elem=this;while(elem.firstChild)elem=elem.firstChild;return elem;}).append(this);return this;},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html);});},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html);});},append:function(){return this.domManip(arguments,true,false,function(elem){if(this.nodeType==1)this.appendChild(elem);});},prepend:function(){return this.domManip(arguments,true,true,function(elem){if(this.nodeType==1)this.insertBefore(elem,this.firstChild);});},before:function(){return this.domManip(arguments,false,false,function(elem){this.parentNode.insertBefore(elem,this);});},after:function(){return this.domManip(arguments,false,true,function(elem){this.parentNode.insertBefore(elem,this.nextSibling);});},end:function(){return this.prevObject||jQuery([]);},find:function(selector){var elems=jQuery.map(this,function(elem){return jQuery.find(selector,elem);});return this.pushStack(/[^+>] [^+>]/.test(selector)||selector.indexOf("..")>-1?jQuery.unique(elems):elems);},clone:function(events){var ret=this.map(function(){if(jQuery.browser.msie&&!jQuery.isXMLDoc(this)){var clone=this.cloneNode(true),container=document.createElement("div");container.appendChild(clone);return jQuery.clean([container.innerHTML])[0];}else -return this.cloneNode(true);});var clone=ret.find("*").andSelf().each(function(){if(this[expando]!=undefined)this[expando]=null;});if(events===true)this.find("*").andSelf().each(function(i){if(this.nodeType==3)return;var events=jQuery.data(this,"events");for(var type in events)for(var handler in events[type])jQuery.event.add(clone[i],type,events[type][handler],events[type][handler].data);});return ret;},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i);})||jQuery.multiFilter(selector,this));},not:function(selector){if(selector.constructor==String)if(isSimple.test(selector))return this.pushStack(jQuery.multiFilter(selector,this,true));else -selector=jQuery.multiFilter(selector,this);var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector;});},add:function(selector){return!selector?this:this.pushStack(jQuery.merge(this.get(),selector.constructor==String?jQuery(selector).get():selector.length!=undefined&&(!selector.nodeName||jQuery.nodeName(selector,"form"))?selector:[selector]));},is:function(selector){return selector?jQuery.multiFilter(selector,this).length>0:false;},hasClass:function(selector){return this.is("."+selector);},val:function(value){if(value==undefined){if(this.length){var elem=this[0];if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0)return null;for(var i=one?index:0,max=one?index+1:options.length;i=0||jQuery.inArray(this.name,value)>=0);else if(jQuery.nodeName(this,"select")){var values=value.constructor==Array?value:[value];jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0);});if(!values.length)this.selectedIndex=-1;}else -this.value=value;});},html:function(value){return value==undefined?(this.length?this[0].innerHTML:null):this.empty().append(value);},replaceWith:function(value){return this.after(value).remove();},eq:function(i){return this.slice(i,i+1);},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments));},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},andSelf:function(){return this.add(this.prevObject);},data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value==null){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data==undefined&&this.length)data=jQuery.data(this[0],key);return data==null&&parts[1]?this.data(parts[0]):data;}else -return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value);});},removeData:function(key){return this.each(function(){jQuery.removeData(this,key);});},domManip:function(args,table,reverse,callback){var clone=this.length>1,elems;return this.each(function(){if(!elems){elems=jQuery.clean(args,this.ownerDocument);if(reverse)elems.reverse();}var obj=this;if(table&&jQuery.nodeName(this,"table")&&jQuery.nodeName(elems[0],"tr"))obj=this.getElementsByTagName("tbody")[0]||this.appendChild(this.ownerDocument.createElement("tbody"));var scripts=jQuery([]);jQuery.each(elems,function(){var elem=clone?jQuery(this).clone(true)[0]:this;if(jQuery.nodeName(elem,"script")){scripts=scripts.add(elem);}else{if(elem.nodeType==1)scripts=scripts.add(jQuery("script",elem).remove());callback.call(obj,elem);}});scripts.each(evalScript);});}};jQuery.prototype.init.prototype=jQuery.prototype;function evalScript(i,elem){if(elem.src)jQuery.ajax({url:elem.src,async:false,dataType:"script"});else -jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"");if(elem.parentNode)elem.parentNode.removeChild(elem);}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(target.constructor==Boolean){deep=target;target=arguments[1]||{};i=2;}if(typeof target!="object"&&typeof target!="function")target={};if(length==1){target=this;i=0;}for(;i-1;}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name];}callback.call(elem);for(var name in options)elem.style[name]=old[name];},css:function(elem,name,force){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;var padding=0,border=0;jQuery.each(which,function(){padding+=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0;border+=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0;});val-=Math.round(padding+border);}if(jQuery(elem).is(":visible"))getWH();else -jQuery.swap(elem,props,getWH);return Math.max(0,val);}return jQuery.curCSS(elem,name,force);},curCSS:function(elem,name,force){var ret;function color(elem){if(!jQuery.browser.safari)return false;var ret=document.defaultView.getComputedStyle(elem,null);return!ret||ret.getPropertyValue("color")=="";}if(name=="opacity"&&jQuery.browser.msie){ret=jQuery.attr(elem.style,"opacity");return ret==""?"1":ret;}if(jQuery.browser.opera&&name=="display"){var save=elem.style.outline;elem.style.outline="0 solid black";elem.style.outline=save;}if(name.match(/float/i))name=styleFloat;if(!force&&elem.style&&elem.style[name])ret=elem.style[name];else if(document.defaultView&&document.defaultView.getComputedStyle){if(name.match(/float/i))name="float";name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var getComputedStyle=document.defaultView.getComputedStyle(elem,null);if(getComputedStyle&&!color(elem))ret=getComputedStyle.getPropertyValue(name);else{var swap=[],stack=[];for(var a=elem;a&&color(a);a=a.parentNode)stack.unshift(a);for(var i=0;i]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+">";});var tags=jQuery.trim(elem).toLowerCase(),div=context.createElement("div");var wrap=!tags.indexOf("",""]||!tags.indexOf("",""]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"","
"]||!tags.indexOf("",""]||(!tags.indexOf("",""]||!tags.indexOf("",""]||jQuery.browser.msie&&[1,"div
","
"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--)div=div.lastChild;if(jQuery.browser.msie){var tbody=!tags.indexOf(""&&tags.indexOf("=0;--j)if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length)tbody[j].parentNode.removeChild(tbody[j]);if(/^\s/.test(elem))div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild);}elem=jQuery.makeArray(div.childNodes);}if(elem.length===0&&(!jQuery.nodeName(elem,"form")&&!jQuery.nodeName(elem,"select")))return;if(elem[0]==undefined||jQuery.nodeName(elem,"form")||elem.options)ret.push(elem);else -ret=jQuery.merge(ret,elem);});return ret;},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8)return undefined;var fix=jQuery.isXMLDoc(elem)?{}:jQuery.props;if(name=="selected"&&jQuery.browser.safari)elem.parentNode.selectedIndex;if(fix[name]){if(value!=undefined)elem[fix[name]]=value;return elem[fix[name]];}else if(jQuery.browser.msie&&name=="style")return jQuery.attr(elem.style,"cssText",value);else if(value==undefined&&jQuery.browser.msie&&jQuery.nodeName(elem,"form")&&(name=="action"||name=="method"))return elem.getAttributeNode(name).nodeValue;else if(elem.tagName){if(value!=undefined){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode)throw"type property can't be changed";elem.setAttribute(name,""+value);}if(jQuery.browser.msie&&/href|src/.test(name)&&!jQuery.isXMLDoc(elem))return elem.getAttribute(name,2);return elem.getAttribute(name);}else{if(name=="opacity"&&jQuery.browser.msie){if(value!=undefined){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseFloat(value).toString()=="NaN"?"":"alpha(opacity="+value*100+")");}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100).toString():"";}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase();});if(value!=undefined)elem[name]=value;return elem[name];}},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"");},makeArray:function(array){var ret=[];if(typeof array!="array")for(var i=0,length=array.length;i*",this).remove();while(this.firstChild)this.removeChild(this.firstChild);}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments);};});jQuery.each(["Height","Width"],function(i,name){var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?jQuery.browser.opera&&document.body["client"+name]||jQuery.browser.safari&&window["inner"+name]||document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(Math.max(document.body["scroll"+name],document.documentElement["scroll"+name]),Math.max(document.body["offset"+name],document.documentElement["offset"+name])):size==undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,size.constructor==String?size:size+"px");};});var chars=jQuery.browser.safari&&parseInt(jQuery.browser.version)<417?"(?:[\\w*_-]|\\\\.)":"(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",quickChild=new RegExp("^>\\s*("+chars+"+)"),quickID=new RegExp("^("+chars+"+)(#)("+chars+"+)"),quickClass=new RegExp("^([#.]?)("+chars+"*)");jQuery.extend({expr:{"":function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},"#":function(a,i,m){return a.getAttribute("id")==m[2];},":":{lt:function(a,i,m){return im[3]-0;},nth:function(a,i,m){return m[3]-0==i;},eq:function(a,i,m){return m[3]-0==i;},first:function(a,i){return i==0;},last:function(a,i,m,r){return i==r.length-1;},even:function(a,i){return i%2==0;},odd:function(a,i){return i%2;},"first-child":function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},"last-child":function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},"only-child":function(a){return!jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},parent:function(a){return a.firstChild;},empty:function(a){return!a.firstChild;},contains:function(a,i,m){return(a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},visible:function(a){return"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},hidden:function(a){return"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},enabled:function(a){return!a.disabled;},disabled:function(a){return a.disabled;},checked:function(a){return a.checked;},selected:function(a){return a.selected||jQuery.attr(a,"selected");},text:function(a){return"text"==a.type;},radio:function(a){return"radio"==a.type;},checkbox:function(a){return"checkbox"==a.type;},file:function(a){return"file"==a.type;},password:function(a){return"password"==a.type;},submit:function(a){return"submit"==a.type;},image:function(a){return"image"==a.type;},reset:function(a){return"reset"==a.type;},button:function(a){return"button"==a.type||jQuery.nodeName(a,"button");},input:function(a){return/input|select|textarea|button/i.test(a.nodeName);},has:function(a,i,m){return jQuery.find(m[3],a).length;},header:function(a){return/h\d/i.test(a.nodeName);},animated:function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}}},parse:[/^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,/^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,new RegExp("^([:.#]*)("+chars+"+)")],multiFilter:function(expr,elems,not){var old,cur=[];while(expr&&expr!=old){old=expr;var f=jQuery.filter(expr,elems,not);expr=f.t.replace(/^\s*,\s*/,"");cur=not?elems=f.r:jQuery.merge(cur,f.r);}return cur;},find:function(t,context){if(typeof t!="string")return[t];if(context&&context.nodeType!=1&&context.nodeType!=9)return[];context=context||document;var ret=[context],done=[],last,nodeName;while(t&&last!=t){var r=[];last=t;t=jQuery.trim(t);var foundToken=false;var re=quickChild;var m=re.exec(t);if(m){nodeName=m[1].toUpperCase();for(var i=0;ret[i];i++)for(var c=ret[i].firstChild;c;c=c.nextSibling)if(c.nodeType==1&&(nodeName=="*"||c.nodeName.toUpperCase()==nodeName))r.push(c);ret=r;t=t.replace(re,"");if(t.indexOf(" ")==0)continue;foundToken=true;}else{re=/^([>+~])\s*(\w*)/i;if((m=re.exec(t))!=null){r=[];var merge={};nodeName=m[2].toUpperCase();m=m[1];for(var j=0,rl=ret.length;j=0;if(!not&&pass||not&&!pass)tmp.push(r[i]);}return tmp;},filter:function(t,r,not){var last;while(t&&t!=last){last=t;var p=jQuery.parse,m;for(var i=0;p[i];i++){m=p[i].exec(t);if(m){t=t.substring(m[0].length);m[2]=m[2].replace(/\\/g,"");break;}}if(!m)break;if(m[1]==":"&&m[2]=="not")r=isSimple.test(m[3])?jQuery.filter(m[3],r,true).r:jQuery(r).not(m[3]);else if(m[1]==".")r=jQuery.classFilter(r,m[2],not);else if(m[1]=="["){var tmp=[],type=m[3];for(var i=0,rl=r.length;i=0)^not)tmp.push(a);}r=tmp;}else if(m[1]==":"&&m[2]=="nth-child"){var merge={},tmp=[],test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(m[3]=="even"&&"2n"||m[3]=="odd"&&"2n+1"||!/\D/.test(m[3])&&"0n+"+m[3]||m[3]),first=(test[1]+(test[2]||1))-0,last=test[3]-0;for(var i=0,rl=r.length;i=0)add=true;if(add^not)tmp.push(node);}r=tmp;}else{var fn=jQuery.expr[m[1]];if(typeof fn=="object")fn=fn[m[2]];if(typeof fn=="string")fn=eval("false||function(a,i){return "+fn+";}");r=jQuery.grep(r,function(elem,i){return fn(elem,i,m,r);},not);}}return{r:r,t:t};},dir:function(elem,dir){var matched=[];var cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1)matched.push(cur);cur=cur[dir];}return matched;},nth:function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir])if(cur.nodeType==1&&++num==result)break;return cur;},sibling:function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&(!elem||n!=elem))r.push(n);}return r;}});jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)return;if(jQuery.browser.msie&&elem.setInterval!=undefined)elem=window;if(!handler.guid)handler.guid=this.guid++;if(data!=undefined){var fn=handler;handler=function(){return fn.apply(this,arguments);};handler.data=data;handler.guid=fn.guid;}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){var val;if(typeof jQuery=="undefined"||jQuery.event.triggered)return val;val=jQuery.event.handle.apply(arguments.callee.elem,arguments);return val;});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];handler.type=parts[1];var handlers=events[type];if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem)===false){if(elem.addEventListener)elem.addEventListener(type,handle,false);else if(elem.attachEvent)elem.attachEvent("on"+type,handle);}}handlers[handler.guid]=handler;jQuery.event.global[type]=true;});elem=null;},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return;var events=jQuery.data(elem,"events"),ret,index;if(events){if(types==undefined||(typeof types=="string"&&types.charAt(0)=="."))for(var type in events)this.remove(elem,type+(types||""));else{if(types.type){handler=types.handler;types=types.type;}jQuery.each(types.split(/\s+/),function(index,type){var parts=type.split(".");type=parts[0];if(events[type]){if(handler)delete events[type][handler.guid];else -for(handler in events[type])if(!parts[1]||events[type][handler].type==parts[1])delete events[type][handler];for(ret in events[type])break;if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem)===false){if(elem.removeEventListener)elem.removeEventListener(type,jQuery.data(elem,"handle"),false);else if(elem.detachEvent)elem.detachEvent("on"+type,jQuery.data(elem,"handle"));}ret=null;delete events[type];}}});}for(ret in events)break;if(!ret){var handle=jQuery.data(elem,"handle");if(handle)handle.elem=null;jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle");}}},trigger:function(type,data,elem,donative,extra){data=jQuery.makeArray(data||[]);if(type.indexOf("!")>=0){type=type.slice(0,-1);var exclusive=true;}if(!elem){if(this.global[type])jQuery("*").add([window,document]).trigger(type,data);}else{if(elem.nodeType==3||elem.nodeType==8)return undefined;var val,ret,fn=jQuery.isFunction(elem[type]||null),event=!data[0]||!data[0].preventDefault;if(event)data.unshift(this.fix({type:type,target:elem}));data[0].type=type;if(exclusive)data[0].exclusive=true;if(jQuery.isFunction(jQuery.data(elem,"handle")))val=jQuery.data(elem,"handle").apply(elem,data);if(!fn&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false)val=false;if(event)data.shift();if(extra&&jQuery.isFunction(extra)){ret=extra.apply(elem,val==null?data:data.concat(val));if(ret!==undefined)val=ret;}if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{elem[type]();}catch(e){}}this.triggered=false;}return val;},handle:function(event){var val;event=jQuery.event.fix(event||window.event||{});var parts=event.type.split(".");event.type=parts[0];var handlers=jQuery.data(this,"events")&&jQuery.data(this,"events")[event.type],args=Array.prototype.slice.call(arguments,1);args.unshift(event);for(var j in handlers){var handler=handlers[j];args[0].handler=handler;args[0].data=handler.data;if(!parts[1]&&!event.exclusive||handler.type==parts[1]){var ret=handler.apply(this,args);if(val!==false)val=ret;if(ret===false){event.preventDefault();event.stopPropagation();}}}if(jQuery.browser.msie)event.target=event.preventDefault=event.stopPropagation=event.handler=event.data=null;return val;},fix:function(event){var originalEvent=event;event=jQuery.extend({},originalEvent);event.preventDefault=function(){if(originalEvent.preventDefault)originalEvent.preventDefault();originalEvent.returnValue=false;};event.stopPropagation=function(){if(originalEvent.stopPropagation)originalEvent.stopPropagation();originalEvent.cancelBubble=true;};if(!event.target)event.target=event.srcElement||document;if(event.target.nodeType==3)event.target=originalEvent.target.parentNode;if(!event.relatedTarget&&event.fromElement)event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement;if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0);}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode))event.which=event.charCode||event.keyCode;if(!event.metaKey&&event.ctrlKey)event.metaKey=event.ctrlKey;if(!event.which&&event.button)event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));return event;},special:{ready:{setup:function(){bindReady();return;},teardown:function(){return;}},mouseenter:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseover",jQuery.event.special.mouseenter.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseover",jQuery.event.special.mouseenter.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseenter";return jQuery.event.handle.apply(this,arguments);}},mouseleave:{setup:function(){if(jQuery.browser.msie)return false;jQuery(this).bind("mouseout",jQuery.event.special.mouseleave.handler);return true;},teardown:function(){if(jQuery.browser.msie)return false;jQuery(this).unbind("mouseout",jQuery.event.special.mouseleave.handler);return true;},handler:function(event){if(withinElement(event,this))return true;arguments[0].type="mouseleave";return jQuery.event.handle.apply(this,arguments);}}}};jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data);});},one:function(type,data,fn){return this.each(function(){jQuery.event.add(this,type,function(event){jQuery(this).unbind(event);return(fn||data).apply(this,arguments);},fn&&data);});},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn);});},trigger:function(type,data,fn){return this.each(function(){jQuery.event.trigger(type,data,this,true,fn);});},triggerHandler:function(type,data,fn){if(this[0])return jQuery.event.trigger(type,data,this[0],false,fn);return undefined;},toggle:function(){var args=arguments;return this.click(function(event){this.lastToggle=0==this.lastToggle?1:0;event.preventDefault();return args[this.lastToggle].apply(this,arguments)||false;});},hover:function(fnOver,fnOut){return this.bind('mouseenter',fnOver).bind('mouseleave',fnOut);},ready:function(fn){bindReady();if(jQuery.isReady)fn.call(document,jQuery);else -jQuery.readyList.push(function(){return fn.call(this,jQuery);});return this;}});jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.apply(document);});jQuery.readyList=null;}jQuery(document).triggerHandler("ready");}}});var readyBound=false;function bindReady(){if(readyBound)return;readyBound=true;if(document.addEventListener&&!jQuery.browser.opera)document.addEventListener("DOMContentLoaded",jQuery.ready,false);if(jQuery.browser.msie&&window==top)(function(){if(jQuery.isReady)return;try{document.documentElement.doScroll("left");}catch(error){setTimeout(arguments.callee,0);return;}jQuery.ready();})();if(jQuery.browser.opera)document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return;for(var i=0;i=0){var selector=url.slice(off,url.length);url=url.slice(0,off);}callback=callback||function(){};var type="GET";if(params)if(jQuery.isFunction(params)){callback=params;params=null;}else{params=jQuery.param(params);type="POST";}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified")self.html(selector?jQuery("
").append(res.responseText.replace(//g,"")).find(selector):res.responseText);self.each(callback,[res.responseText,status,res]);}});return this;},serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){return jQuery.nodeName(this,"form")?jQuery.makeArray(this.elements):this;}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password/i.test(this.type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:val.constructor==Array?jQuery.map(val,function(val,i){return{name:elem.name,value:val};}):{name:elem.name,value:val};}).get();}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f);};});var jsc=(new Date).getTime();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null;}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type});},getScript:function(url,callback){return jQuery.get(url,null,callback,"script");},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={};}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type});},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings);},ajaxSettings:{global:true,type:"GET",timeout:0,contentType:"application/x-www-form-urlencoded",processData:true,async:true,data:null,username:null,password:null,accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){var jsonp,jsre=/=\?(&|$)/g,status,data;s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));if(s.data&&s.processData&&typeof s.data!="string")s.data=jQuery.param(s.data);if(s.dataType=="jsonp"){if(s.type.toLowerCase()=="get"){if(!s.url.match(jsre))s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?";}else if(!s.data||!s.data.match(jsre))s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?";s.dataType="json";}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data)s.data=(s.data+"").replace(jsre,"="+jsonp+"$1");s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp];}catch(e){}if(head)head.removeChild(script);};}if(s.dataType=="script"&&s.cache==null)s.cache=false;if(s.cache===false&&s.type.toLowerCase()=="get"){var ts=(new Date()).getTime();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"");}if(s.data&&s.type.toLowerCase()=="get"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null;}if(s.global&&!jQuery.active++)jQuery.event.trigger("ajaxStart");if((!s.url.indexOf("http")||!s.url.indexOf("//"))&&s.dataType=="script"&&s.type.toLowerCase()=="get"){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset)script.charset=s.scriptCharset;if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();head.removeChild(script);}};}head.appendChild(script);return undefined;}var requestDone=false;var xml=window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest();xml.open(s.type,s.url,s.async,s.username,s.password);try{if(s.data)xml.setRequestHeader("Content-Type",s.contentType);if(s.ifModified)xml.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT");xml.setRequestHeader("X-Requested-With","XMLHttpRequest");xml.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default);}catch(e){}if(s.beforeSend)s.beforeSend(xml);if(s.global)jQuery.event.trigger("ajaxSend",[xml,s]);var onreadystatechange=function(isTimeout){if(!requestDone&&xml&&(xml.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null;}status=isTimeout=="timeout"&&"timeout"||!jQuery.httpSuccess(xml)&&"error"||s.ifModified&&jQuery.httpNotModified(xml,s.url)&&"notmodified"||"success";if(status=="success"){try{data=jQuery.httpData(xml,s.dataType);}catch(e){status="parsererror";}}if(status=="success"){var modRes;try{modRes=xml.getResponseHeader("Last-Modified");}catch(e){}if(s.ifModified&&modRes)jQuery.lastModified[s.url]=modRes;if(!jsonp)success();}else -jQuery.handleError(s,xml,status);complete();if(s.async)xml=null;}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0)setTimeout(function(){if(xml){xml.abort();if(!requestDone)onreadystatechange("timeout");}},s.timeout);}try{xml.send(s.data);}catch(e){jQuery.handleError(s,xml,null,e);}if(!s.async)onreadystatechange();function success(){if(s.success)s.success(data,status);if(s.global)jQuery.event.trigger("ajaxSuccess",[xml,s]);}function complete(){if(s.complete)s.complete(xml,status);if(s.global)jQuery.event.trigger("ajaxComplete",[xml,s]);if(s.global&&!--jQuery.active)jQuery.event.trigger("ajaxStop");}return xml;},handleError:function(s,xml,status,e){if(s.error)s.error(xml,status,e);if(s.global)jQuery.event.trigger("ajaxError",[xml,s,e]);},active:0,httpSuccess:function(r){try{return!r.status&&location.protocol=="file:"||(r.status>=200&&r.status<300)||r.status==304||r.status==1223||jQuery.browser.safari&&r.status==undefined;}catch(e){}return false;},httpNotModified:function(xml,url){try{var xmlRes=xml.getResponseHeader("Last-Modified");return xml.status==304||xmlRes==jQuery.lastModified[url]||jQuery.browser.safari&&xml.status==undefined;}catch(e){}return false;},httpData:function(r,type){var ct=r.getResponseHeader("content-type");var xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0;var data=xml?r.responseXML:r.responseText;if(xml&&data.documentElement.tagName=="parsererror")throw"parsererror";if(type=="script")jQuery.globalEval(data);if(type=="json")data=eval("("+data+")");return data;},param:function(a){var s=[];if(a.constructor==Array||a.jquery)jQuery.each(a,function(){s.push(encodeURIComponent(this.name)+"="+encodeURIComponent(this.value));});else -for(var j in a)if(a[j]&&a[j].constructor==Array)jQuery.each(a[j],function(){s.push(encodeURIComponent(j)+"="+encodeURIComponent(this));});else -s.push(encodeURIComponent(j)+"="+encodeURIComponent(a[j]));return s.join("&").replace(/%20/g,"+");}});jQuery.fn.extend({show:function(speed,callback){return speed?this.animate({height:"show",width:"show",opacity:"show"},speed,callback):this.filter(":hidden").each(function(){this.style.display=this.oldblock||"";if(jQuery.css(this,"display")=="none"){var elem=jQuery("<"+this.tagName+" />").appendTo("body");this.style.display=elem.css("display");if(this.style.display=="none")this.style.display="block";elem.remove();}}).end();},hide:function(speed,callback){return speed?this.animate({height:"hide",width:"hide",opacity:"hide"},speed,callback):this.filter(":visible").each(function(){this.oldblock=this.oldblock||jQuery.css(this,"display");this.style.display="none";}).end();},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle(fn,fn2):fn?this.animate({height:"toggle",width:"toggle",opacity:"toggle"},fn,fn2):this.each(function(){jQuery(this)[jQuery(this).is(":hidden")?"show":"hide"]();});},slideDown:function(speed,callback){return this.animate({height:"show"},speed,callback);},slideUp:function(speed,callback){return this.animate({height:"hide"},speed,callback);},slideToggle:function(speed,callback){return this.animate({height:"toggle"},speed,callback);},fadeIn:function(speed,callback){return this.animate({opacity:"show"},speed,callback);},fadeOut:function(speed,callback){return this.animate({opacity:"hide"},speed,callback);},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback);},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){if(this.nodeType!=1)return false;var opt=jQuery.extend({},optall);var hidden=jQuery(this).is(":hidden"),self=this;for(var p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden)return jQuery.isFunction(opt.complete)&&opt.complete.apply(this);if(p=="height"||p=="width"){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow;}}if(opt.overflow!=null)this.style.overflow="hidden";opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val))e[val=="toggle"?hidden?"show":"hide":val](prop);else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit;}if(parts[1])end=((parts[1]=="-="?-1:1)*end)+start;e.custom(start,end,unit);}else -e.custom(start,val,"");}});return true;});},queue:function(type,fn){if(jQuery.isFunction(type)||(type&&type.constructor==Array)){fn=type;type="fx";}if(!type||(typeof type=="string"&&!fn))return queue(this[0],type);return this.each(function(){if(fn.constructor==Array)queue(this,type,fn);else{queue(this,type).push(fn);if(queue(this,type).length==1)fn.apply(this);}});},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue)this.queue([]);this.each(function(){for(var i=timers.length-1;i>=0;i--)if(timers[i].elem==this){if(gotoEnd)timers[i](true);timers.splice(i,1);}});if(!gotoEnd)this.dequeue();return this;}});var queue=function(elem,type,array){if(!elem)return undefined;type=type||"fx";var q=jQuery.data(elem,type+"queue");if(!q||array)q=jQuery.data(elem,type+"queue",array?jQuery.makeArray(array):[]);return q;};jQuery.fn.dequeue=function(type){type=type||"fx";return this.each(function(){var q=queue(this,type);q.shift();if(q.length)q[0].apply(this);});};jQuery.extend({speed:function(speed,easing,fn){var opt=speed&&speed.constructor==Object?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&easing.constructor!=Function&&easing};opt.duration=(opt.duration&&opt.duration.constructor==Number?opt.duration:{slow:600,fast:200}[opt.duration])||400;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false)jQuery(this).dequeue();if(jQuery.isFunction(opt.old))opt.old.apply(this);};return opt;},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p;},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum;}},timers:[],timerId:null,fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig)options.orig={};}});jQuery.fx.prototype={update:function(){if(this.options.step)this.options.step.apply(this.elem,[this.now,this]);(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if(this.prop=="height"||this.prop=="width")this.elem.style.display="block";},cur:function(force){if(this.elem[this.prop]!=null&&this.elem.style[this.prop]==null)return this.elem[this.prop];var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0;},custom:function(from,to,unit){this.startTime=(new Date()).getTime();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;this.update();var self=this;function t(gotoEnd){return self.step(gotoEnd);}t.elem=this.elem;jQuery.timers.push(t);if(jQuery.timerId==null){jQuery.timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;ithis.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim)if(this.options.curAnim[i]!==true)done=false;if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none")this.elem.style.display="block";}if(this.options.hide)this.elem.style.display="none";if(this.options.hide||this.options.show)for(var p in this.options.curAnim)jQuery.attr(this.elem.style,p,this.options.orig[p]);}if(done&&jQuery.isFunction(this.options.complete))this.options.complete.apply(this.elem);return false;}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update();}return true;}};jQuery.fx.step={scrollLeft:function(fx){fx.elem.scrollLeft=fx.now;},scrollTop:function(fx){fx.elem.scrollTop=fx.now;},opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now);},_default:function(fx){fx.elem.style[fx.prop]=fx.now+fx.unit;}};jQuery.fn.offset=function(){var left=0,top=0,elem=this[0],results;if(elem)with(jQuery.browser){var parent=elem.parentNode,offsetChild=elem,offsetParent=elem.offsetParent,doc=elem.ownerDocument,safari2=safari&&parseInt(version)<522&&!/adobeair/i.test(userAgent),fixed=jQuery.css(elem,"position")=="fixed";if(elem.getBoundingClientRect){var box=elem.getBoundingClientRect();add(box.left+Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),box.top+Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));add(-doc.documentElement.clientLeft,-doc.documentElement.clientTop);}else{add(elem.offsetLeft,elem.offsetTop);while(offsetParent){add(offsetParent.offsetLeft,offsetParent.offsetTop);if(mozilla&&!/^t(able|d|h)$/i.test(offsetParent.tagName)||safari&&!safari2)border(offsetParent);if(!fixed&&jQuery.css(offsetParent,"position")=="fixed")fixed=true;offsetChild=/^body$/i.test(offsetParent.tagName)?offsetChild:offsetParent;offsetParent=offsetParent.offsetParent;}while(parent&&parent.tagName&&!/^body|html$/i.test(parent.tagName)){if(!/^inline|table.*$/i.test(jQuery.css(parent,"display")))add(-parent.scrollLeft,-parent.scrollTop);if(mozilla&&jQuery.css(parent,"overflow")!="visible")border(parent);parent=parent.parentNode;}if((safari2&&(fixed||jQuery.css(offsetChild,"position")=="absolute"))||(mozilla&&jQuery.css(offsetChild,"position")!="absolute"))add(-doc.body.offsetLeft,-doc.body.offsetTop);if(fixed)add(Math.max(doc.documentElement.scrollLeft,doc.body.scrollLeft),Math.max(doc.documentElement.scrollTop,doc.body.scrollTop));}results={top:top,left:left};}function border(elem){add(jQuery.curCSS(elem,"borderLeftWidth",true),jQuery.curCSS(elem,"borderTopWidth",true));}function add(l,t){left+=parseInt(l)||0;top+=parseInt(t)||0;}return results;};})(); \ No newline at end of file + +// Map over jQuery in case of overwrite +if ( window.jQuery ) + var _jQuery = window.jQuery; + +var jQuery = window.jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.prototype.init( selector, context ); +}; + +// Map over the $ in case of overwrite +if ( window.$ ) + var _$ = window.$; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +// A simple way to check for HTML strings or ID strings +// (both of which we optimize for) +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +// Is it a simple selector +var isSimple = /^.[^:#\[\.]*$/; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this[0] = selector; + this.length = 1; + return this; + + // Handle HTML strings + } else if ( typeof selector == "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) + selector = jQuery.clean( [ match[1] ], context ); + + // HANDLE: $("#id") + else { + var elem = document.getElementById( match[3] ); + + // Make sure an element was located + if ( elem ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id != match[3] ) + return jQuery().find( selector ); + + // Otherwise, we inject the element directly into the jQuery object + else { + this[0] = elem; + this.length = 1; + return this; + } + + else + selector = []; + } + + // HANDLE: $(expr, [context]) + // (which is just equivalent to: $(content).find(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) + return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object, contains DOM nodes, is passed in as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + // The current version of jQuery being used + jquery: "1.2.3", + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + // The number of elements contained in the matched element set + length: 0, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + // Build a new jQuery matched element set + var ret = jQuery( elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Force the current matched set of elements to become + // the specified array of elements (destroying the stack in the process) + // You should use pushStack() in order to do this, but maintain the stack + setArray: function( elems ) { + // Resetting the length to 0, then using the native Array push + // is a super-fast way to populate an object with array-like properties + this.length = 0; + Array.prototype.push.apply( this, elems ); + + return this; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + var ret = -1; + + // Locate the position of the desired element + this.each(function(i){ + if ( this == elem ) + ret = i; + }); + + return ret; + }, + + attr: function( name, value, type ) { + var options = name; + + // Look for the case where we're accessing a style value + if ( name.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; + + else { + options = {}; + options[ name ] = value; + } + + // Check to see if we're setting style values + return this.each(function(i){ + // Set all the styles + for ( name in options ) + jQuery.attr( + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) + ); + }); + }, + + css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; + return this.attr( key, value, "curCSS" ); + }, + + text: function( text ) { + if ( typeof text != "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; + + jQuery.each( text || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); + }); + }); + + return ret; + }, + + wrapAll: function( html ) { + if ( this[0] ) + // The elements to wrap the target around + jQuery( html, this[0].ownerDocument ) + .clone() + .insertBefore( this[0] ) + .map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function( html ) { + return this.each(function(){ + jQuery( this ).contents().wrapAll( html ); + }); + }, + + wrap: function( html ) { + return this.each(function(){ + jQuery( this ).wrapAll( html ); + }); + }, + + append: function() { + return this.domManip(arguments, true, false, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, false, function(elem){ + this.parentNode.insertBefore( elem, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, true, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery( [] ); + }, + + find: function( selector ) { + var elems = jQuery.map(this, function(elem){ + return jQuery.find( selector, elem ); + }); + + return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? + jQuery.unique( elems ) : + elems ); + }, + + clone: function( events ) { + // Do the clone + var ret = this.map(function(){ + if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var clone = this.cloneNode(true), + container = document.createElement("div"); + container.appendChild(clone); + return jQuery.clean([container.innerHTML])[0]; + } else + return this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if ( events === true ) + this.find("*").andSelf().each(function(i){ + if (this.nodeType == 3) + return; + var events = jQuery.data( this, "events" ); + + for ( var type in events ) + for ( var handler in events[ type ] ) + jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); + }); + + // Return the cloned set + return ret; + }, + + filter: function( selector ) { + return this.pushStack( + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); + }) || + + jQuery.multiFilter( selector, this ) ); + }, + + not: function( selector ) { + if ( selector.constructor == String ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ) ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return !selector ? this : this.pushStack( jQuery.merge( + this.get(), + selector.constructor == String ? + jQuery( selector ).get() : + selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? + selector : [selector] ) ); + }, + + is: function( selector ) { + return selector ? + jQuery.multiFilter( selector, this ).length > 0 : + false; + }, + + hasClass: function( selector ) { + return this.is( "." + selector ); + }, + + val: function( value ) { + if ( value == undefined ) { + + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return value; + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + + // Everything else, we just grab the value + } else + return (this[0].value || "").replace(/\r/g, ""); + + } + + return undefined; + } + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = value.constructor == Array ? + value : + [ value ]; + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value == undefined ? + (this.length ? + this[0].innerHTML : + null) : + this.empty().append( value ); + }, + + replaceWith: function( value ) { + return this.after( value ).remove(); + }, + + eq: function( i ) { + return this.slice( i, i + 1 ); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + data: function( key, value ){ + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value == null ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data == undefined && this.length ) + data = jQuery.data( this[0], key ); + + return data == null && parts[1] ? + this.data( parts[0] ) : + data; + } else + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ + jQuery.data( this, key, value ); + }); + }, + + removeData: function( key ){ + return this.each(function(){ + jQuery.removeData( this, key ); + }); + }, + + domManip: function( args, table, reverse, callback ) { + var clone = this.length > 1, elems; + + return this.each(function(){ + if ( !elems ) { + elems = jQuery.clean( args, this.ownerDocument ); + + if ( reverse ) + elems.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); + + var scripts = jQuery( [] ); + + jQuery.each(elems, function(){ + var elem = clone ? + jQuery( this ).clone( true )[0] : + this; + + // execute all scripts after the elements have been injected + if ( jQuery.nodeName( elem, "script" ) ) { + scripts = scripts.add( elem ); + } else { + // Remove any inner scripts for later evaluation + if ( elem.nodeType == 1 ) + scripts = scripts.add( jQuery( "script", elem ).remove() ); + + // Inject the elements into the document + callback.call( obj, elem ); + } + }); + + scripts.each( evalScript ); + }); + } +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.prototype.init.prototype = jQuery.prototype; + +function evalScript( i, elem ) { + if ( elem.src ) + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild( elem ); +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target != "object" && typeof target != "function" ) + target = {}; + + // extend jQuery itself if only one argument is passed + if ( length == 1 ) { + target = this; + i = 0; + } + + for ( ; i < length; i++ ) + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) + // Extend the base object + for ( var name in options ) { + // Prevent never-ending loop + if ( target === options[ name ] ) + continue; + + // Recurse if we're merging object values + if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) + target[ name ] = jQuery.extend( target[ name ], options[ name ] ); + + // Don't bring in undefined values + else if ( options[ name ] != undefined ) + target[ name ] = options[ name ]; + + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; + +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) + window.jQuery = _jQuery; + + return jQuery; + }, + + // See test/unit/core.js for details concerning this function. + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a (or is an) XML document + isXMLDoc: function( elem ) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + globalEval: function( data ) { + data = jQuery.trim( data ); + + if ( data ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + if ( jQuery.browser.msie ) + script.text = data; + else + script.appendChild( document.createTextNode( data ) ); + + head.appendChild( script ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? + jQuery.cache[ id ][ name ] : + id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + + for ( name in jQuery.cache[ id ] ) + break; + + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( object, callback, args ) { + if ( args ) { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.apply( object[ name ], args ) === false ) + break; + } else + for ( var i = 0, length = object.length; i < length; i++ ) + if ( callback.apply( object[ i ], args ) === false ) + break; + + // A special, fast, case for the most common use of each + } else { + if ( object.length == undefined ) { + for ( var name in object ) + if ( callback.call( object[ name ], name, object[ name ] ) === false ) + break; + } else + for ( var i = 0, length = object.length, value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} + } + + return object; + }, + + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames != undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; + }, + + // internal only, use is(".class") + has: function( elem, className ) { + return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; + } + }, + + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + callback.call( elem ); + + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, + + css: function( elem, name, force ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + var padding = 0, border = 0; + jQuery.each( which, function() { + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + val -= Math.round(padding + border); + } + + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return Math.max(0, val); + } + + return jQuery.curCSS( elem, name, force ); + }, + + curCSS: function( elem, name, force ) { + var ret; + + // A helper method for determining if an element's values are broken + function color( elem ) { + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle( elem, null ); + return !ret || ret.getPropertyValue("color") == ""; + } + + // We need to handle opacity special in IE + if ( name == "opacity" && jQuery.browser.msie ) { + ret = jQuery.attr( elem.style, "opacity" ); + + return ret == "" ? + "1" : + ret; + } + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = elem.style.outline; + elem.style.outline = "0 solid black"; + elem.style.outline = save; + } + + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; + + if ( !force && elem.style && elem.style[ name ] ) + ret = elem.style[ name ]; + + else if ( document.defaultView && document.defaultView.getComputedStyle ) { + + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; + + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); + + var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); + + if ( getComputedStyle && !color( elem ) ) + ret = getComputedStyle.getPropertyValue( name ); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + var swap = [], stack = []; + + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( var i = 0; i < stack.length; i++ ) + if ( color( stack[ i ] ) ) { + swap[ i ] = stack[ i ].style.display; + stack[ i ].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = name == "display" && swap[ stack.length - 1 ] != null ? + "none" : + ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; + + // Finally, revert the display styles back + for ( var i = 0; i < swap.length; i++ ) + if ( swap[ i ] != null ) + stack[ i ].style.display = swap[ i ]; + } + + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) + ret = "1"; + + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + + // Revert the changed values + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function( elems, context ) { + var ret = []; + context = context || document; + // !context.createElement fails in IE with an error but returns typeof 'object' + if (typeof context.createElement == 'undefined') + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + jQuery.each(elems, function(i, elem){ + if ( !elem ) + return; + + if ( elem.constructor == Number ) + elem = elem.toString(); + + // Convert html string into DOM nodes + if ( typeof elem == "string" ) { + // Fix "XHTML"-style tags in all browsers + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); + + var wrap = + // option or optgroup + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + + !tags.indexOf("", "" ] || + + // matched above + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + // IE can't serialize and + @@ -22,7 +23,7 @@ - - - - +
+ +
diff --git a/js/euphorik.js b/js/euphorik.js index d7ef712..27ec5bb 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -415,6 +415,7 @@ Client.prototype.resetDonneesPersonnelles = function() this.password = "" this.email = "" this.css = jQuery("link#cssPrincipale").attr("href") + this.nickFormat = "nick" this.pagePrincipale = 1 @@ -550,6 +551,7 @@ Client.prototype.getJSONProfile = function() "nick" : this.pseudo, "email" : this.email, "css" : this.css, + "nick_format" : this.nickFormat, "main_page" : this.pagePrincipale < 1 ? 1 : this.pagePrincipale, "conversations" : this.getJSONConversations() } @@ -660,7 +662,8 @@ Client.prototype.connexion = function(messageJson) } Client.prototype.deconnexion = function() -{ +{ + this.flush() this.setStatut(statutType.deconnected) // deconnexion this.resetDonneesPersonnelles() this.delCookie () @@ -681,6 +684,7 @@ Client.prototype.chargerDonnees = function(data) this.pseudo = data["nick"] this.email = data["email"] this.css = data["css"] + this.nickFormat = data["nick_format"] // la page de la conversation principale this.pagePrincipale = data["main_page"] == undefined ? 1 : data["main_page"] diff --git a/js/pageMinichat.js b/js/pageMinichat.js index d82648e..e8d607a 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -210,11 +210,12 @@ function Reponse(id, pseudo, login) * @param pseudo * @param contenu */ -function Message(id, date, pseudo, contenu) +function Message(id, date, pseudo, login, contenu) { this.id = id this.date = date this.pseudo = pseudo + this.login = login this.contenu = contenu this.appartientAuClient = false @@ -285,7 +286,7 @@ Message.prototype.getConversation = function(messages) * @param numConv le numéro (appelé id) de la conversation * @param formateur outil permettant la mise en forme du texte des messages */ -function Conversation(num, util, formateur) +function Conversation(num, util, formateur, client) { var thisConversation = this @@ -294,6 +295,8 @@ function Conversation(num, util, formateur) this.messageOver = null // le message sur lequel se trouve le curseur this.util = util this.formateur = formateur + this.client = client + this.messages = new Array() this.messagesParId = new Object() @@ -424,9 +427,14 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) var XHTML = "" for (var i = this.messages.length - 1; i >= 0; i--) if (this.messages[i].id > idDernierMessageAffiche) - { + { var message = this.messages[i] + // construit l'identifiant de la personne + var identifiant = + this.client.nickFormat == "nick" ? message.pseudo : + (this.client.nickFormat == "login" ? message.login : message.pseudo + "(" + message.login +")" ) + var XHTMLrepondA = "" for (var id in message.repondA) XHTMLrepondA += this.formateur.traitementComplet(message.repondA[id].pseudo) + "> " @@ -441,7 +449,7 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) "\">" + "
>
" + "[" + message.date + "]" + - "" + this.formateur.traitementComplet(message.pseudo) + ":" + + "" + this.formateur.traitementComplet(identifiant) + ":" + XHTMLrepondA + "" + (message.systeme ? this.formateur.remplacerBalisesHTML(message.contenu) : this.formateur.traitementComplet(message.contenu, message.pseudo)) + "" + "" @@ -623,6 +631,7 @@ Messages.prototype.ajouterMessage = function(element, numConversation) id, element["date"], element["nick"], + element["login"], element["content"] ) @@ -657,7 +666,7 @@ Messages.prototype.nouvelleConversation = function(num, funFermer, funLien) { var thisMessages = this - this.conversations[num] = new Conversation(num, this.util, this.formateur) + this.conversations[num] = new Conversation(num, this.util, this.formateur, this.client) if (funFermer != undefined) this.conversations[num].eventFermer(funFermer) if (funLien != undefined) @@ -796,6 +805,8 @@ Messages.prototype.rafraichirMessages = function(vider) // ajoute les messages reçu à leur conversation respective for (var numConv = 0; numConv < data["conversations"].length; numConv++) { + //PLOP if (data["conversations"][numConv]["messages"].length == 0) continue + thisMessages.ajouterMessages(data["conversations"][numConv], numConv) // définit les événements liés à la conversation diff --git a/js/pageProfile.js b/js/pageProfile.js index 4a86aee..f3ef3a8 100755 --- a/js/pageProfile.js +++ b/js/pageProfile.js @@ -11,6 +11,7 @@ function PageProfile(client, formateur, util) PageProfile.prototype.contenu = function() { + // pourquoi ? return "" } @@ -33,13 +34,18 @@ PageProfile.prototype.chargerProfile = function() jQuery("form#profile input.login").val(this.client.login) jQuery("form#profile input.pseudo").val(this.client.pseudo) - jQuery("form#profile input.email").val(this.client.email) + jQuery("form#profile input.email").val(this.client.email) + + jQuery("form#profile select#affichagePseudo option").removeAttr("selected") + jQuery("form#profile select#affichagePseudo option[value=" + this.client.nickFormat + "]").attr("selected", "selected") + - jQuery("#page form#profile button").click( + jQuery("form#profile button").click( function() { thisPage.client.pseudo = thisPage.formateur.filtrerInputPseudo(jQuery("form#profile input.pseudo").val()) - thisPage.client.email = jQuery("form#profile input.email").val() + thisPage.client.email = jQuery("form#profile input.email").val() + thisPage.client.nickFormat = jQuery("form#profile select#affichagePseudo option:selected").attr("value") var password = jQuery("form#profile input.password").val() var passwordRe = jQuery("form#profile input.passwordRe").val() @@ -108,6 +114,16 @@ return '\ e-mail\ \ \ + \ + Affichage des identifiants\ + \ + \ + \ + \ ' : '') + '\ \ \ @@ -115,4 +131,5 @@ return '\ \ \ ' -} \ No newline at end of file +} + diff --git a/modules/erl/euphorik_bd.erl b/modules/erl/euphorik_bd.erl index 298db8d..c836776 100755 --- a/modules/erl/euphorik_bd.erl +++ b/modules/erl/euphorik_bd.erl @@ -14,6 +14,7 @@ % Instructions pour créer une nouvelle base : % $erl -sname yaws -mnesia dir '"/projets/euphorik/BD"' +% voir doc/installation.txt % >l(euphorik_bd). % >euphorik_bd:create(). create() -> @@ -83,7 +84,17 @@ vers_version(5) -> end, record_info(fields, user), user - ). + ); +% Ajout le format d'affichage des pseudos +vers_version(6) -> + mnesia:transform_table( + user, + fun({user, Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, Indice_flood, Page_Principale, Conversations}) -> + {user, Id, Cookie, Pseudo, Login, Password, Email, Date_creation, Date_derniere_connexion, Css, nick, Indice_flood, Page_Principale, Conversations} + end, + record_info(fields, user), + user + ). % exemple de peuplage de la BD, utilisé pour les tests diff --git a/modules/erl/euphorik_minichat.erl b/modules/erl/euphorik_minichat.erl index 2e2f406..519870c 100755 --- a/modules/erl/euphorik_minichat.erl +++ b/modules/erl/euphorik_minichat.erl @@ -28,7 +28,7 @@ est_une_reponse_a_user/2, % set : update_pseudo_user/2, - set_profile/8, + set_profile/9, update_date_derniere_connexion/1, nouveau_user/2, nouveau_user/3, @@ -196,33 +196,38 @@ update_pseudo_user(UserId, Pseudo) -> % Mise à par Cookie les autres peuvent être undefined ce qui veut dire qu'ils ne seront pas modifié. -set_profile(Cookie, Login, Password, Pseudo, Email, Css, Page_principale, Conversations) -> - resultat_transaction(mnesia:transaction( - fun() -> - case user_by_cookie(Cookie) of - {ok, User} -> - case user_by_login(Login) of - {ok, U} when U#user.id =/= User#user.id -> - login_deja_pris; - _ -> - User_modifie = User#user{ - % TODO : pourquoi ne pas tester avec la valeur "undefined" plutôt qu'avec "is_list" ? - % TODO : validation plus strict des données (pas de page négative dans les conv par exemple) - login = if is_list(Login) -> Login; true -> User#user.login end, - password = if is_list(Password) -> Password; true -> User#user.password end, - pseudo = if is_list(Pseudo) -> Pseudo; true -> User#user.pseudo end, - email = if is_list(Email) -> Email; true -> User#user.email end, - css = if is_list(Css) -> Css; true -> User#user.css end, - page_principale = if is_integer(Page_principale), Page_principale > 0 -> Page_principale; true -> User#user.page_principale end, - conversations = if is_list(Conversations) -> Conversations; true -> User#user.conversations end - }, - mnesia:write(User_modifie), - ok - end; - _ -> erreur - end - end - )). +set_profile(Cookie, Login, Password, Pseudo, Email, Css, Page_principale, Nick_format, Conversations) -> + if Nick_format =:= nick; Nick_format =:= login; Nick_format =:= nick_login -> + resultat_transaction(mnesia:transaction( + fun() -> + case user_by_cookie(Cookie) of + {ok, User} -> + case user_by_login(Login) of + {ok, U} when U#user.id =/= User#user.id -> + login_deja_pris; + _ -> + User_modifie = User#user{ + % TODO : pourquoi ne pas tester avec la valeur "undefined" plutôt qu'avec "is_list" ? + % TODO : validation plus strict des données (pas de page négative dans les conv par exemple) + login = if is_list(Login) -> Login; true -> User#user.login end, + password = if is_list(Password) -> Password; true -> User#user.password end, + pseudo = if is_list(Pseudo) -> Pseudo; true -> User#user.pseudo end, + email = if is_list(Email) -> Email; true -> User#user.email end, + css = if is_list(Css) -> Css; true -> User#user.css end, + nick_format = Nick_format, + page_principale = if is_integer(Page_principale), Page_principale > 0 -> Page_principale; true -> User#user.page_principale end, + conversations = if is_list(Conversations) -> Conversations; true -> User#user.conversations end + }, + mnesia:write(User_modifie), + ok + end; + _ -> erreur + end + end + )); + true -> + erreur + end. % Met à jour la date de la dernière connexion d'un utilisateur à maintenant diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index d264bcc..eb154ee 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -13,6 +13,8 @@ conversations/4 ]). +-compile(export_all). + -include("euphorik_bd.hrl"). -include_lib("stdlib/include/qlc.hrl"). @@ -222,7 +224,7 @@ conversation(Messages, [M | Reste], X) -> true -> Enfants = enfants(M), Parents = parents(M), - % un message est dit exiterne si un de ses parent ne fait pas partie de la conversation ou si un de ses parents fait partie de X + % un message est dit externe si un de ses parent ne fait pas partie de la conversation ou si un de ses parents fait partie de X Est_message_externe = Parents -- Messages =/= [] orelse intersection(Parents, X) =/= [], conversation([M | Messages], Reste ++ Enfants, if Est_message_externe -> [M | X]; true -> X end) end; diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index 154c7d4..c2cb984 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -45,7 +45,10 @@ loginUser({ok, User}) -> euphorik_minichat:update_date_derniere_connexion(User#user.id), json_reponse_login_ok(User); loginUser(_) -> - erreur("Erreur login"). + % ajoute un délais d'attente (TODO : un autre moyen plus élégant ?) + receive after 1000 -> + erreur("Erreur login") + end. % Renvoie un string() représentant un cookie en base 36. Il y a 10^32 possibillités. @@ -69,6 +72,7 @@ profile( {nick, Pseudo}, {email, Email}, {css, Css}, + {nick_format, Nick_format_str}, {main_page, Main_page}, {conversations, {array, Conversations_json}} ] @@ -86,7 +90,7 @@ profile( [], Conversations_json ), - case euphorik_minichat:set_profile(Cookie, Login, Password, Pseudo, Email, Css, Main_page, Conversations) of + case euphorik_minichat:set_profile(Cookie, Login, Password, Pseudo, Email, Css, list_to_atom(Nick_format_str), Main_page, Conversations) of ok -> json_reponse_ok(); login_deja_pris -> @@ -245,6 +249,7 @@ json_reponse_login_ok(User) -> {login, User#user.login}, {email, User#user.email}, {css, User#user.css}, + {nick_format, atom_to_list(User#user.nick_format)}, {main_page, User#user.page_principale}, {conversations, {array, diff --git a/modules/erl/euphorik_requests.erl b/modules/erl/euphorik_requests.erl index 13a86cb..7ee5c7d 100755 --- a/modules/erl/euphorik_requests.erl +++ b/modules/erl/euphorik_requests.erl @@ -12,8 +12,9 @@ -include_lib("xmerl/include/xmerl.hrl"). -include_lib("yaws/include/yaws_api.hrl"). + -% Test du module +% Test du module (TODO) tester() -> que_dal. @@ -22,15 +23,13 @@ tester() -> out(A) -> %inet:setopts(A#arg.clisock, inet:getopts(A#arg.clisock, [active])), {value, {_, Contenu}} = lists:keysearch("action", 1, yaws_api:parse_post(A)), - Ret = traiter_donnees(Contenu), - %{content, "text/xml", Ret}. + Ret = traiter_donnees(Contenu), {content, "application/json", Ret}. traiter_donnees(Contenu) -> case json:decode_string(Contenu) of {ok, {struct, [{action, Action}| Reste]}} -> - %io:format("~p~n", [euphorik_protocole:login(JSON)]), json:encode(traiter_action(Action, Reste)); _ -> error diff --git a/modules/include/euphorik_bd.hrl b/modules/include/euphorik_bd.hrl index 841d7a4..173ab09 100755 --- a/modules/include/euphorik_bd.hrl +++ b/modules/include/euphorik_bd.hrl @@ -40,6 +40,7 @@ date_creation, % erlang:now() date_derniere_connexion, % erlang:now(), est mis à jour lors de n'importe quelle activitée (envoie de message par exemple) css = [], % string() + nick_format = nick, %atom(), peut valoir 'nick', 'login' ou 'nick_login' indice_flood = 0, % integer() est incrémenté lorsque l'utilisateur envoie trop rapidement des messages. page_principale = 1, % la page de la conversation principale conversations = [] % [{integer(), integer()}], la liste des messages correspondant au conversation ainsi que la page affichée -- 2.45.1 From 6fab12088e85e62ef34a312c3f3a33f9636bbc97 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Fri, 2 May 2008 20:28:31 +0000 Subject: [PATCH 09/16] FIX petit bug de merde qui faisait bien chier sa race --- js/pageMinichat.js | 3 ++- modules/erl/euphorik_minichat_conversation.erl | 18 ++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/js/pageMinichat.js b/js/pageMinichat.js index e8d607a..a6ba5a6 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -805,7 +805,8 @@ Messages.prototype.rafraichirMessages = function(vider) // ajoute les messages reçu à leur conversation respective for (var numConv = 0; numConv < data["conversations"].length; numConv++) { - //PLOP if (data["conversations"][numConv]["messages"].length == 0) continue + // ya pas de nouveaux message -> on passe à la prochaine conversation + if (data["conversations"][numConv]["messages"].length == 0) continue thisMessages.ajouterMessages(data["conversations"][numConv], numConv) diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index eb154ee..9015fec 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -13,8 +13,6 @@ conversations/4 ]). --compile(export_all). - -include("euphorik_bd.hrl"). -include_lib("stdlib/include/qlc.hrl"). @@ -198,7 +196,7 @@ conversation_principale2(C, Messages, N, S) -> % @spec conversation([integer()], integer(), integer(), integer()) -> Conversation_detailee() conversation(R, N, D, P) -> {C, X} = conversation([], [R], []), - Decalage = N*(P-1)+1, + Decalage = N * (P - 1) + 1, { reverse(C), if Decalage > length(C) -> @@ -220,13 +218,13 @@ conversation(R, N, D, P) -> conversation(Messages, [M | Reste], X) -> Est_deja_traite = any(fun(E) -> E =:= M end, Messages), if Est_deja_traite -> - conversation(Messages, Reste, X); - true -> - Enfants = enfants(M), - Parents = parents(M), - % un message est dit externe si un de ses parent ne fait pas partie de la conversation ou si un de ses parents fait partie de X - Est_message_externe = Parents -- Messages =/= [] orelse intersection(Parents, X) =/= [], - conversation([M | Messages], Reste ++ Enfants, if Est_message_externe -> [M | X]; true -> X end) + conversation(Messages, Reste, X); + true -> + Enfants = enfants(M), + Parents = parents(M), + % un message est dit externe si un de ses parent ne fait pas partie de la conversation ou si un de ses parents fait partie de X + Est_message_externe = Parents -- Messages =/= [] orelse intersection(Parents, X) =/= [], + conversation([M | Messages], lists:merge(Reste, Enfants), if Est_message_externe -> [M | X]; true -> X end) end; conversation(Messages, [], X) -> {Messages, X}. -- 2.45.1 From 5f49b7e6af9be3e2415136013370af4ac99d59da Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sat, 3 May 2008 23:03:00 +0000 Subject: [PATCH 10/16] FIX gros bug moisi (ajout de l'information du dernier message au niveau des conversations) --- doc/TODO.txt | 6 ++- doc/graphiques/fond3.xcf | Bin 0 -> 1837 bytes doc/protocole3.txt | 3 +- img/css1/fond.png | Bin 212 -> 362 bytes js/euphorik.js | 6 --- js/pageMinichat.js | 49 +++++++++++++----- modules/erl/euphorik_minichat.erl | 4 +- .../erl/euphorik_minichat_conversation.erl | 14 +++-- modules/erl/euphorik_protocole.erl | 8 ++- 9 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 doc/graphiques/fond3.xcf diff --git a/doc/TODO.txt b/doc/TODO.txt index 4daa86d..be11f27 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -151,7 +151,11 @@ 1 : Critique 2 : Urgent 3 : Peu grave - + +[1] Bug rafraichissement des conversations, exemple : + - la page 2 de la conv est affiché (mess 1 à 10) et la conv principale contient les mess de 11 à 2. + - lors de l'ajout d'un mess dans la conv celle ci n'est pas rafraichit. + - trouver une solution : donné un idDernierMess pour chaque conv ou supprimer cet idDernierMess et jouer sur le fait que l'on recoit un message après l'autre (orientation des messages après attente) [1] Lors de l'extraction d'une conv il arrive que la conv extracté soit bien créée mais vide, le bouton ne ferme pas la conv (très étrange, bug de firefox?) [2] Quand on revient en arrière dans firefox le message en rédaction est perdu [2] En changeant de page puis en revenant sur la page principale les smiles ne sont plus highlightés lorsque le curseur les survol diff --git a/doc/graphiques/fond3.xcf b/doc/graphiques/fond3.xcf new file mode 100644 index 0000000000000000000000000000000000000000..33cf542db1a4c3124a3eb0abced4c23a062eb5a8 GIT binary patch literal 1837 zcmc&#&2G~`5OxB}2A6spe(a-{Q_@3lfrGDBk%Ex;@rk?Zt{scSu54FLBqUyd124gW zSKtA7D+J%z>ne!Yk$hpKZ@+JMc4lYncoQe=AHRv8goedyM_>!N)Pu&ckfImT8H(M$QK>a~YKKQrslvQoMTo)+f(NwKZ7>v7E!y zL(@hdni<$rpr@<9lQ-f`u$4I`+K>j=2%s1B8yG81yYDFt()1mDw4?9u=;IyDp($5m z41&%eYknAa>M4!GrP3alfW5;{U^1`9@C!|t!E_GTy_xHd(T=I%Ab&fo4qqK->kRps z(TCm6v#D?1Q9JeJ9`IWRGuea#c5mhr$85*cbdbLtR)?>SvnLGsnc0Wk&ab6l| zHhtIH(RmPljPvX|t*-a~btyHMA}SjFstUWkfHYiKjQ;M(yc+BYP0-Fa;5+d14~PHg A s "conversations" : [ { "racine" : 123, - "page" : 1 + "page" : 1, + "last_message_id" : 4 (pas obligatoire) } ] } diff --git a/img/css1/fond.png b/img/css1/fond.png index 948403721e935b3321523c0f98484f9b54ed0593..84fd46678871cf1a8011bc191c76ecdcf29e767f 100755 GIT binary patch delta 288 zcmcb@_=-ufGr-TCmrII^fq{Y7)59eQNIQTq2OE%Fm05UiqM|(yvjDHGQqs~HKq1MA zIg<76p1uL$jeO!j{!vdC$B>F!Z*LoNwK(vwUMRen)~#zh{kwff@1b{`*F+RGo-CD> znA5IU@38#*uG-_SbC1_;wR!f`)+lsueaQNYdw^yDt$RLevvkVyim!9NgX{%?|HlhV zj;}6u`o(ZkW+5wB$loV7;0i+O-_M`>_^PENH&{i(Im-v{e((6twiV1}*s->5GJ_7|qv;M{c~4hAmvv4F FO#m|7VS)ev delta 137 zcmaFGbcIo|Gr-TCmrII^fq{Y7)59eQNDF{42OE%-|NK93qM|(yqX-Mzm809UfI_kp zb0qykGEx=XJ$(b-r>N!u#k4(L978NlCqEJ9{&Bv6{m;+8yz@<%g_&Cut~4A>VBlU@ jk(T&WiucIFd\n", "text/xml") - var s = new XMLSerializer() - alert(s.serializeToString(doc)) */ - var util = new Util() var client = new Client(util) var pages = new Pages() diff --git a/js/pageMinichat.js b/js/pageMinichat.js index a6ba5a6..9e042e4 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -296,6 +296,7 @@ function Conversation(num, util, formateur, client) this.util = util this.formateur = formateur this.client = client + this.idDernierMessageAffiche = 0 this.messages = new Array() this.messagesParId = new Object() @@ -403,6 +404,7 @@ Conversation.prototype.ajouterMessage = function(message) Conversation.prototype.viderMessages = function() { this.messages = new Array() + this.idDernierMessageAffiche = 0 jQuery("#conversations #" + this.getId() + " .message").remove() } @@ -415,18 +417,15 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) { var thisConversation = this - var idDernierMessageAffiche = jQuery("#conversations #" + this.getId() + " div:first").attr("id") - idDernierMessageAffiche = (idDernierMessageAffiche == undefined ? 0 : parseInt(idDernierMessageAffiche, 36)) - // est-ce que le prochain message est pair ? (permet d'alterner le style des messages) - var messagePair = (idDernierMessageAffiche == 0 ? true : + var messagePair = (this.idDernierMessageAffiche == 0 ? true : (jQuery("#conversations #" + this.getId() + " div:first").attr("class").search("messagePair") == -1) ) // construction de l'XHTML des messages var XHTML = "" for (var i = this.messages.length - 1; i >= 0; i--) - if (this.messages[i].id > idDernierMessageAffiche) + if (this.messages[i].id > this.idDernierMessageAffiche) { var message = this.messages[i] @@ -470,7 +469,7 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) jQuery("#conversations #" + this.getId() + " .message").slice(this.nbMessageMax, nbMessagesAffiche).empty() // Ajoute les événements liés à chaque message - jQuery("#conversations #" + this.getId() + " .message").filter(function(){return parseInt(jQuery(this).attr("id"), 36) > idDernierMessageAffiche}).each( + jQuery("#conversations #" + this.getId() + " .message").filter(function(){return parseInt(jQuery(this).attr("id"), 36) > thisConversation.idDernierMessageAffiche}).each( function() { jQuery(".lienConv", this).click( @@ -520,6 +519,9 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) ) } ) + + this.idDernierMessageAffiche = jQuery("#conversations #" + this.getId() + " div:first").attr("id") + this.idDernierMessageAffiche = (this.idDernierMessageAffiche == undefined ? 0 : parseInt(this.idDernierMessageAffiche, 36)) } /** @@ -574,7 +576,8 @@ function Messages(client, formateur, util) this.conversations = new Array() // les conversations, la première représente la conversation principale this.nouvelleConversation(0) - this.idDernierMessage = null // l'id du dernier message connu +// Obsolète + //this.idDernierMessage = null // l'id du dernier message connu // l'objet JSONHttpRequest représentant la connexion d'attente this.attenteCourante = null @@ -590,15 +593,28 @@ Messages.prototype.getJSONrafraichirMessages = function() "page" : "chat", "message_count" : conf.nbMessageAffiche, "main_page" : this.client.pagePrincipale, - "conversations" : this.client.getJSONConversations() + "conversations" : this.getJSONConversations() } if (this.client.cookie != null) mess["cookie"] = this.client.cookie; - if (this.idDernierMessage != null) mess["last_message_id"] = this.idDernierMessage + mess["last_message_id"] = this.conversations[0].idDernierMessageAffiche + + // obsolète + //if (this.idDernierMessage != null) mess["last_message_id"] = this.idDernierMessage return mess } +Messages.prototype.getJSONConversations = function() +{ + var clientConv = this.client.getJSONConversations() + for (var i = 1; i < this.conversations.length; i++) + { + clientConv[i-1]["last_message_id"] = this.conversations[i].idDernierMessageAffiche + } + return clientConv +} + /** * Ajoute un ensemble de messages puis les affiches. * @param elements un tableau d'éléments JSON représentant les messages, voir protocole.txt @@ -624,8 +640,9 @@ Messages.prototype.ajouterMessage = function(element, numConversation) // pas d'utilisation de jquery pour des raisons de performance var id = element["id"] - if (this.idDernierMessage == null || id > this.idDernierMessage) - this.idDernierMessage = id + // Obsolète + /*if (this.idDernierMessage == null || id > this.idDernierMessage) + this.idDernierMessage = id*/ var message = new Message( id, @@ -756,7 +773,8 @@ Messages.prototype.flush = function(numConv) Messages.prototype.viderMessages = function() { - this.idDernierMessage = null + // Obsolète + //this.idDernierMessage = null for (var i = 0; i < this.conversations.length; i++) this.conversations[i].viderMessages() @@ -785,8 +803,11 @@ Messages.prototype.rafraichirMessages = function(vider) this.stopAttenteCourante() + /*if (vider) + this.idDernierMessage = null*/ if (vider) - this.idDernierMessage = null + for (var i = 0; i < this.conversations.length; i++) + this.conversations[i].idDernierMessageAffiche = 0 dumpObj(this.getJSONrafraichirMessages()) this.attenteCourante = jQuery.ajax({ @@ -802,7 +823,7 @@ Messages.prototype.rafraichirMessages = function(vider) if (vider) thisMessages.viderMessages() - // ajoute les messages reçu à leur conversation respective + // ajoute les messages reçus à leur conversation respective for (var numConv = 0; numConv < data["conversations"].length; numConv++) { // ya pas de nouveaux message -> on passe à la prochaine conversation diff --git a/modules/erl/euphorik_minichat.erl b/modules/erl/euphorik_minichat.erl index 519870c..6f229ac 100755 --- a/modules/erl/euphorik_minichat.erl +++ b/modules/erl/euphorik_minichat.erl @@ -196,14 +196,14 @@ update_pseudo_user(UserId, Pseudo) -> % Mise à par Cookie les autres peuvent être undefined ce qui veut dire qu'ils ne seront pas modifié. -set_profile(Cookie, Login, Password, Pseudo, Email, Css, Page_principale, Nick_format, Conversations) -> +set_profile(Cookie, Login, Password, Pseudo, Email, Css, Nick_format, Page_principale, Conversations) -> if Nick_format =:= nick; Nick_format =:= login; Nick_format =:= nick_login -> resultat_transaction(mnesia:transaction( fun() -> case user_by_cookie(Cookie) of {ok, User} -> case user_by_login(Login) of - {ok, U} when U#user.id =/= User#user.id -> + {ok, U} when User#user.login =/= [], U#user.id =/= User#user.id -> login_deja_pris; _ -> User_modifie = User#user{ diff --git a/modules/erl/euphorik_minichat_conversation.erl b/modules/erl/euphorik_minichat_conversation.erl index 9015fec..a280e1f 100755 --- a/modules/erl/euphorik_minichat_conversation.erl +++ b/modules/erl/euphorik_minichat_conversation.erl @@ -27,7 +27,7 @@ % Message est le message de type #minichat et Parents une liste d'Id. % Plus est un bool. Si Plus vaut true alors il y a encore des messages. % Si il n'y a pas de nouveaux message alors la fonction est bloquante et attend un nouveau message. -% @spec conversations([{integer(), integer()}], integer(), integer(), integer()) -> [Conversation()] +% @spec conversations([{integer(), integer(), integer()}], integer(), integer(), integer()) -> [Conversation()] conversations(Racines, N, D, P) -> % écoute des nouveaux messages case subscribe(minichat, 2) of @@ -36,6 +36,7 @@ conversations(Racines, N, D, P) -> _ -> % demande des conversations Conversations = conversations_detailees(Racines, N, D, P), + %io:format("Conversations : ~p~n", [Conversations]), % si les conversations sont vides alors on attend un nouveau message Vide = not any( fun(C) -> @@ -50,11 +51,14 @@ conversations(Racines, N, D, P) -> Conversations_mises_en_forme = mise_en_forme_conversations( if Vide -> attend_nouveau_message(), + %io:format("Racines = ~p, N = ~p, D = ~p, P = ~p~n", [Racines, N, D, P]), + %io:format("Conversations = ~p~n", [conversations_detailees(Racines, N, D, P)]), conversations_detailees(Racines, N, D, P); true -> Conversations end ), + %io:format("Conversations_mises_en_forme = ~p~n", [Conversations_mises_en_forme]), unsubscribe(minichat), Conversations_mises_en_forme end. @@ -132,7 +136,7 @@ mise_en_forme_conversation(Messages) -> % Racines est une liste de tuple {Id, P} des racines des conversations ou P est la page et Id l'id du message. % @spec conversations_detailees([{integer(), integer()}], integer(), integer(), integer()) -> [[integer()] | Conversation_detailee()] conversations_detailees(Racines, N, D, P) -> - Conversations = map(fun({Racine, P_conv}) -> conversation(Racine, N, D, P_conv) end, Racines), + Conversations = map(fun({Racine, P_conv, Dernier}) -> conversation(Racine, N, Dernier, P_conv) end, Racines), Conversation_principale = resultat_transaction(transaction(fun() -> Curseur = qlc:cursor(q([E#minichat.id || E <- qlc:sort(table(minichat), [{order, descending}])])), {CP, Plus} = conversation_principale(Curseur, Conversations, N, P), @@ -202,10 +206,10 @@ conversation(R, N, D, P) -> if Decalage > length(C) -> []; true -> - reverse(filter( + filter( fun(E) -> E > D end, - sublist(C, Decalage, N) - )) + reverse(sublist(C, Decalage, N)) + ) end, reverse(X), Decalage + N - 1 < length(C) diff --git a/modules/erl/euphorik_protocole.erl b/modules/erl/euphorik_protocole.erl index c2cb984..7519ba8 100755 --- a/modules/erl/euphorik_protocole.erl +++ b/modules/erl/euphorik_protocole.erl @@ -109,7 +109,13 @@ wait_event(Data) -> {value, {_, Message_count}} = lists:keysearch(message_count, 1, Data), Main_page = case lists:keysearch(main_page, 1, Data) of {value, {_, P}} -> P; _ -> 1 end, {value, {_, {array, Conversations_json}}} = lists:keysearch(conversations, 1, Data), - Conversations = lists:map(fun({struct, [{root, Racine}, {page, Page}]}) -> {Racine, Page} end, Conversations_json), + Conversations = lists:map( + fun({struct, [{root, Racine}, {page, Page} | Reste]}) -> + Last_mess_conv = case Reste of [{last_message_id, L}] -> L; _ -> 0 end, + {Racine, Page, Last_mess_conv} + end, + Conversations_json + ), User = case euphorik_minichat:user_by_cookie(Cookie) of {ok, U} -> U; _ -> inconnu -- 2.45.1 From f6158580ec307685d5ac2075ff7a58f205335690 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sat, 3 May 2008 23:09:25 +0000 Subject: [PATCH 11/16] =?utf8?q?MOD=20optimisation=20qui=20je=20l'esp?= =?utf8?q?=C3=A8re=20n'a=20pas=20trop=20foutu=20la=20merde?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- js/pageMinichat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/pageMinichat.js b/js/pageMinichat.js index 9e042e4..637ff21 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -520,8 +520,8 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) } ) - this.idDernierMessageAffiche = jQuery("#conversations #" + this.getId() + " div:first").attr("id") - this.idDernierMessageAffiche = (this.idDernierMessageAffiche == undefined ? 0 : parseInt(this.idDernierMessageAffiche, 36)) + if (this.messages.length > 0) + this.idDernierMessageAffiche = this.messages[this.messages.length-1].id } /** -- 2.45.1 From ac67ff1ae69108b98f190f3da18ced663a84c0da Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 4 May 2008 15:18:51 +0000 Subject: [PATCH 12/16] ADD LOGO + favicon MOD simplification dans pageMinichat.js --- doc/TODO.txt | 12 ++--- doc/graphiques/logo.svg | 101 ++++++++++++++++++++++++++++++++++++++++ favicon.gif | Bin 0 -> 397 bytes js/pageMinichat.js | 23 ++++----- 4 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 doc/graphiques/logo.svg create mode 100644 favicon.gif diff --git a/doc/TODO.txt b/doc/TODO.txt index be11f27..def1a70 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -4,11 +4,6 @@ * Rendre compatible IE 7 * Tester avec des caractères accentués sur Firefox, Safari, Opera et IE7. Les messages doivent être envoyés en UTF8. * Tester avec des caractères exotiques (jap, coréen, etc..) -* Ralentir volontairement le connexion lors d'un mauvais login (ou après n mauvais login) -* Pouvoir afficher le login et/ou le pseudo. Avoir dans le profile une liste box avec ces choix : - * pseudo - * login - * pseudo(login) * Réduire les pseudos trop long en mettant un ".." à la fin et permettre de le voir en entier lorsque le curseur le survol. * Mettre un icone (genre sablier ou truc qui tourne à la apple) lorsque le chat se charge (également lors d'un changement de page par exemple) * Modifier la syntaxe des smiles actuels (pour pas qu'ils entre en conflit avec totoz) @@ -146,7 +141,12 @@ [ok] Utiliser une listbox pour la liste des css [ok] Changer les noms des css : Light -> Cold, Old -> Classic [ok] Faire une page faq et raconter n'importe quoi (entre autre la limitation avec firefox) "pourquoi ce site à des couleurs qui ne veulent rien dire ?" - +[ok] Ralentir volontairement le connexion lors d'un mauvais login (ou après n mauvais login) +[ok] Pouvoir afficher le login et/ou le pseudo. Avoir dans le profile une liste box avec ces choix : + * pseudo + * login + * pseudo(login) + === Bugs === 1 : Critique 2 : Urgent diff --git a/doc/graphiques/logo.svg b/doc/graphiques/logo.svg new file mode 100644 index 0000000..14120f6 --- /dev/null +++ b/doc/graphiques/logo.svg @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/favicon.gif b/favicon.gif new file mode 100644 index 0000000000000000000000000000000000000000..90238b632664dc8132b8058e2d86b6e1290f66b6 GIT binary patch literal 397 zcmZ?wbhEHb6krfwSZc}u1dNPKoSghzTtFlsEG#c6sVOA|L|W3)+S1ZGva))zvifpz zKx7~%XDBZZL`KTW7Ah*1s;buN>UQet_8J-v8XAt8nogRU&f40p+S+b9I_|o<9=f`o zdV1da`aXt+ex|0O78X&KmeIDhNw&7hc6KQa4jE2P+0M>6?(Rh%9;IGh<=);EK0Z}G zKGnXyHGY0|0RfHw2?51_g3d*$i6yBi3gww484B*6z5xu1KUo;L80;BzK;8p+l!0xk zLqmawju>;R^W%+yEIkd4hn?PDNSo|fsIW1|WLh6j%1n;7#`aVb CYkHpm literal 0 HcmV?d00001 diff --git a/js/pageMinichat.js b/js/pageMinichat.js index 637ff21..31d19ba 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -413,7 +413,7 @@ Conversation.prototype.viderMessages = function() * d'afficher les messages non-affichés. * @param funClickExtract fonction (fun(numMess)) appellée lors du clic sur un bouton "extraire" */ -Conversation.prototype.flush = function(funClickExtract, funClickLienConv) +Conversation.prototype.flush = function(funClickOuvrirConv) { var thisConversation = this @@ -477,7 +477,7 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) { // FIXME : ya pas mieux ? var racine = jQuery(event.target).text() - funClickLienConv(parseInt(racine.substring(1, racine.length - 1), 36)) + funClickOuvrirConv(parseInt(racine.substring(1, racine.length - 1), 36)) return false } ) @@ -493,7 +493,7 @@ Conversation.prototype.flush = function(funClickExtract, funClickLienConv) // extraction d'une conversation if (jQuery(event.target).is(".extraire")) { - funClickExtract(parseInt(idMess, 36)) + funClickOuvrirConv(parseInt(idMess, 36)) return } @@ -757,20 +757,21 @@ Messages.prototype.flush = function(numConv) var thisMessages = this this.conversations[numConv].flush( - // fonction appelée lors de la demande d'extraction d'une conversation - function(idMess) - { - if (thisMessages.client.ajouterConversation(idMess)) - thisMessages.rafraichirMessages(true) - }, function(racine) // appelé lorsqu'un utilisateur click sur un lien vers une conversation { - if (thisMessages.client.ajouterConversation(racine)) - thisMessages.rafraichirMessages(true) + thisMessages.ouvrirConversation(racine) } ) } +Messages.prototype.ouvrirConversation = function(racine) +{ + if (this.client.ajouterConversation(racine)) + this.rafraichirMessages(true) + else + this.util.messageDialogue("Cette conversation est déjà ouverte") +} + Messages.prototype.viderMessages = function() { // Obsolète -- 2.45.1 From 02d92b37eeead65a9d8fb2f45560db913d04190f Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 4 May 2008 15:35:08 +0000 Subject: [PATCH 13/16] --- favicon.gif | Bin 397 -> 0 bytes favicon.ico | Bin 0 -> 1150 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 favicon.gif create mode 100644 favicon.ico diff --git a/favicon.gif b/favicon.gif deleted file mode 100644 index 90238b632664dc8132b8058e2d86b6e1290f66b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 397 zcmZ?wbhEHb6krfwSZc}u1dNPKoSghzTtFlsEG#c6sVOA|L|W3)+S1ZGva))zvifpz zKx7~%XDBZZL`KTW7Ah*1s;buN>UQet_8J-v8XAt8nogRU&f40p+S+b9I_|o<9=f`o zdV1da`aXt+ex|0O78X&KmeIDhNw&7hc6KQa4jE2P+0M>6?(Rh%9;IGh<=);EK0Z}G zKGnXyHGY0|0RfHw2?51_g3d*$i6yBi3gww484B*6z5xu1KUo;L80;BzK;8p+l!0xk zLqmawju>;R^W%+yEIkd4hn?PDNSo|fsIW1|WLh6j%1n;7#`aVb CYkHpm diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..725fc65d95fcf685612432782863897af71a8304 GIT binary patch literal 1150 zcmbtT&r3o<5MHB;UKE5tMGaK+<&W131SK?6O7j<9y40;Y2z3ggs0jL-J9V1oo8By& zVNkutyxliD-|RQv&KeWpH<2*>-8RcjW44Sj6*hLU=hM%_y624--v4NdCB} zXmPztMdpgX9S#Ze{Zh%zA$af#!hPpKKzE}NO?}_uuex124D*4TpUrA5f=9jZW6!7Q zRJba>>(qi6Z~zzR!F34UOQi%qs@LhV)1eDCXy)pGJg3bjz0Bv5AM1*5FdsK|b>8

Date: Sun, 4 May 2008 17:50:20 +0000 Subject: [PATCH 14/16] ADD nouveaux smiles --- css/1/euphorik.css | 2 +- css/1/pageMinichat.css | 6 ++++++ doc/TODO.txt | 10 +++++----- img/css1/fond.png | Bin 362 -> 362 bytes img/smileys/agreed.gif | Bin 0 -> 457 bytes img/smileys/boh.gif | Bin 0 -> 133 bytes img/smileys/dodo.gif | Bin 0 -> 431 bytes img/smileys/heink.gif | Bin 0 -> 282 bytes img/smileys/hum.gif | Bin 0 -> 123 bytes img/smileys/slurp.gif | Bin 141 -> 96 bytes js/euphorik.js | 31 +++++++++++++++++++------------ js/pageMinichat.js | 7 ++++--- 12 files changed, 35 insertions(+), 21 deletions(-) create mode 100644 img/smileys/agreed.gif create mode 100644 img/smileys/boh.gif create mode 100644 img/smileys/dodo.gif create mode 100644 img/smileys/heink.gif create mode 100644 img/smileys/hum.gif diff --git a/css/1/euphorik.css b/css/1/euphorik.css index 16b6436..67848f0 100755 --- a/css/1/euphorik.css +++ b/css/1/euphorik.css @@ -71,7 +71,7 @@ body { height: 37px; position: absolute; top: -20px; - left: -10px; + left: 4px; } #footer { diff --git a/css/1/pageMinichat.css b/css/1/pageMinichat.css index 022af89..67a915d 100755 --- a/css/1/pageMinichat.css +++ b/css/1/pageMinichat.css @@ -127,6 +127,12 @@ color: #76ff33; } +#page.minichat div.message .pseudo .login { + margin-left: 2px; + font-size: 8px; + color: #a7d88f; +} + #page.minichat div.systeme .pseudo { color: #CCCCCC } diff --git a/doc/TODO.txt b/doc/TODO.txt index def1a70..96977c3 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -7,9 +7,7 @@ * Réduire les pseudos trop long en mettant un ".." à la fin et permettre de le voir en entier lorsque le curseur le survol. * Mettre un icone (genre sablier ou truc qui tourne à la apple) lorsque le chat se charge (également lors d'un changement de page par exemple) * Modifier la syntaxe des smiles actuels (pour pas qu'ils entre en conflit avec totoz) -* Créer un favicon (joli) * Ajouter dans la FAQ et/ou dans la page d'enregistrement les conditions d'utilisation, genre "chacun est responsable de ses dires" https://linuxfr.org/bouchot/ -* Inscrire le nom de l'image dans les les liens vers des images (à la place de simplement [jpg] ou [gif]) * Ajouter de nouveaux smiles et changer la syntax pour eviter le conflit avec totoz : * "slurp" : http://forum-images.hardware.fr/images/perso/huit.gif * "agreed" : http://forum-images.hardware.fr/icones/smilies/jap.gif @@ -30,7 +28,6 @@ * Cleaner le code (erl, js, xhtml, css) et eventuellement profiler un peu (le refresh est lent sous opera) * Restructurer le code Erlang : déplacer certaines fonctions d'un module à l'autre (ev. créer des modules) * Choisir une licence et la mettre un peu partout dans les sources, voir : http://www.gnu.org/licenses/gpl-howto.fr.html -* Créer une page 'about' * Trouver un moyen pour éviter la création à la suite de plusieurs comptes (via register). * Finir le script de mise en production * Make des modules. @@ -146,7 +143,9 @@ * pseudo * login * pseudo(login) - +* Créer un favicon (joli) +[ok] Créer une page 'about' + === Bugs === 1 : Critique 2 : Urgent @@ -213,7 +212,8 @@ ok : Implémenté * Possibilité d'utiliser les balises , , , (quoted text) * La balise pour mettre des spoilers [2] Pouvoir cacher les dates -[3] Gestion de l'historique (calendrier) +[3] Gestion de l'historique (calendrier) +[3] Inscrire le nom de l'image dans les les liens vers des images (à la place de simplement [jpg] ou [gif]) [4] Outil de localisation des personnes un peu comme ca : http://bouchot.org/cps [4] Pouvoir voir le profile des personnes. * Voir leurs derniers messages diff --git a/img/css1/fond.png b/img/css1/fond.png index 84fd46678871cf1a8011bc191c76ecdcf29e767f..2a46fbce9bbfc436c63c855b80dcf23e0116b8df 100755 GIT binary patch delta 242 zcmaFG^onVMIVS@M{B+)3KhZ&fgGEqJSB-tc?THzN^&5Fx40u>C2+Wn}Z1TNP&&~Bt z%_1g3%%d)EV$hz1pXyDixBK7kSozxOyzUByePB&9Op|}pJyDp5HYLg4HSd#u!9nk?CEYURG)Umyn2(SMb{<-AVV?v3SXAOTNT KKbLh*2~7Y>{a1wm delta 242 zcmaFG^onVMIp=={AY8C_`Q(WX3LMM=ys}D3OJ_{XFswJ^YH{FUy-;{Dty|Z2`gi+| z-b3#=uZbvXJXtC$F{fRz-eLLqUA4zu=N_-yYV+)=tx@RS`jGV(_b`Bf!}D32rBj|) ze4X>14J^RG@c(#$$??_2PQMsV$}D7ss*({nd-0WJ++5>DpEDW3VizpgZT>M%whU5@ zy3Pa^Sy0SZ@vC;fm3jtTMM(Yo`Ews%wRGeLt7tf9`QY8}9sk+3g1HPk*49mC&|!Qu Q-2p7`>FVdQ&MBb@00sYA#{d8T diff --git a/img/smileys/agreed.gif b/img/smileys/agreed.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7a08e1ba65f46d364a22c04529dcc5be51a3027 GIT binary patch literal 457 zcmZ?wbhEHb6k!ly*u=o_|Nnmm1_l!olix>~{{3fTWMl+#fk5#;x1VcBu(M-;tC5}o zGe}hNCky8Z237_gkUU5`19L#ct~>u!4@fpI(Cew)cuBgQHDSlZfXrD!$}6;QA1c(D zIBmiEJ$>g}78GdY=rXm$3r^2b=)9ozSW;HXKJ=03?5S4W4<3Bmv7~Q#$Vbc1%_9XY5f@fD9Z+}{nW$-ZD1BD)!gU)Ka~iBJ{mk>M*!hpW z+=YW20ygs$Km9OZnjf%;-z(K@wST6d^_D+#j_V&!joEfAB}J7H?2QzN4J<$#1b{Yp zM(mPO)H!AD(pt3BV3&NfNJK?oEwL$`YK17Wc2n s(TYBEGmtCQYW_^8k5OkWSb{^QZGUMb1U8+Ew(kGOx@p6P4Gav{06NX5fB*mh literal 0 HcmV?d00001 diff --git a/img/smileys/boh.gif b/img/smileys/boh.gif new file mode 100644 index 0000000000000000000000000000000000000000..467b7feaed81db25bd42380d83cbf25747cb05c0 GIT binary patch literal 133 zcmZ?wbhEHb67NQZ?hJ^dAV$_r0-Jasb!i0A0}Unm^7J#!5RQA!Ge~SmTA+b)z{be^z_V}IkU91w4$P7^5n@27cT7R z=;-e5E-o%EDk_>VVM1YHVOv{UZEbCDZ||Hrb0$riw0!yUS+i!9mzOVHy0o&gvbwsu zv$M0TtgNxI@&Et-3=9kq63CzhQ2fcl$iSe;paU`-)@2^N+=R zg=JeL=SH>8UllsjC24E$i_4N{+b83nL4I4oC$^I|H+&$Eu5aCzv?CY+jhP`_nx}VV)-j)BKs&+<)ncD^TspBQ${S?H-HAhE;p@{eBC9 z?L$)`C?Tbyr@*vHVyDGx?ew*0CqvAMU_voRKtoI9Uta@f$6kwgjh9IQOkktX6k##S F8URdF0cRq literal 0 HcmV?d00001 diff --git a/img/smileys/slurp.gif b/img/smileys/slurp.gif index cced52cd1b05281117dda9cb094daa2e01db6d9e..ab3ca570e19bd84a6929c0bdc3a11fef39ad68a5 100755 GIT binary patch literal 96 zcmZ?wbhEHbtqYYOJFDP7lKV6X-NguWo? literal 141 zcmZ?wbhEHbz>% diff --git a/js/euphorik.js b/js/euphorik.js index 6685b16..3b17bf5 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -21,19 +21,26 @@ var conf = { "bigsmile" : [/:D/g, /:-D/g], "clin" : [/;\)/g, /;-\)/g], "cool" : [/8\)/g, /8-\)/g], - "eheheh" : [/:P/g, /:-P/g], - "oh" : [/:o/g, /:O/g], + "eheheh" : [/:P/g, /:-P/g], + "lol" : [/\[-lol\]/g], + "spliff" : [/\[-spliff\]/g], + "oh" : [/:o/g, /:O/g], + "heink" : [/\[-heink\]/g], + "hum" : [/\[-hum\]/g], + "boh" : [/\[-boh\]/g], + "sniff" : [/:\(/g, /:-\(/g], + "triste" : [/\[-triste\]/g], "pascontent" : [/>\(/g, />\(/g], - "sniff" : [/:\(/g, /:-\(/g], - "argn" : [/\[:argn\]/g], - "bunny" : [/\[:lapin\]/g], - "chat" : [/\[:chat\]/g], - "renne" : [/\[:renne\]/g], - "lol" : [/\[:lol\]/g], - "spliff" : [/\[:spliff\]/g], - "star" : [/\[:star\]/g], - "triste" : [/\[:triste\]/g], - "kirby" : [/\[:kirby\]/g] + "argn" : [/\[-argn\]/g], + "redface" : [/\[-redface\]/g], + "bunny" : [/\[-lapin\]/g], + "chat" : [/\[-chat\]/g], + "renne" : [/\[-renne\]/g], + "star" : [/\[-star\]/g], + "kirby" : [/\[-kirby\]/g], + "slurp" : [/\[-slurp\]/g], + "agreed" : [/\[-agreed\]/g], + "dodo" : [/\[-dodo\]/g] } } diff --git a/js/pageMinichat.js b/js/pageMinichat.js index 31d19ba..8d914b4 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -431,8 +431,9 @@ Conversation.prototype.flush = function(funClickOuvrirConv) // construit l'identifiant de la personne var identifiant = - this.client.nickFormat == "nick" ? message.pseudo : - (this.client.nickFormat == "login" ? message.login : message.pseudo + "(" + message.login +")" ) + this.client.nickFormat == "nick" ? this.formateur.traitementComplet(message.pseudo) : + (this.client.nickFormat == "login" ? this.formateur.traitementComplet(message.login) : + this.formateur.traitementComplet(message.pseudo) + "(" + this.formateur.traitementComplet(message.login) +")" ) var XHTMLrepondA = "" for (var id in message.repondA) @@ -448,7 +449,7 @@ Conversation.prototype.flush = function(funClickOuvrirConv) "\">" + "

>
" + "[" + message.date + "]" + - "" + this.formateur.traitementComplet(identifiant) + ":" + + "" + identifiant + ":" + XHTMLrepondA + "" + (message.systeme ? this.formateur.remplacerBalisesHTML(message.contenu) : this.formateur.traitementComplet(message.contenu, message.pseudo)) + "" + "" -- 2.45.1 From ed8f28689ec85a02ee1507ae259e1fbd5517f701 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 4 May 2008 20:42:11 +0000 Subject: [PATCH 15/16] MOD affichage des smiles dans une fenetre --- css/1/euphorik.css | 2 +- css/1/pageMinichat.css | 27 ++++++++++++------- doc/TODO.txt | 18 ++++++------- doc/graphiques/bouton_smiles.xcf | Bin 0 -> 1033 bytes img/css1/bouton_smiles.png | Bin 0 -> 237 bytes img/smileys/bn.gif | Bin 0 -> 1446 bytes img/smileys/hum.gif | Bin 123 -> 124 bytes img/smileys/redface.gif | Bin 0 -> 95 bytes js/euphorik.js | 10 +++---- js/pageMinichat.js | 43 +++++++++++++++++++++++++------ 10 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 doc/graphiques/bouton_smiles.xcf create mode 100644 img/css1/bouton_smiles.png create mode 100644 img/smileys/bn.gif create mode 100644 img/smileys/redface.gif diff --git a/css/1/euphorik.css b/css/1/euphorik.css index 67848f0..2630f1f 100755 --- a/css/1/euphorik.css +++ b/css/1/euphorik.css @@ -91,7 +91,7 @@ div#info { z-index: 20; } -div#info .fermer { +div#info div.fermer { float:right; cursor: pointer; height:16px; diff --git a/css/1/pageMinichat.css b/css/1/pageMinichat.css index 67a915d..208584b 100755 --- a/css/1/pageMinichat.css +++ b/css/1/pageMinichat.css @@ -4,17 +4,19 @@ vertical-align: bottom; } -#page.minichat #smiles { - border-width: 1px 0px 1px 0px; +#smiles { + border-width: 1px 1px 1px 1px; border-color: #253f18; border-style: solid; margin-bottom: 10px; padding: 1px; - height: 100%; + width: 100px; background-color: #0c2003; + position: absolute; + display: none } - -#page.minichat #smiles img { +#smiles img { + margin: 1px; cursor: pointer; opacity: 0.5; } @@ -28,23 +30,28 @@ margin-bottom: 15px; padding-left: 10px; } - #page.minichat form .pseudo { margin-right: 5px; } - #page.minichat form .message { margin-right: 5px; } - #page.minichat form .return { - height: 15px; + height: 16px; width: 32px; background-image: url(../../img/css1/return.png); background-repeat: no-repeat; background-position: 5px 2px; vertical-align: top; } +#page.minichat form .smiles { + height: 16px; + width: 16px; + background-image: url(../../img/css1/bouton_smiles.png); + background-repeat: no-repeat; + background-position: 2px 2px; + vertical-align: top; +} /* voir pour l'astuce css "float left" des conversations : http://www.quirksmode.org/css/clearing.html */ #page.minichat #conversations { @@ -172,7 +179,7 @@ float: right; padding-right: 5px; padding-left: 5px; - background-color: #c90000; + background-color: #7d1b1b; cursor: pointer; } diff --git a/doc/TODO.txt b/doc/TODO.txt index 96977c3..27e80f9 100755 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -8,15 +8,6 @@ * Mettre un icone (genre sablier ou truc qui tourne à la apple) lorsque le chat se charge (également lors d'un changement de page par exemple) * Modifier la syntaxe des smiles actuels (pour pas qu'ils entre en conflit avec totoz) * Ajouter dans la FAQ et/ou dans la page d'enregistrement les conditions d'utilisation, genre "chacun est responsable de ses dires" https://linuxfr.org/bouchot/ -* Ajouter de nouveaux smiles et changer la syntax pour eviter le conflit avec totoz : - * "slurp" : http://forum-images.hardware.fr/images/perso/huit.gif - * "agreed" : http://forum-images.hardware.fr/icones/smilies/jap.gif - * "dodo" (tete avec un bonnet de nuit et des ZZZZ) - * "hum?" : http://forum-images.hardware.fr/icones/smilies/heink.gif - * "pas reveillé" avec une tasse de café et des cernes : http://forum-images.hardware.fr/images/perso/elmoricq.gif - * "interrogation" genre http://forum-images.hardware.fr/icones/confused.gif - * http://forum-images.hardware.fr/images/perso/dao.gif ou http://forum-images.hardware.fr/icones/redface.gif - * http://forum-images.hardware.fr/icones/ohwell.gif * Avoir un thème de discussion affiché en haut des messages genre appellé "troll de la semaine : linux sera-t-il desktop ready en 2008?" * Un statut "EK" avec plein de privilège à la con. (avoir une petite étoile à coté de son nick ou le nick d'une certaine couleur) * Une page pour voir les trolls de la semaine et pouvoir en ajouter et modifier les siens (page "admin") @@ -145,6 +136,15 @@ * pseudo(login) * Créer un favicon (joli) [ok] Créer une page 'about' +[ok] Ajouter de nouveaux smiles et changer la syntax pour eviter le conflit avec totoz : + * "slurp" : http://forum-images.hardware.fr/images/perso/huit.gif + * "agreed" : http://forum-images.hardware.fr/icones/smilies/jap.gif + * "dodo" (tete avec un bonnet de nuit et des ZZZZ) + * "hum?" : http://forum-images.hardware.fr/icones/smilies/heink.gif + * "pas reveillé" avec une tasse de café et des cernes : http://forum-images.hardware.fr/images/perso/elmoricq.gif + * "interrogation" genre http://forum-images.hardware.fr/icones/confused.gif + * http://forum-images.hardware.fr/images/perso/dao.gif ou http://forum-images.hardware.fr/icones/redface.gif + * http://forum-images.hardware.fr/icones/ohwell.gif === Bugs === 1 : Critique diff --git a/doc/graphiques/bouton_smiles.xcf b/doc/graphiques/bouton_smiles.xcf new file mode 100644 index 0000000000000000000000000000000000000000..21ac57a33d4070485f5f26166e178da739715610 GIT binary patch literal 1033 zcmc&yOHRWu5OqHN(2w}D_6oI&paK#HC<}zd?+R(^q!w*bC8^p-9DxOw$%ead2v+O} zZ&DkzqAU^9KKps*jrBTiASYA4@Oc+ohDd8gc*I2gFRchW0k136WtE?Ng0T6LZOPN;Q}OkGcg0Y5*} z7dATCrliU_vrwim?~MexUPQj1i1gbaQrXYcGPB-F^H5>DGG<-q6L$SpG~LFXnDZMq z6EO))S`bx$9;yK9ij#Uvact!+q@id6nzvSXdxdX<(_K1hAi78YF)Uq#m677wEwtv- zdd_^NbBkHI%__OcjQoS;Iel4P%?(xqjNAfD)NSZmf2uZ_RlrGMvRd)Uiep-;I8~6f uup{)Zp=mbzuJ;(k(JUNN>A!}q9~~B~H!_0IHZgSTeVNiZo2)ZWeZBy{#-1wx literal 0 HcmV?d00001 diff --git a/img/css1/bouton_smiles.png b/img/css1/bouton_smiles.png new file mode 100644 index 0000000000000000000000000000000000000000..40a681d73e44503f209e61615fb81fe9f697e6c8 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>VN3FMcVVby zkY4nJa0`PlBg3pY5H=O_8Y7$!dB|9e?uJJ(Ul6sYwX`aGyWF zT9vJ`skx}cggdgOsm_G8tGUOd*{`WhS%|S;Sa8~O!LB)h#<6pj$}ciDiH+4#1UZS7 z3)M-rlsd`(UVb3NN$K}YW&)j5&{R+dbWw9li3w|GQ>#f+Rem?nMSa48Q>O`b&IY<@ z_7eGp2p2&DiH(5+2$_I^#QES$t&-)`7a~kx_sXHVR|e?bl+1Y?3Z76 zFaPx|eEdGjIcyu>zHGJ^0f5C}Up6PhTWcI2rhXlFT6K z1*x_7E#^M4tOZMR8i72<#lQ>I%?p%%WYRm$a$?e{T@V#$QKf?H^#YyqC4Xx#i)`G! zZ~b&C9mf_x>x6`U3yn zX>QH#e?;vY6FI=yF#t6!g&_y%e9`)n+&1 z9`mIaAxd-nbR$=WCe==`zs3LEbLpB)hq)IlzV}``7W+|svd5Krle$JFtZ~;&wJ5-q v^Zh4H3KWy~nBguzbvnPuyan^;&zbJIbh)or#`HDI66B-hA&GL3l}OeA3tjJt literal 0 HcmV?d00001 diff --git a/img/smileys/hum.gif b/img/smileys/hum.gif index c7e8bebb6187d5fe44928475388f128ed56e245c..db24401b988b99675ea42267a2ac19003a8e33b7 100644 GIT binary patch delta 103 zcmb=fiFEgLv#?C$XAomp$jkr)Teoig|DT~&T3YcZ3nK#qGlLFD6eQ2U zhD*kEYJYBwe?E2gjg}OSEx9L{4%+P3>AgOG&hv&t*%w\ return '\ -
\
\

\ \ \ \ + \ \

\
\ @@ -41,8 +40,10 @@ PageMinichat.prototype.charger = function() this.util.setCaretToEnd(jQuery("form input.message")[0]) + // + jQuery("body").append("
") // affichage des smiles - jQuery("#smiles").html(this.formateur.getSmilesHTML()).children().each( + jQuery("#smiles").append(this.formateur.getSmilesHTML()).children().each( function(i) { var opacityBase = jQuery(this).css("opacity") @@ -72,12 +73,28 @@ PageMinichat.prototype.charger = function() ) } ) + jQuery("form button.smiles").hover( + function(e) + { + var offset = jQuery(e.target).offset() + jQuery("#smiles").css("top", offset.top).css("left", offset.left).show() + }, + function(e){} + ) + jQuery("#smiles").hover( + function(){}, + function(e) + { + jQuery("#smiles").hide() + } + ) + //
- /// événements - jQuery("form button.return").click( + // événements + var nouveauMessage = function() - { - // captcha anti bot + { + // captcha anti bot if (jQuery("form input.captcha").val() != "") return thisPage.envoyerMessage( @@ -87,9 +104,19 @@ PageMinichat.prototype.charger = function() jQuery("form input.message")[0].focus() } + + jQuery("form input.message").keypress( + function(e) + { + if (e.which == 13) // return + nouveauMessage() + } ) + + jQuery("form button.return").click(nouveauMessage) + // interdiction de submiter le formulaire - jQuery("form").submit(function(){return false}) + jQuery("form").submit(function(){ return false}) jQuery("input.pseudo").click( function() -- 2.45.1 From a67d59e51fcca70497d1132327e14975be9383f3 Mon Sep 17 00:00:00 2001 From: Greg Burri Date: Sun, 4 May 2008 20:55:26 +0000 Subject: [PATCH 16/16] FIX petit bug concernant l'affichage des smiles --- css/1/pageMinichat.css | 2 +- js/pageMinichat.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/css/1/pageMinichat.css b/css/1/pageMinichat.css index 208584b..fac422e 100755 --- a/css/1/pageMinichat.css +++ b/css/1/pageMinichat.css @@ -10,7 +10,7 @@ border-style: solid; margin-bottom: 10px; padding: 1px; - width: 100px; + width: 140px; background-color: #0c2003; position: absolute; display: none diff --git a/js/pageMinichat.js b/js/pageMinichat.js index 9a88dce..c118c54 100755 --- a/js/pageMinichat.js +++ b/js/pageMinichat.js @@ -105,7 +105,7 @@ PageMinichat.prototype.charger = function() jQuery("form input.message")[0].focus() } - jQuery("form input.message").keypress( + jQuery("form").keypress( function(e) { if (e.which == 13) // return @@ -132,6 +132,8 @@ PageMinichat.prototype.decharger = function() { //alert(this.attenteCourante) this.messages.stopAttenteCourante() + + jQuery("body #smiles").remove() } PageMinichat.prototype.getJSONMessage = function(pseudo, message, repondA) -- 2.45.1