diff options
23 files changed, 7685 insertions, 1135 deletions
diff --git a/etc/basepage.html.dist b/etc/basepage.html.dist index cd3164a..45e8f30 100644 --- a/etc/basepage.html.dist +++ b/etc/basepage.html.dist @@ -40,49 +40,14 @@ a.menulink { a.menulink:hover { color: #e0e0ff; } - -.selectableitem { - border:2px solid #FFFFFF; - float:left; - height:140px; - margin:10px; - padding:10px; - text-align:center; - width:160px; -} - -.selectableitem p { - font-weight:bold; -} - -.selectableitem div { - height:120px; - line-height:120px; -} - -.selecteditem { - border:2px solid #999999; -} - -.selecthelper { - background-color:#000000; - opacity:0.3; -} - -.zoom { - height:330px; - overflow:auto; - width:700px; -} - --> </STYLE> -<script type="text/javascript" src="js/jquery.js"></script> -<script type="text/javascript" src="js/jquery.dimensions.js"></script> -<script type="text/javascript" src="js/iutil.js"></script> -<script type="text/javascript" src="js/smokeping_iselect.js"></script> -<script type="text/javascript" src="js/smokeping_zoom.js"></script> +<script src="cropper/lib/prototype.js" type="text/javascript"></script> +<script src="cropper/lib/scriptaculous.js?load=builder,dragdrop" type="text/javascript"></script> +<script src="cropper/cropper.js" type="text/javascript"></script> +<script src="cropper/smokeping_cropper.js" type="text/javascript"></script> + </HEAD> diff --git a/etc/config.dist b/etc/config.dist index bf10e17..6e53e10 100644 --- a/etc/config.dist +++ b/etc/config.dist @@ -1,20 +1,16 @@ -# Note that all IP addresses in this file are false, to prevent some -# machine falling under a deadly DOS storm because all users keep -# the same addresses in their config. - *** General *** -owner = Joe Random -contact = joe@some.place.xyz -mailhost = smtp.mailhost.abc +owner = Tobi Oetiker +contact = tobi@oetiker.ch +mailhost = johan.oetiker.ch sendmail = /usr/lib/sendmail -imgcache = /home/oetiker/public_html/.simg -imgurl = ../.simg -datadir = /tmp/smokeping/data -piddir = /tmp/smokeping/var -cgiurl = http://tobi.oetiker.ch/smokeping/smokeping.cgi -smokemail = /home/oetiker/checkouts/smokeping/trunk/software/etc/smokemail.dist -tmail = /home/oetiker/checkouts/smokeping/trunk/software/etc/tmail.dist +imgcache = /home/oetiker/public_html/smokeping-ms/cache +imgurl = cache +datadir = /tmp/smokeping-ms/data +piddir = /tmp/smokeping-ms/var +cgiurl = http://johan.oetiker.ch/~oetiker/smokeping-ms/smokeping.cgi +smokemail = /scratch/oetiker/smoke-master/etc/smokemail.dist +tmail = /scratch/oetiker/smoke-master/etc/tmail.dist # specify this to get syslog logging syslogfacility = local0 # each probe is now run in its own process @@ -22,39 +18,15 @@ syslogfacility = local0 # concurrentprobes = no *** Alerts *** -to = admin@company.xy +to = tobi@oetiker.ch from = smokealert@company.xy -+bigloss -type = loss -# in percent -pattern = ==0%,==0%,==0%,==0%,>0%,>0%,>0% -comment = suddenly there is packet loss - +someloss type = loss # in percent pattern = >0%,*12*,>0%,*12*,>0% comment = loss 3 times in a row -+startloss -type = loss -# in percent -pattern = ==S,>0%,>0%,>0% -comment = loss at startup - -+rttdetect -type = rtt -# in milli seconds -pattern = <10,<10,<10,<10,<10,<100,>100,>100,>100 -comment = routing mesed up again ? - -+median -type = matcher -# in milli seconds -pattern = Median(old=>5,new=>7,diff=>2) -comment = median crossed - *** Database *** step = 300 @@ -72,7 +44,36 @@ AVERAGE 0.5 144 720 *** Presentation *** -template = /home/oetiker/checkouts/smokeping/trunk/software/etc/basepage.html.dist +template = /scratch/oetiker/smoke-master/etc/basepage.html.dist + ++ charts + +menu = Charts +title = The most interesting destinations + +++ stddev +sorter = StdDev(entries=>4) +title = Top Standard Deviation +menu = Std Deviation +format = Stdandard Deviation %f + +++ max +sorter = Max(entries=>5) +title = Top Max Roundtrip Time +menu = by Max +format = Max Roundtrip Time %f seconds + +++ loss +sorter = Loss(entries=>5) +title = Top Packet Loss +menu = Loss +format = Packets Lost %f + +++ median +sorter = Median(entries=>5) +title = Top Median Roundtrip Time +menu = by Median +format = Median RTT %f seconds + overview @@ -98,11 +99,10 @@ unison_tolerance = 2 binary = /usr/sbin/fping *** Slaves *** -secrets=/home/oetiker/checkouts/smokeping/trunk/software/etc/smokeping_secrets.dist -+mipsrv01 -name=mipsrv01 -++override -Probes.FPing.binary=/usr/bin/fping +secrets=/scratch/oetiker/smoke-master/etc/smokeping_secrets.dist ++boomer +display_name=boomer +color=0000ff *** Targets *** @@ -113,80 +113,10 @@ title = Network Latency Grapher remark = Welcome to the SmokePing website of xxx Company. \ Here you will learn all about the latency of our network. -+ World - -menu = World -title = Worldwide Connectivity - -++ Europe - -menu = Europe -title =European Connectivity - -+++ Switzerland - -menu = Switzerland -title =Swiss Connectivity -alerts = bigloss,someloss,startloss -slaves = mipsrv01 johan - -++++ SBB - -menu = SBB/CFF/FFS -title =Swiss Federal Railways Webserver -host = www.railway-server.abc - - -++++ Tiscali - -menu = Tiscali Web -title = Tiscali Webserver www.tiscali.abc -host = www.tiscali-web.abc - -+++ UK - -menu = United Kingdom -title = United Kingdom - -++++ UCL - -menu = UCL -title = UCL -host = www.ucl-abc.acc.uk - -++ USA - -menu = North America -title =North American Connectivity - -+++ MIT - -menu = MIT -title = Massachusetts Institute of Technology Webserver -host = www.gurkoman.ybc - -+++ IU - -menu = IU -title = Indiana University -host = www.iu.ali - -+++ UCB - -menu = U. C. Berkeley -title = U. C. Berkeley Webserver -host = www.berkly.udi -alerts = median - -+++ UCSD - -menu = U. C. San Diego -title = U. C. San Diego Webserver -host = www.ucsdddar.art - -+++ Sun - -menu = Sun Microsystems -title = Sun Microsystems Webserver -host = www.sun-web.com ++ James +menu = Test Target +title =Test Target +alerts = someloss +slaves = boomer +host = james.oetiker.ch diff --git a/etc/smokeping_secrets.dist b/etc/smokeping_secrets.dist index d44aef1..590c41d 100644 --- a/etc/smokeping_secrets.dist +++ b/etc/smokeping_secrets.dist @@ -1,2 +1,3 @@ host1:mysercert host2:yoursercert +boomer:lkasdf93uhhfdfddf diff --git a/htdocs/cropper/cropper.css b/htdocs/cropper/cropper.css new file mode 100644 index 0000000..c2e7598 --- /dev/null +++ b/htdocs/cropper/cropper.css @@ -0,0 +1,182 @@ +.imgCrop_wrap {
+ /* width: 500px; @done_in_js */
+ /* height: 375px; @done_in_js */
+ position: relative;
+ cursor: crosshair;
+}
+
+/* an extra classname is applied for Opera < 9.0 to fix it's lack of opacity support */
+.imgCrop_wrap.opera8 .imgCrop_overlay,
+.imgCrop_wrap.opera8 .imgCrop_clickArea {
+ background-color: transparent;
+}
+
+/* fix for IE displaying all boxes at line-height by default, although they are still 1 pixel high until we combine them with the pointless span */
+.imgCrop_wrap,
+.imgCrop_wrap * {
+ font-size: 0;
+}
+
+.imgCrop_overlay {
+ background-color: #000;
+ opacity: 0.5;
+ filter:alpha(opacity=50);
+ position: absolute;
+ width: 100%;
+ height: 100%;
+}
+
+.imgCrop_selArea {
+ position: absolute;
+ /* @done_in_js
+ top: 20px;
+ left: 20px;
+ width: 200px;
+ height: 200px;
+ background: transparent url(castle.jpg) no-repeat -210px -110px;
+ */
+ cursor: move;
+ z-index: 2;
+}
+
+/* clickArea is all a fix for IE 5.5 & 6 to allow the user to click on the given area */
+.imgCrop_clickArea {
+ width: 100%;
+ height: 100%;
+ background-color: #FFF;
+ opacity: 0.01;
+ filter:alpha(opacity=01);
+}
+
+.imgCrop_marqueeHoriz {
+ position: absolute;
+ width: 100%;
+ height: 1px;
+ background: transparent url(marqueeHoriz.gif) repeat-x 0 0;
+ z-index: 3;
+}
+
+.imgCrop_marqueeVert {
+ position: absolute;
+ height: 100%;
+ width: 1px;
+ background: transparent url(marqueeVert.gif) repeat-y 0 0;
+ z-index: 3;
+}
+
+/*
+ * FIX MARCHING ANTS IN IE
+ * As IE <6 tries to load background images we can uncomment the follwoing hack
+ * to remove that issue, not as pretty - but is anything in IE?
+ * And yes I do know that 'filter' is evil, but it will make it look semi decent in IE
+ *
+* html .imgCrop_marqueeHoriz,
+* html .imgCrop_marqueeVert {
+ background: transparent;
+ filter: Invert;
+}
+* html .imgCrop_marqueeNorth { border-top: 1px dashed #000; }
+* html .imgCrop_marqueeEast { border-right: 1px dashed #000; }
+* html .imgCrop_marqueeSouth { border-bottom: 1px dashed #000; }
+* html .imgCrop_marqueeWest { border-left: 1px dashed #000; }
+*/
+
+.imgCrop_marqueeNorth { top: 0; left: 0; }
+.imgCrop_marqueeEast { top: 0; right: 0; }
+.imgCrop_marqueeSouth { bottom: 0px; left: 0; }
+.imgCrop_marqueeWest { top: 0; left: 0; }
+
+
+.imgCrop_handle {
+ position: absolute;
+ border: 1px solid #333;
+ width: 6px;
+ height: 6px;
+ background: #FFF;
+ opacity: 0.5;
+ filter:alpha(opacity=50);
+ z-index: 4;
+}
+
+/* fix IE 5 box model */
+* html .imgCrop_handle {
+ width: 8px;
+ height: 8px;
+ wid\th: 6px;
+ hei\ght: 6px;
+}
+
+.imgCrop_handleN {
+ top: -3px;
+ left: 0;
+ /* margin-left: 49%; @done_in_js */
+ cursor: n-resize;
+}
+
+.imgCrop_handleNE {
+ top: -3px;
+ right: -3px;
+ cursor: ne-resize;
+}
+
+.imgCrop_handleE {
+ top: 0;
+ right: -3px;
+ /* margin-top: 49%; @done_in_js */
+ cursor: e-resize;
+}
+
+.imgCrop_handleSE {
+ right: -3px;
+ bottom: -3px;
+ cursor: se-resize;
+}
+
+.imgCrop_handleS {
+ right: 0;
+ bottom: -3px;
+ /* margin-right: 49%; @done_in_js */
+ cursor: s-resize;
+}
+
+.imgCrop_handleSW {
+ left: -3px;
+ bottom: -3px;
+ cursor: sw-resize;
+}
+
+.imgCrop_handleW {
+ top: 0;
+ left: -3px;
+ /* margin-top: 49%; @done_in_js */
+ cursor: w-resize;
+}
+
+.imgCrop_handleNW {
+ top: -3px;
+ left: -3px;
+ cursor: nw-resize;
+}
+
+/**
+ * Create an area to click & drag around on as the default browser behaviour is to let you drag the image
+ */
+.imgCrop_dragArea {
+ width: 100%;
+ height: 100%;
+ z-index: 200;
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+
+.imgCrop_previewWrap {
+ /* width: 200px; @done_in_js */
+ /* height: 200px; @done_in_js */
+ overflow: hidden;
+ position: relative;
+}
+
+.imgCrop_previewWrap img {
+ position: absolute;
+}
\ No newline at end of file diff --git a/htdocs/cropper/cropper.js b/htdocs/cropper/cropper.js new file mode 100644 index 0000000..486a92a --- /dev/null +++ b/htdocs/cropper/cropper.js @@ -0,0 +1,566 @@ +/**
+ * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * See scriptaculous.js for full scriptaculous licence
+ */
+
+var CropDraggable=Class.create(); +Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){ +this.options=Object.extend({drawMethod:function(){ +}},arguments[1]||{}); +this.element=$(_1); +this.handle=this.element; +this.delta=this.currentDelta(); +this.dragging=false; +this.eventMouseDown=this.initDrag.bindAsEventListener(this); +Event.observe(this.handle,"mousedown",this.eventMouseDown); +Draggables.register(this); +},draw:function(_2){ +var _3=Position.cumulativeOffset(this.element); +var d=this.currentDelta(); +_3[0]-=d[0]; +_3[1]-=d[1]; +var p=[0,1].map(function(i){ +return (_2[i]-_3[i]-this.offset[i]); +}.bind(this)); +this.options.drawMethod(p); +}}); +var Cropper={}; +Cropper.Img=Class.create(); +Cropper.Img.prototype={initialize:function(_7,_8){ +this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{}); +this.img=$(_7); +this.clickCoords={x:0,y:0}; +this.dragging=false; +this.resizing=false; +this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent); +this.isIE=/MSIE/.test(navigator.userAgent); +this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent); +this.ratioX=0; +this.ratioY=0; +this.attached=false; +this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth)); +this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight)); +if(typeof this.img=="undefined"){ +return; +} +$A(document.getElementsByTagName("script")).each(function(s){ +if(s.src.match(/cropper\.js/)){ +var _a=s.src.replace(/cropper\.js(.*)?/,""); +var _b=document.createElement("link"); +_b.rel="stylesheet"; +_b.type="text/css"; +_b.href=_a+"cropper.css"; +_b.media="screen"; +document.getElementsByTagName("head")[0].appendChild(_b); +} +}); +if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){ +var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y); +this.ratioX=this.options.ratioDim.x/_c; +this.ratioY=this.options.ratioDim.y/_c; +} +this.subInitialize(); +if(this.img.complete||this.isWebKit){ +this.onLoad(); +}else{ +Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this)); +} +},getGCD:function(a,b){ +if(b==0){ +return a; +} +return this.getGCD(b,a%b); +},onLoad:function(){ +var _f="imgCrop_"; +var _10=this.img.parentNode; +var _11=""; +if(this.isOpera8){ +_11=" opera8"; +} +this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11}); +this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]); +this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]); +this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]); +this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]); +var _12=[this.north,this.east,this.south,this.west]; +this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12); +this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"}); +this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"}); +this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"}); +this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"}); +this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"}); +this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"}); +this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"}); +this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"}); +this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]); +this.imgWrap.appendChild(this.img); +this.imgWrap.appendChild(this.dragArea); +this.dragArea.appendChild(this.selArea); +this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"})); +_10.appendChild(this.imgWrap); +this.startDragBind=this.startDrag.bindAsEventListener(this); +Event.observe(this.dragArea,"mousedown",this.startDragBind); +this.onDragBind=this.onDrag.bindAsEventListener(this); +Event.observe(document,"mousemove",this.onDragBind); +this.endCropBind=this.endCrop.bindAsEventListener(this); +Event.observe(document,"mouseup",this.endCropBind); +this.resizeBind=this.startResize.bindAsEventListener(this); +this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW]; +this.registerHandles(true); +if(this.options.captureKeys){ +this.keysBind=this.handleKeys.bindAsEventListener(this); +Event.observe(document,"keypress",this.keysBind); +} +new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)}); +this.setParams(); +},registerHandles:function(_13){ +for(var i=0;i<this.handles.length;i++){ +var _15=$(this.handles[i]); +if(_13){ +var _16=false; +if(this.fixedWidth&&this.fixedHeight){ +_16=true; +}else{ +if(this.fixedWidth||this.fixedHeight){ +var _17=_15.className.match(/([S|N][E|W])$/); +var _18=_15.className.match(/(E|W)$/); +var _19=_15.className.match(/(N|S)$/); +if(_17){ +_16=true; +}else{ +if(this.fixedWidth&&_18){ +_16=true; +}else{ +if(this.fixedHeight&&_19){ +_16=true; +} +} +} +} +} +if(_16){ +_15.hide(); +}else{ +Event.observe(_15,"mousedown",this.resizeBind); +} +}else{ +_15.show(); +Event.stopObserving(_15,"mousedown",this.resizeBind); +} +} +},setParams:function(){ +this.imgW=this.img.width; +this.imgH=this.img.height; +$(this.north).setStyle({height:0}); +$(this.east).setStyle({width:0,height:0}); +$(this.south).setStyle({height:0}); +$(this.west).setStyle({width:0,height:0}); +$(this.imgWrap).setStyle({"width":this.imgW+"px","height":this.imgH+"px"}); +$(this.selArea).hide(); +var _1a={x1:0,y1:0,x2:0,y2:0}; +var _1b=false; +if(this.options.onloadCoords!=null){ +_1a=this.cloneCoords(this.options.onloadCoords); +_1b=true; +}else{ +if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){ +_1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2); +_1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2); +_1a.x2=_1a.x1+this.options.ratioDim.x; +_1a.y2=_1a.y1+this.options.ratioDim.y; +_1b=true; +} +} +this.setAreaCoords(_1a,false,false,1); +if(this.options.displayOnInit&&_1b){ +this.selArea.show(); +this.drawArea(); +this.endCrop(); +} +this.attached=true; +},remove:function(){ +if(this.attached){ +this.attached=false; +this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap); +this.imgWrap.parentNode.removeChild(this.imgWrap); +Event.stopObserving(this.dragArea,"mousedown",this.startDragBind); +Event.stopObserving(document,"mousemove",this.onDragBind); +Event.stopObserving(document,"mouseup",this.endCropBind); +this.registerHandles(false); +if(this.options.captureKeys){ +Event.stopObserving(document,"keypress",this.keysBind); +} +} +},reset:function(){ +if(!this.attached){ +this.onLoad(); +}else{ +this.setParams(); +} +this.endCrop(); +},handleKeys:function(e){ +var dir={x:0,y:0}; +if(!this.dragging){ +switch(e.keyCode){ +case (37): +dir.x=-1; +break; +case (38): +dir.y=-1; +break; +case (39): +dir.x=1; +break; +case (40): +dir.y=1; +break; +} +if(dir.x!=0||dir.y!=0){ +if(e.shiftKey){ +dir.x*=10; +dir.y*=10; +} +this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]); +Event.stop(e); +} +} +},calcW:function(){ +return (this.areaCoords.x2-this.areaCoords.x1); +},calcH:function(){ +return (this.areaCoords.y2-this.areaCoords.y1); +},moveArea:function(_1e){ +this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false); +this.drawArea(); +},cloneCoords:function(_1f){ +return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2}; +},setAreaCoords:function(_20,_21,_22,_23,_24){ +if(_21){ +var _25=_20.x2-_20.x1; +var _26=_20.y2-_20.y1; +if(_20.x1<0){ +_20.x1=0; +_20.x2=_25; +} +if(_20.y1<0){ +_20.y1=0; +_20.y2=_26; +} +if(_20.x2>this.imgW){ +_20.x2=this.imgW; +_20.x1=this.imgW-_25; +} +if(_20.y2>this.imgH){ +_20.y2=this.imgH; +_20.y1=this.imgH-_26; +} +}else{ +if(_20.x1<0){ +_20.x1=0; +} +if(_20.y1<0){ +_20.y1=0; +} +if(_20.x2>this.imgW){ +_20.x2=this.imgW; +} +if(_20.y2>this.imgH){ +_20.y2=this.imgH; +} +if(_23!=null){ +if(this.ratioX>0){ +this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24); +}else{ +if(_22){ +this.applyRatio(_20,{x:1,y:1},_23,_24); +} +} +var _27=[this.options.minWidth,this.options.minHeight]; +var _28=[this.options.maxWidth,this.options.maxHeight]; +if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){ +var _29={a1:_20.x1,a2:_20.x2}; +var _2a={a1:_20.y1,a2:_20.y2}; +var _2b={min:0,max:this.imgW}; +var _2c={min:0,max:this.imgH}; +if((_27[0]!=0||_27[1]!=0)&&_22){ +if(_27[0]>0){ +_27[1]=_27[0]; +}else{ +if(_27[1]>0){ +_27[0]=_27[1]; +} +} +} +if((_28[0]!=0||_28[0]!=0)&&_22){ +if(_28[0]>0&&_28[0]<=_28[1]){ +_28[1]=_28[0]; +}else{ +if(_28[1]>0&&_28[1]<=_28[0]){ +_28[0]=_28[1]; +} +} +} +if(_27[0]>0){ +this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min"); +} +if(_27[1]>1){ +this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min"); +} +if(_28[0]>0){ +this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max"); +} +if(_28[1]>1){ +this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max"); +} +_20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2}; +} +} +} +this.areaCoords=_20; +},applyDimRestriction:function(_2d,val,_2f,_30,_31){ +var _32; +if(_31=="min"){ +_32=((_2d.a2-_2d.a1)<val); +}else{ +_32=((_2d.a2-_2d.a1)>val); +} +if(_32){ +if(_2f==1){ +_2d.a2=_2d.a1+val; +}else{ +_2d.a1=_2d.a2-val; +} +if(_2d.a1<_30.min){ +_2d.a1=_30.min; +_2d.a2=val; +}else{ +if(_2d.a2>_30.max){ +_2d.a1=_30.max-val; +_2d.a2=_30.max; +} +} +} +},applyRatio:function(_33,_34,_35,_36){ +var _37; +if(_36=="N"||_36=="S"){ +_37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW}); +_33.x1=_37.b1; +_33.y1=_37.a1; +_33.x2=_37.b2; +_33.y2=_37.a2; +}else{ +_37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH}); +_33.x1=_37.a1; +_33.y1=_37.b1; +_33.x2=_37.a2; +_33.y2=_37.b2; +} +},applyRatioToAxis:function(_38,_39,_3a,_3b){ +var _3c=Object.extend(_38,{}); +var _3d=_3c.a2-_3c.a1; +var _3e=Math.floor(_3d*_39.b/_39.a); +var _3f; +var _40; +var _41=null; +if(_3a.b==1){ +_3f=_3c.b1+_3e; +if(_3f>_3b.max){ +_3f=_3b.max; +_41=_3f-_3c.b1; +} +_3c.b2=_3f; +}else{ +_3f=_3c.b2-_3e; +if(_3f<_3b.min){ +_3f=_3b.min; +_41=_3f+_3c.b2; +} +_3c.b1=_3f; +} +if(_41!=null){ +_40=Math.floor(_41*_39.a/_39.b); +if(_3a.a==1){ +_3c.a2=_3c.a1+_40; +}else{ +_3c.a1=_3c.a1=_3c.a2-_40; +} +} +return _3c; +},drawArea:function(){ +var _42=this.calcW(); +var _43=this.calcH(); +var px="px"; +var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px]; +var _46=this.selArea.style; +_46.left=_45[0]; +_46.top=_45[1]; +_46.width=_45[2]; +_46.height=_45[3]; +var _47=Math.ceil((_42-6)/2)+px; +var _48=Math.ceil((_43-6)/2)+px; +this.handleN.style.left=_47; +this.handleE.style.top=_48; +this.handleS.style.left=_47; +this.handleW.style.top=_48; +this.north.style.height=_45[1]; +var _49=this.east.style; +_49.top=_45[1]; +_49.height=_45[3]; +_49.left=_45[4]; +_49.width=_45[6]; +var _4a=this.south.style; +_4a.top=_45[5]; +_4a.height=_45[7]; +var _4b=this.west.style; +_4b.top=_45[1]; +_4b.height=_45[3]; +_4b.width=_45[0]; +this.subDrawArea(); +this.forceReRender(); +},forceReRender:function(){ +if(this.isIE||this.isWebKit){ +var n=document.createTextNode(" "); +var d,el,fixEL,i; +if(this.isIE){ +fixEl=this.selArea; +}else{ +if(this.isWebKit){ +fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0]; +d=Builder.node("div",""); +d.style.visibility="hidden"; +var _4e=["SE","S","SW"]; +for(i=0;i<_4e.length;i++){ +el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0]; +if(el.childNodes.length){ +el.removeChild(el.childNodes[0]); +} +el.appendChild(d); +} +} +} +fixEl.appendChild(n); +fixEl.removeChild(n); +} +},startResize:function(e){ +this.startCoords=this.cloneCoords(this.areaCoords); +this.resizing=true; +this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,""); +Event.stop(e); +},startDrag:function(e){ +this.selArea.show(); +this.clickCoords=this.getCurPos(e); +this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null); +this.dragging=true; +this.onDrag(e); +Event.stop(e); +},getCurPos:function(e){ +var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el); +while(el.nodeName!="BODY"){ +wrapOffsets[1]-=el.scrollTop||0; +wrapOffsets[0]-=el.scrollLeft||0; +el=el.parentNode; +} +return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]}; +},onDrag:function(e){ +if(this.dragging||this.resizing){ +var _54=null; +var _55=this.getCurPos(e); +var _56=this.cloneCoords(this.areaCoords); +var _57={x:1,y:1}; +if(this.dragging){ +if(_55.x<this.clickCoords.x){ +_57.x=-1; +} +if(_55.y<this.clickCoords.y){ +_57.y=-1; +} +this.transformCoords(_55.x,this.clickCoords.x,_56,"x"); +this.transformCoords(_55.y,this.clickCoords.y,_56,"y"); +}else{ +if(this.resizing){ +_54=this.resizeHandle; +if(_54.match(/E/)){ +this.transformCoords(_55.x,this.startCoords.x1,_56,"x"); +if(_55.x<this.startCoords.x1){ +_57.x=-1; +} +}else{ +if(_54.match(/W/)){ +this.transformCoords(_55.x,this.startCoords.x2,_56,"x"); +if(_55.x<this.startCoords.x2){ +_57.x=-1; +} +} +} +if(_54.match(/N/)){ +this.transformCoords(_55.y,this.startCoords.y2,_56,"y"); +if(_55.y<this.startCoords.y2){ +_57.y=-1; +} +}else{ +if(_54.match(/S/)){ +this.transformCoords(_55.y,this.startCoords.y1,_56,"y"); +if(_55.y<this.startCoords.y1){ +_57.y=-1; +} +} +} +} +} +this.setAreaCoords(_56,false,e.shiftKey,_57,_54); +this.drawArea(); +Event.stop(e); +} +},transformCoords:function(_58,_59,_5a,_5b){ +var _5c=[_58,_59]; +if(_58>_59){ +_5c.reverse(); +} +_5a[_5b+"1"]=_5c[0]; +_5a[_5b+"2"]=_5c[1]; +},endCrop:function(){ +this.dragging=false; +this.resizing=false; +this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()}); +},subInitialize:function(){ +},subDrawArea:function(){ +}}; +Cropper.ImgWithPreview=Class.create(); +Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){ +this.hasPreviewImg=false; +if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){ +this.previewWrap=$(this.options.previewWrap); +this.previewImg=this.img.cloneNode(false); +this.previewImg.id="imgCrop_"+this.previewImg.id; +this.options.displayOnInit=true; +this.hasPreviewImg=true; +this.previewWrap.addClassName("imgCrop_previewWrap"); +this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"}); +this.previewWrap.appendChild(this.previewImg); +} +},subDrawArea:function(){ +if(this.hasPreviewImg){ +var _5d=this.calcW(); +var _5e=this.calcH(); +var _5f={x:this.imgW/_5d,y:this.imgH/_5e}; +var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight}; +var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"}; +var _62=this.previewImg.style; +_62.width=_61.w; +_62.height=_61.h; +_62.left=_61.x; +_62.top=_61.y; +} +}}); +
diff --git a/htdocs/cropper/cropper.uncompressed.js b/htdocs/cropper/cropper.uncompressed.js new file mode 100644 index 0000000..6618554 --- /dev/null +++ b/htdocs/cropper/cropper.uncompressed.js @@ -0,0 +1,1331 @@ +/**
+ * Image Cropper (v. 1.2.0 - 2006-10-30 )
+ * Copyright (c) 2006 David Spurr (http://www.defusion.org.uk/)
+ *
+ * The image cropper provides a way to draw a crop area on an image and capture
+ * the coordinates of the drawn crop area.
+ *
+ * Features include:
+ * - Based on Prototype and Scriptaculous
+ * - Image editing package styling, the crop area functions and looks
+ * like those found in popular image editing software
+ * - Dynamic inclusion of required styles
+ * - Drag to draw areas
+ * - Shift drag to draw/resize areas as squares
+ * - Selection area can be moved
+ * - Seleciton area can be resized using resize handles
+ * - Allows dimension ratio limited crop areas
+ * - Allows minimum dimension crop areas
+ * - Allows maximum dimesion crop areas
+ * - If both min & max dimension options set to the same value for a single axis,then the cropper will not
+ * display the resize handles as appropriate (when min & max dimensions are passed for both axes this
+ * results in a 'fixed size' crop area)
+ * - Allows dynamic preview of resultant crop ( if minimum width & height are provided ), this is
+ * implemented as a subclass so can be excluded when not required
+ * - Movement of selection area by arrow keys ( shift + arrow key will move selection area by
+ * 10 pixels )
+ * - All operations stay within bounds of image
+ * - All functionality & display compatible with most popular browsers supported by Prototype:
+ * PC: IE 7, 6 & 5.5, Firefox 1.5, Opera 8.5 (see known issues) & 9.0b
+ * MAC: Camino 1.0, Firefox 1.5, Safari 2.0
+ *
+ * Requires:
+ * - Prototype v. 1.5.0_rc0 > (as packaged with Scriptaculous 1.6.1)
+ * - Scriptaculous v. 1.6.1 > modules: builder, dragdrop
+ *
+ * Known issues:
+ * - Safari animated gifs, only one of each will animate, this seems to be a known Safari issue
+ *
+ * - After drawing an area and then clicking to start a new drag in IE 5.5 the rendered height
+ * appears as the last height until the user drags, this appears to be the related to the error
+ * that the forceReRender() method fixes for IE 6, i.e. IE 5.5 is not redrawing the box properly.
+ *
+ * - Lack of CSS opacity support in Opera before version 9 mean we disable those style rules, these
+ * could be fixed by using PNGs with transparency if Opera 8.5 support is high priority for you
+ *
+ * - Marching ants keep reloading in IE <6 (not tested in IE7), it is a known issue in IE and I have
+ * found no viable workarounds that can be included in the release. If this really is an issue for you
+ * either try this post: http://mir.aculo.us/articles/2005/08/28/internet-explorer-and-ajax-image-caching-woes
+ * or uncomment the 'FIX MARCHING ANTS IN IE' rules in the CSS file
+ *
+ * - Styling & borders on image, any CSS styling applied directly to the image itself (floats, borders, padding, margin, etc.) will
+ * cause problems with the cropper. The use of a wrapper element to apply these styles to is recommended.
+ *
+ * - overflow: auto or overflow: scroll on parent will cause cropper to burst out of parent in IE and Opera (maybe Mac browsers too)
+ * I'm not sure why yet.
+ *
+ * Usage:
+ * See Cropper.Img & Cropper.ImgWithPreview for usage details
+ *
+ * Changelog:
+ * v1.2.0 - 2006-10-30
+ * + Added id to the preview image element using 'imgCrop_[originalImageID]'
+ * * #00001 - Fixed bug: Doesn't account for scroll offsets
+ * * #00009 - Fixed bug: Placing the cropper inside differently positioned elements causes incorrect co-ordinates and display
+ * * #00013 - Fixed bug: I-bar cursor appears on drag plane
+ * * #00014 - Fixed bug: If ID for image tag is not found in document script throws error
+ * * Fixed bug with drag start co-ordinates if wrapper element has moved in browser (e.g. dragged to a new position)
+ * * Fixed bug with drag start co-ordinates if image contained in a wrapper with scrolling - this may be buggy if image
+ * has other ancestors with scrolling applied (except the body)
+ * * #00015 - Fixed bug: When cropper removed and then reapplied onEndCrop callback gets called multiple times, solution suggestion from Bill Smith
+ * * Various speed increases & code cleanup which meant improved performance in Mac - which allowed removal of different overlay methods for
+ * IE and all other browsers, which led to a fix for:
+ * * #00010 - Fixed bug: Select area doesn't adhere to image size when image resized using img attributes
+ * - #00006 - Removed default behaviour of automatically setting a ratio when both min width & height passed, the ratioDimensions must be passed in
+ * + #00005 - Added ability to set maximum crop dimensions, if both min & max set as the same value then we'll get a fixed cropper size on the axes as appropriate
+ * and the resize handles will not be displayed as appropriate
+ * * Switched keydown for keypress for moving select area with cursor keys (makes for nicer action) - doesn't appear to work in Safari
+ *
+ * v1.1.3 - 2006-08-21
+ * * Fixed wrong cursor on western handle in CSS
+ * + #00008 & #00003 - Added feature: Allow to set dimensions & position for cropper on load
+ * * #00002 - Fixed bug: Pressing 'remove cropper' twice removes image in IE
+ *
+ * v1.1.2 - 2006-06-09
+ * * Fixed bugs with ratios when GCD is low (patch submitted by Andy Skelton)
+ *
+ * v1.1.1 - 2006-06-03
+ * * Fixed bug with rendering issues fix in IE 5.5
+ * * Fixed bug with endCrop callback issues once cropper had been removed & reset in IE
+ *
+ * v1.1.0 - 2006-06-02
+ * * Fixed bug with IE constantly trying to reload select area background image
+ * * Applied more robust fix to Safari & IE rendering issues
+ * + Added method to reset parameters - useful for when dynamically changing img cropper attached to
+ * + Added method to remove cropper from image
+ *
+ * v1.0.0 - 2006-05-18
+ * + Initial verison
+ *
+ *
+ * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/)
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * See scriptaculous.js for full scriptaculous licence
+ */
+
+/**
+ * Extend the Draggable class to allow us to pass the rendering
+ * down to the Cropper object.
+ */
+var CropDraggable = Class.create();
+
+Object.extend( Object.extend( CropDraggable.prototype, Draggable.prototype), {
+
+ initialize: function(element) {
+ this.options = Object.extend(
+ {
+ /**
+ * The draw method to defer drawing to
+ */
+ drawMethod: function() {}
+ },
+ arguments[1] || {}
+ );
+
+ this.element = $(element);
+
+ this.handle = this.element;
+
+ this.delta = this.currentDelta();
+ this.dragging = false;
+
+ this.eventMouseDown = this.initDrag.bindAsEventListener(this);
+ Event.observe(this.handle, "mousedown", this.eventMouseDown);
+
+ Draggables.register(this);
+ },
+
+ /**
+ * Defers the drawing of the draggable to the supplied method
+ */
+ draw: function(point) {
+ var pos = Position.cumulativeOffset(this.element);
+ var d = this.currentDelta();
+ pos[0] -= d[0];
+ pos[1] -= d[1];
+
+ var p = [0,1].map(function(i) {
+ return (point[i]-pos[i]-this.offset[i])
+ }.bind(this));
+
+ this.options.drawMethod( p );
+ }
+
+});
+
+
+/**
+ * The Cropper object, this will attach itself to the provided image by wrapping it with
+ * the generated xHTML structure required by the cropper.
+ *
+ * Usage:
+ * @param obj Image element to attach to
+ * @param obj Optional options:
+ * - ratioDim obj
+ * The pixel dimensions to apply as a restrictive ratio, with properties x & y
+ *
+ * - minWidth int
+ * The minimum width for the select area in pixels
+ *
+ * - minHeight int
+ * The mimimum height for the select area in pixels
+ *
+ * - maxWidth int
+ * The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed)
+ *
+ * - maxHeight int
+ * The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed)
+ *
+ * - displayOnInit int
+ * Whether to display the select area on initialisation, only used when providing minimum width & height or ratio
+ *
+ * - onEndCrop func
+ * The callback function to provide the crop details to on end of a crop (see below)
+ *
+ * - captureKeys boolean
+ * Whether to capture the keys for moving the select area, as these can cause some problems at the moment
+ *
+ * - onloadCoords obj
+ * A coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area to display onload
+ *
+ *----------------------------------------------
+ *
+ * The callback function provided via the onEndCrop option should accept the following parameters:
+ * - coords obj
+ * The coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area
+ *
+ * - dimensions obj
+ * The dimensions object with properites width & height; for the dimensions of the select area
+ *
+ *
+ * Example:
+ * function onEndCrop( coords, dimensions ) {
+ * $( 'x1' ).value = coords.x1;
+ * $( 'y1' ).value = coords.y1;
+ * $( 'x2' ).value = coords.x2;
+ * $( 'y2' ).value = coords.y2;
+ * $( 'width' ).value = dimensions.width;
+ * $( 'height' ).value = dimensions.height;
+ * }
+ *
+ */
+var Cropper = {};
+Cropper.Img = Class.create();
+Cropper.Img.prototype = {
+
+ /**
+ * Initialises the class
+ *
+ * @access public
+ * @param obj Image element to attach to
+ * @param obj Options
+ * @return void
+ */
+ initialize: function(element, options) {
+ this.options = Object.extend(
+ {
+ /**
+ * @var obj
+ * The pixel dimensions to apply as a restrictive ratio
+ */
+ ratioDim: { x: 0, y: 0 },
+ /**
+ * @var int
+ * The minimum pixel width, also used as restrictive ratio if min height passed too
+ */
+ minWidth: 0,
+ /**
+ * @var int
+ * The minimum pixel height, also used as restrictive ratio if min width passed too
+ */
+ minHeight: 0,
+ /**
+ * @var boolean
+ * Whether to display the select area on initialisation, only used when providing minimum width & height or ratio
+ */
+ displayOnInit: false,
+ /**
+ * @var function
+ * The call back function to pass the final values to
+ */
+ onEndCrop: Prototype.emptyFunction,
+ /**
+ * @var boolean
+ * Whether to capture key presses or not
+ */
+ captureKeys: true,
+ /**
+ * @var obj Coordinate object x1, y1, x2, y2
+ * The coordinates to optionally display the select area at onload
+ */
+ onloadCoords: null,
+ /**
+ * @var int
+ * The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed)
+ */
+ maxWidth: 0,
+ /**
+ * @var int
+ * The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed)
+ */
+ maxHeight: 0
+ },
+ options || {}
+ );
+ /**
+ * @var obj
+ * The img node to attach to
+ */
+ this.img = $( element );
+ /**
+ * @var obj
+ * The x & y coordinates of the click point
+ */
+ this.clickCoords = { x: 0, y: 0 };
+ /**
+ * @var boolean
+ * Whether the user is dragging
+ */
+ this.dragging = false;
+ /**
+ * @var boolean
+ * Whether the user is resizing
+ */
+ this.resizing = false;
+ /**
+ * @var boolean
+ * Whether the user is on a webKit browser
+ */
+ this.isWebKit = /Konqueror|Safari|KHTML/.test( navigator.userAgent );
+ /**
+ * @var boolean
+ * Whether the user is on IE
+ */
+ this.isIE = /MSIE/.test( navigator.userAgent );
+ /**
+ * @var boolean
+ * Whether the user is on Opera below version 9
+ */
+ this.isOpera8 = /Opera\s[1-8]/.test( navigator.userAgent );
+ /**
+ * @var int
+ * The x ratio
+ */
+ this.ratioX = 0;
+ /**
+ * @var int
+ * The y ratio
+ */
+ this.ratioY = 0;
+ /**
+ * @var boolean
+ * Whether we've attached sucessfully
+ */
+ this.attached = false;
+ /**
+ * @var boolean
+ * Whether we've got a fixed width (if minWidth EQ or GT maxWidth then we have a fixed width
+ * in the case of minWidth > maxWidth maxWidth wins as the fixed width)
+ */
+ this.fixedWidth = ( this.options.maxWidth > 0 && ( this.options.minWidth >= this.options.maxWidth ) );
+ /**
+ * @var boolean
+ * Whether we've got a fixed height (if minHeight EQ or GT maxHeight then we have a fixed height
+ * in the case of minHeight > maxHeight maxHeight wins as the fixed height)
+ */
+ this.fixedHeight = ( this.options.maxHeight > 0 && ( this.options.minHeight >= this.options.maxHeight ) );
+
+ // quit if the image element doesn't exist
+ if( typeof this.img == 'undefined' ) return;
+
+ // include the stylesheet
+ $A( document.getElementsByTagName( 'script' ) ).each(
+ function(s) {
+ if( s.src.match( /cropper\.js/ ) ) {
+ var path = s.src.replace( /cropper\.js(.*)?/, '' );
+ // '<link rel="stylesheet" type="text/css" href="' + path + 'cropper.css" media="screen" />';
+ var style = document.createElement( 'link' );
+ style.rel = 'stylesheet';
+ style.type = 'text/css';
+ style.href = path + 'cropper.css';
+ style.media = 'screen';
+ document.getElementsByTagName( 'head' )[0].appendChild( style );
+ }
+ }
+ );
+
+ // calculate the ratio when neccessary
+ if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) {
+ var gcd = this.getGCD( this.options.ratioDim.x, this.options.ratioDim.y );
+ this.ratioX = this.options.ratioDim.x / gcd;
+ this.ratioY = this.options.ratioDim.y / gcd;
+ // dump( 'RATIO : ' + this.ratioX + ':' + this.ratioY + '\n' );
+ }
+
+ // initialise sub classes
+ this.subInitialize();
+
+ // only load the event observers etc. once the image is loaded
+ // this is done after the subInitialize() call just in case the sub class does anything
+ // that will affect the result of the call to onLoad()
+ if( this.img.complete || this.isWebKit ) this.onLoad(); // for some reason Safari seems to support img.complete but returns 'undefined' on the this.img object
+ else Event.observe( this.img, 'load', this.onLoad.bindAsEventListener( this) );
+ },
+
+ /**
+ * The Euclidean algorithm used to find the greatest common divisor
+ *
+ * @acces private
+ * @param int Value 1
+ * @param int Value 2
+ * @return int
+ */
+ getGCD : function( a , b ) {
+ if( b == 0 ) return a;
+ return this.getGCD(b, a % b );
+ },
+
+ /**
+ * Attaches the cropper to the image once it has loaded
+ *
+ * @access private
+ * @return void
+ */
+ onLoad: function( ) {
+ /*
+ * Build the container and all related elements, will result in the following
+ *
+ * <div class="imgCrop_wrap">
+ * <img ... this.img ... />
+ * <div class="imgCrop_dragArea">
+ * <!-- the inner spans are only required for IE to stop it making the divs 1px high/wide -->
+ * <div class="imgCrop_overlay imageCrop_north"><span></span></div>
+ * <div class="imgCrop_overlay imageCrop_east"><span></span></div>
+ * <div class="imgCrop_overlay imageCrop_south"><span></span></div>
+ * <div class="imgCrop_overlay imageCrop_west"><span></span></div>
+ * <div class="imgCrop_selArea">
+ * <!-- marquees -->
+ * <!-- the inner spans are only required for IE to stop it making the divs 1px high/wide -->
+ * <div class="imgCrop_marqueeHoriz imgCrop_marqueeNorth"><span></span></div>
+ * <div class="imgCrop_marqueeVert imgCrop_marqueeEast"><span></span></div>
+ * <div class="imgCrop_marqueeHoriz imgCrop_marqueeSouth"><span></span></div>
+ * <div class="imgCrop_marqueeVert imgCrop_marqueeWest"><span></span></div>
+ * <!-- handles -->
+ * <div class="imgCrop_handle imgCrop_handleN"></div>
+ * <div class="imgCrop_handle imgCrop_handleNE"></div>
+ * <div class="imgCrop_handle imgCrop_handleE"></div>
+ * <div class="imgCrop_handle imgCrop_handleSE"></div>
+ * <div class="imgCrop_handle imgCrop_handleS"></div>
+ * <div class="imgCrop_handle imgCrop_handleSW"></div>
+ * <div class="imgCrop_handle imgCrop_handleW"></div>
+ * <div class="imgCrop_handle imgCrop_handleNW"></div>
+ * <div class="imgCrop_clickArea"></div>
+ * </div>
+ * <div class="imgCrop_clickArea"></div>
+ * </div>
+ * </div>
+ */
+ var cNamePrefix = 'imgCrop_';
+
+ // get the point to insert the container
+ var insertPoint = this.img.parentNode;
+
+ // apply an extra class to the wrapper to fix Opera below version 9
+ var fixOperaClass = '';
+ if( this.isOpera8 ) fixOperaClass = ' opera8';
+ this.imgWrap = Builder.node( 'div', { 'class': cNamePrefix + 'wrap' + fixOperaClass } );
+
+ this.north = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'north' }, [Builder.node( 'span' )] );
+ this.east = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'east' } , [Builder.node( 'span' )] );
+ this.south = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'south' }, [Builder.node( 'span' )] );
+ this.west = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'west' } , [Builder.node( 'span' )] );
+
+ var overlays = [ this.north, this.east, this.south, this.west ];
+
+ this.dragArea = Builder.node( 'div', { 'class': cNamePrefix + 'dragArea' }, overlays );
+
+ this.handleN = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleN' } );
+ this.handleNE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNE' } );
+ this.handleE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleE' } );
+ this.handleSE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSE' } );
+ this.handleS = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleS' } );
+ this.handleSW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSW' } );
+ this.handleW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleW' } );
+ this.handleNW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNW' } );
+
+ this.selArea = Builder.node( 'div', { 'class': cNamePrefix + 'selArea' },
+ [
+ Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeNorth' }, [Builder.node( 'span' )] ),
+ Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeEast' } , [Builder.node( 'span' )] ),
+ Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeSouth' }, [Builder.node( 'span' )] ),
+ Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeWest' } , [Builder.node( 'span' )] ),
+ this.handleN,
+ this.handleNE,
+ this.handleE,
+ this.handleSE,
+ this.handleS,
+ this.handleSW,
+ this.handleW,
+ this.handleNW,
+ Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } )
+ ]
+ );
+
+ this.imgWrap.appendChild( this.img );
+ this.imgWrap.appendChild( this.dragArea );
+ this.dragArea.appendChild( this.selArea );
+ this.dragArea.appendChild( Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } ) );
+
+ insertPoint.appendChild( this.imgWrap );
+
+ // add event observers
+ this.startDragBind = this.startDrag.bindAsEventListener( this );
+ Event.observe( this.dragArea, 'mousedown', this.startDragBind );
+
+ this.onDragBind = this.onDrag.bindAsEventListener( this );
+ Event.observe( document, 'mousemove', this.onDragBind );
+
+ this.endCropBind = this.endCrop.bindAsEventListener( this );
+ Event.observe( document, 'mouseup', this.endCropBind );
+
+ this.resizeBind = this.startResize.bindAsEventListener( this );
+ this.handles = [ this.handleN, this.handleNE, this.handleE, this.handleSE, this.handleS, this.handleSW, this.handleW, this.handleNW ];
+ this.registerHandles( true );
+
+ if( this.options.captureKeys ) {
+ this.keysBind = this.handleKeys.bindAsEventListener( this );
+ Event.observe( document, 'keypress', this.keysBind );
+ }
+
+ // attach the dragable to the select area
+ new CropDraggable( this.selArea, { drawMethod: this.moveArea.bindAsEventListener( this ) } );
+
+ this.setParams();
+ },
+
+ /**
+ * Manages adding or removing the handle event handler and hiding or displaying them as appropriate
+ *
+ * @access private
+ * @param boolean registration true = add, false = remove
+ * @return void
+ */
+ registerHandles: function( registration ) {
+ for( var i = 0; i < this.handles.length; i++ ) {
+ var handle = $( this.handles[i] );
+
+ if( registration ) {
+ var hideHandle = false; // whether to hide the handle
+
+ // disable handles asappropriate if we've got fixed dimensions
+ // if both dimensions are fixed we don't need to do much
+ if( this.fixedWidth && this.fixedHeight ) hideHandle = true;
+ else if( this.fixedWidth || this.fixedHeight ) {
+ // if one of the dimensions is fixed then just hide those handles
+ var isCornerHandle = handle.className.match( /([S|N][E|W])$/ )
+ var isWidthHandle = handle.className.match( /(E|W)$/ );
+ var isHeightHandle = handle.className.match( /(N|S)$/ );
+ if( isCornerHandle ) hideHandle = true;
+ else if( this.fixedWidth && isWidthHandle ) hideHandle = true;
+ else if( this.fixedHeight && isHeightHandle ) hideHandle = true;
+ }
+ if( hideHandle ) handle.hide();
+ else Event.observe( handle, 'mousedown', this.resizeBind );
+ } else {
+ handle.show();
+ Event.stopObserving( handle, 'mousedown', this.resizeBind );
+ }
+ }
+ },
+
+ /**
+ * Sets up all the cropper parameters, this can be used to reset the cropper when dynamically
+ * changing the images
+ *
+ * @access private
+ * @return void
+ */
+ setParams: function() {
+ /**
+ * @var int
+ * The image width
+ */
+ this.imgW = this.img.width;
+ /**
+ * @var int
+ * The image height
+ */
+ this.imgH = this.img.height;
+
+ $( this.north ).setStyle( { height: 0 } );
+ $( this.east ).setStyle( { width: 0, height: 0 } );
+ $( this.south ).setStyle( { height: 0 } );
+ $( this.west ).setStyle( { width: 0, height: 0 } );
+
+ // resize the container to fit the image
+ $( this.imgWrap ).setStyle( { 'width': this.imgW + 'px', 'height': this.imgH + 'px' } );
+
+ // hide the select area
+ $( this.selArea ).hide();
+
+ // setup the starting position of the select area
+ var startCoords = { x1: 0, y1: 0, x2: 0, y2: 0 };
+ var validCoordsSet = false;
+
+ // display the select area
+ if( this.options.onloadCoords != null ) {
+ // if we've being given some coordinates to
+ startCoords = this.cloneCoords( this.options.onloadCoords );
+ validCoordsSet = true;
+ } else if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) {
+ // if there is a ratio limit applied and the then set it to initial ratio
+ startCoords.x1 = Math.ceil( ( this.imgW - this.options.ratioDim.x ) / 2 );
+ startCoords.y1 = Math.ceil( ( this.imgH - this.options.ratioDim.y ) / 2 );
+ startCoords.x2 = startCoords.x1 + this.options.ratioDim.x;
+ startCoords.y2 = startCoords.y1 + this.options.ratioDim.y;
+ validCoordsSet = true;
+ }
+
+ this.setAreaCoords( startCoords, false, false, 1 );
+
+ if( this.options.displayOnInit && validCoordsSet ) {
+ this.selArea.show();
+ this.drawArea();
+ this.endCrop();
+ }
+
+ this.attached = true;
+ },
+
+ /**
+ * Removes the cropper
+ *
+ * @access public
+ * @return void
+ */
+ remove: function() {
+ if( this.attached ) {
+ this.attached = false;
+
+ // remove the elements we inserted
+ this.imgWrap.parentNode.insertBefore( this.img, this.imgWrap );
+ this.imgWrap.parentNode.removeChild( this.imgWrap );
+
+ // remove the event observers
+ Event.stopObserving( this.dragArea, 'mousedown', this.startDragBind );
+ Event.stopObserving( document, 'mousemove', this.onDragBind );
+ Event.stopObserving( document, 'mouseup', this.endCropBind );
+ this.registerHandles( false );
+ if( this.options.captureKeys ) Event.stopObserving( document, 'keypress', this.keysBind );
+ }
+ },
+
+ /**
+ * Resets the cropper, can be used either after being removed or any time you wish
+ *
+ * @access public
+ * @return void
+ */
+ reset: function() {
+ if( !this.attached ) this.onLoad();
+ else this.setParams();
+ this.endCrop();
+ },
+
+ /**
+ * Handles the key functionality, currently just using arrow keys to move, if the user
+ * presses shift then the area will move by 10 pixels
+ */
+ handleKeys: function( e ) {
+ var dir = { x: 0, y: 0 }; // direction to move it in & the amount in pixels
+ if( !this.dragging ) {
+
+ // catch the arrow keys
+ switch( e.keyCode ) {
+ case( 37 ) : // left
+ dir.x = -1;
+ break;
+ case( 38 ) : // up
+ dir.y = -1;
+ break;
+ case( 39 ) : // right
+ dir.x = 1;
+ break
+ case( 40 ) : // down
+ dir.y = 1;
+ break;
+ }
+
+ if( dir.x != 0 || dir.y != 0 ) {
+ // if shift is pressed then move by 10 pixels
+ if( e.shiftKey ) {
+ dir.x *= 10;
+ dir.y *= 10;
+ }
+
+ this.moveArea( [ this.areaCoords.x1 + dir.x, this.areaCoords.y1 + dir.y ] );
+ Event.stop( e );
+ }
+ }
+ },
+
+ /**
+ * Calculates the width from the areaCoords
+ *
+ * @access private
+ * @return int
+ */
+ calcW: function() {
+ return (this.areaCoords.x2 - this.areaCoords.x1)
+ },
+
+ /**
+ * Calculates the height from the areaCoords
+ *
+ * @access private
+ * @return int
+ */
+ calcH: function() {
+ return (this.areaCoords.y2 - this.areaCoords.y1)
+ },
+
+ /**
+ * Moves the select area to the supplied point (assumes the point is x1 & y1 of the select area)
+ *
+ * @access public
+ * @param array Point for x1 & y1 to move select area to
+ * @return void
+ */
+ moveArea: function( point ) {
+ // dump( 'moveArea : ' + point[0] + ',' + point[1] + ',' + ( point[0] + ( this.areaCoords.x2 - this.areaCoords.x1 ) ) + ',' + ( point[1] + ( this.areaCoords.y2 - this.areaCoords.y1 ) ) + '\n' );
+ this.setAreaCoords(
+ {
+ x1: point[0],
+ y1: point[1],
+ x2: point[0] + this.calcW(),
+ y2: point[1] + this.calcH()
+ },
+ true,
+ false
+ );
+ this.drawArea();
+ },
+
+ /**
+ * Clones a co-ordinates object, stops problems with handling them by reference
+ *
+ * @access private
+ * @param obj Coordinate object x1, y1, x2, y2
+ * @return obj Coordinate object x1, y1, x2, y2
+ */
+ cloneCoords: function( coords ) {
+ return { x1: coords.x1, y1: coords.y1, x2: coords.x2, y2: coords.y2 };
+ },
+
+ /**
+ * Sets the select coords to those provided but ensures they don't go
+ * outside the bounding box
+ *
+ * @access private
+ * @param obj Coordinates x1, y1, x2, y2
+ * @param boolean Whether this is a move
+ * @param boolean Whether to apply squaring
+ * @param obj Direction of mouse along both axis x, y ( -1 = negative, 1 = positive ) only required when moving etc.
+ * @param string The current resize handle || null
+ * @return void
+ */
+ setAreaCoords: function( coords, moving, square, direction, resizeHandle ) {
+ // dump( 'setAreaCoords (in) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 );
+ if( moving ) {
+ // if moving
+ var targW = coords.x2 - coords.x1;
+ var targH = coords.y2 - coords.y1;
+
+ // ensure we're within the bounds
+ if( coords.x1 < 0 ) {
+ coords.x1 = 0;
+ coords.x2 = targW;
+ }
+ if( coords.y1 < 0 ) {
+ coords.y1 = 0;
+ coords.y2 = targH;
+ }
+ if( coords.x2 > this.imgW ) {
+ coords.x2 = this.imgW;
+ coords.x1 = this.imgW - targW;
+ }
+ if( coords.y2 > this.imgH ) {
+ coords.y2 = this.imgH;
+ coords.y1 = this.imgH - targH;
+ }
+ } else {
+ // ensure we're within the bounds
+ if( coords.x1 < 0 ) coords.x1 = 0;
+ if( coords.y1 < 0 ) coords.y1 = 0;
+ if( coords.x2 > this.imgW ) coords.x2 = this.imgW;
+ if( coords.y2 > this.imgH ) coords.y2 = this.imgH;
+
+ // This is passed as null in onload
+ if( direction != null ) {
+
+ // apply the ratio or squaring where appropriate
+ if( this.ratioX > 0 ) this.applyRatio( coords, { x: this.ratioX, y: this.ratioY }, direction, resizeHandle );
+ else if( square ) this.applyRatio( coords, { x: 1, y: 1 }, direction, resizeHandle );
+
+ var mins = [ this.options.minWidth, this.options.minHeight ]; // minimum dimensions [x,y]
+ var maxs = [ this.options.maxWidth, this.options.maxHeight ]; // maximum dimensions [x,y]
+
+ // apply dimensions where appropriate
+ if( mins[0] > 0 || mins[1] > 0 || maxs[0] > 0 || maxs[1] > 0) {
+
+ var coordsTransX = { a1: coords.x1, a2: coords.x2 };
+ var coordsTransY = { a1: coords.y1, a2: coords.y2 };
+ var boundsX = { min: 0, max: this.imgW };
+ var boundsY = { min: 0, max: this.imgH };
+
+ // handle squaring properly on single axis minimum dimensions
+ if( (mins[0] != 0 || mins[1] != 0) && square ) {
+ if( mins[0] > 0 ) mins[1] = mins[0];
+ else if( mins[1] > 0 ) mins[0] = mins[1];
+ }
+
+ if( (maxs[0] != 0 || maxs[0] != 0) && square ) {
+ // if we have a max x value & it is less than the max y value then we set the y max to the max x (so we don't go over the minimum maximum of one of the axes - if that makes sense)
+ if( maxs[0] > 0 && maxs[0] <= maxs[1] ) maxs[1] = maxs[0];
+ else if( maxs[1] > 0 && maxs[1] <= maxs[0] ) maxs[0] = maxs[1];
+ }
+
+ if( mins[0] > 0 ) this.applyDimRestriction( coordsTransX, mins[0], direction.x, boundsX, 'min' );
+ if( mins[1] > 1 ) this.applyDimRestriction( coordsTransY, mins[1], direction.y, boundsY, 'min' );
+
+ if( maxs[0] > 0 ) this.applyDimRestriction( coordsTransX, maxs[0], direction.x, boundsX, 'max' );
+ if( maxs[1] > 1 ) this.applyDimRestriction( coordsTransY, maxs[1], direction.y, boundsY, 'max' );
+
+ coords = { x1: coordsTransX.a1, y1: coordsTransY.a1, x2: coordsTransX.a2, y2: coordsTransY.a2 };
+ }
+
+ }
+ }
+
+ // dump( 'setAreaCoords (out) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 + '\n' );
+ this.areaCoords = coords;
+ },
+
+ /**
+ * Applies the supplied dimension restriction to the supplied coordinates along a single axis
+ *
+ * @access private
+ * @param obj Single axis coordinates, a1, a2 (e.g. for the x axis a1 = x1 & a2 = x2)
+ * @param int The restriction value
+ * @param int The direction ( -1 = negative, 1 = positive )
+ * @param obj The bounds of the image ( for this axis )
+ * @param string The dimension restriction type ( 'min' | 'max' )
+ * @return void
+ */
+ applyDimRestriction: function( coords, val, direction, bounds, type ) {
+ var check;
+ if( type == 'min' ) check = ( ( coords.a2 - coords.a1 ) < val );
+ else check = ( ( coords.a2 - coords.a1 ) > val );
+ if( check ) {
+ if( direction == 1 ) coords.a2 = coords.a1 + val;
+ else coords.a1 = coords.a2 - val;
+
+ // make sure we're still in the bounds (not too pretty for the user, but needed)
+ if( coords.a1 < bounds.min ) {
+ coords.a1 = bounds.min;
+ coords.a2 = val;
+ } else if( coords.a2 > bounds.max ) {
+ coords.a1 = bounds.max - val;
+ coords.a2 = bounds.max;
+ }
+ }
+ },
+
+ /**
+ * Applies the supplied ratio to the supplied coordinates
+ *
+ * @access private
+ * @param obj Coordinates, x1, y1, x2, y2
+ * @param obj Ratio, x, y
+ * @param obj Direction of mouse, x & y : -1 == negative 1 == positive
+ * @param string The current resize handle || null
+ * @return void
+ */
+ applyRatio : function( coords, ratio, direction, resizeHandle ) {
+ // dump( 'direction.y : ' + direction.y + '\n');
+ var newCoords;
+ if( resizeHandle == 'N' || resizeHandle == 'S' ) {
+ // dump( 'north south \n');
+ // if moving on either the lone north & south handles apply the ratio on the y axis
+ newCoords = this.applyRatioToAxis(
+ { a1: coords.y1, b1: coords.x1, a2: coords.y2, b2: coords.x2 },
+ { a: ratio.y, b: ratio.x },
+ { a: direction.y, b: direction.x },
+ { min: 0, max: this.imgW }
+ );
+ coords.x1 = newCoords.b1;
+ coords.y1 = newCoords.a1;
+ coords.x2 = newCoords.b2;
+ coords.y2 = newCoords.a2;
+ } else {
+ // otherwise deal with it as if we're applying the ratio on the x axis
+ newCoords = this.applyRatioToAxis(
+ { a1: coords.x1, b1: coords.y1, a2: coords.x2, b2: coords.y2 },
+ { a: ratio.x, b: ratio.y },
+ { a: direction.x, b: direction.y },
+ { min: 0, max: this.imgH }
+ );
+ coords.x1 = newCoords.a1;
+ coords.y1 = newCoords.b1;
+ coords.x2 = newCoords.a2;
+ coords.y2 = newCoords.b2;
+ }
+
+ },
+
+ /**
+ * Applies the provided ratio to the provided coordinates based on provided direction & bounds,
+ * use to encapsulate functionality to make it easy to apply to either axis. This is probably
+ * quite hard to visualise so see the x axis example within applyRatio()
+ *
+ * Example in parameter details & comments is for requesting applying ratio to x axis.
+ *
+ * @access private
+ * @param obj Coords object (a1, b1, a2, b2) where a = x & b = y in example
+ * @param obj Ratio object (a, b) where a = x & b = y in example
+ * @param obj Direction object (a, b) where a = x & b = y in example
+ * @param obj Bounds (min, max)
+ * @return obj Coords object (a1, b1, a2, b2) where a = x & b = y in example
+ */
+ applyRatioToAxis: function( coords, ratio, direction, bounds ) {
+ var newCoords = Object.extend( coords, {} );
+ var calcDimA = newCoords.a2 - newCoords.a1; // calculate dimension a (e.g. width)
+ var targDimB = Math.floor( calcDimA * ratio.b / ratio.a ); // the target dimension b (e.g. height)
+ var targB; // to hold target b (e.g. y value)
+ var targDimA; // to hold target dimension a (e.g. width)
+ var calcDimB = null; // to hold calculated dimension b (e.g. height)
+
+ // dump( 'newCoords[0]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
+
+ if( direction.b == 1 ) { // if travelling in a positive direction
+ // make sure we're not going out of bounds
+ targB = newCoords.b1 + targDimB;
+ if( targB > bounds.max ) {
+ targB = bounds.max;
+ calcDimB = targB - newCoords.b1; // calcuate dimension b (e.g. height)
+ }
+
+ newCoords.b2 = targB;
+ } else { // if travelling in a negative direction
+ // make sure we're not going out of bounds
+ targB = newCoords.b2 - targDimB;
+ if( targB < bounds.min ) {
+ targB = bounds.min;
+ calcDimB = targB + newCoords.b2; // calcuate dimension b (e.g. height)
+ }
+ newCoords.b1 = targB;
+ }
+
+ // dump( 'newCoords[1]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
+
+ // apply the calculated dimensions
+ if( calcDimB != null ) {
+ targDimA = Math.floor( calcDimB * ratio.a / ratio.b );
+
+ if( direction.a == 1 ) newCoords.a2 = newCoords.a1 + targDimA;
+ else newCoords.a1 = newCoords.a1 = newCoords.a2 - targDimA;
+ }
+
+ // dump( 'newCoords[2]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n');
+
+ return newCoords;
+ },
+
+ /**
+ * Draws the select area
+ *
+ * @access private
+ * @return void
+ */
+ drawArea: function( ) {
+ /*
+ * NOTE: I'm not using the Element.setStyle() shortcut as they make it
+ * quite sluggish on Mac based browsers
+ */
+ // dump( 'drawArea : ' + this.areaCoords.x1 + ',' + this.areaCoords.y1 + ',' + this.areaCoords.x2 + ',' + this.areaCoords.y2 + '\n' );
+ var areaWidth = this.calcW();
+ var areaHeight = this.calcH();
+
+ /*
+ * Calculate all the style strings before we use them, allows reuse & produces quicker
+ * rendering (especially noticable in Mac based browsers)
+ */
+ var px = 'px';
+ var params = [
+ this.areaCoords.x1 + px, // the left of the selArea
+ this.areaCoords.y1 + px, // the top of the selArea
+ areaWidth + px, // width of the selArea
+ areaHeight + px, // height of the selArea
+ this.areaCoords.x2 + px, // bottom of the selArea
+ this.areaCoords.y2 + px, // right of the selArea
+ (this.img.width - this.areaCoords.x2) + px, // right edge of selArea
+ (this.img.height - this.areaCoords.y2) + px // bottom edge of selArea
+ ];
+
+ // do the select area
+ var areaStyle = this.selArea.style;
+ areaStyle.left = params[0];
+ areaStyle.top = params[1];
+ areaStyle.width = params[2];
+ areaStyle.height = params[3];
+
+ // position the north, east, south & west handles
+ var horizHandlePos = Math.ceil( (areaWidth - 6) / 2 ) + px;
+ var vertHandlePos = Math.ceil( (areaHeight - 6) / 2 ) + px;
+
+ this.handleN.style.left = horizHandlePos;
+ this.handleE.style.top = vertHandlePos;
+ this.handleS.style.left = horizHandlePos;
+ this.handleW.style.top = vertHandlePos;
+
+ // draw the four overlays
+ this.north.style.height = params[1];
+
+ var eastStyle = this.east.style;
+ eastStyle.top = params[1];
+ eastStyle.height = params[3];
+ eastStyle.left = params[4];
+ eastStyle.width = params[6];
+
+ var southStyle = this.south.style;
+ southStyle.top = params[5];
+ southStyle.height = params[7];
+
+ var westStyle = this.west.style;
+ westStyle.top = params[1];
+ westStyle.height = params[3];
+ westStyle.width = params[0];
+
+ // call the draw method on sub classes
+ this.subDrawArea();
+
+ this.forceReRender();
+ },
+
+ /**
+ * Force the re-rendering of the selArea element which fixes rendering issues in Safari
+ * & IE PC, especially evident when re-sizing perfectly vertical using any of the south handles
+ *
+ * @access private
+ * @return void
+ */
+ forceReRender: function() {
+ if( this.isIE || this.isWebKit) {
+ var n = document.createTextNode(' ');
+ var d,el,fixEL,i;
+
+ if( this.isIE ) fixEl = this.selArea;
+ else if( this.isWebKit ) {
+ fixEl = document.getElementsByClassName( 'imgCrop_marqueeSouth', this.imgWrap )[0];
+ /* we have to be a bit more forceful for Safari, otherwise the the marquee &
+ * the south handles still don't move
+ */
+ d = Builder.node( 'div', '' );
+ d.style.visibility = 'hidden';
+
+ var classList = ['SE','S','SW'];
+ for( i = 0; i < classList.length; i++ ) {
+ el = document.getElementsByClassName( 'imgCrop_handle' + classList[i], this.selArea )[0];
+ if( el.childNodes.length ) el.removeChild( el.childNodes[0] );
+ el.appendChild(d);
+ }
+ }
+ fixEl.appendChild(n);
+ fixEl.removeChild(n);
+ }
+ },
+
+ /**
+ * Starts the resize
+ *
+ * @access private
+ * @param obj Event
+ * @return void
+ */
+ startResize: function( e ) {
+ this.startCoords = this.cloneCoords( this.areaCoords );
+
+ this.resizing = true;
+ this.resizeHandle = Event.element( e ).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/, '');
+ // dump( 'this.resizeHandle : ' + this.resizeHandle + '\n' );
+ Event.stop( e );
+ },
+
+ /**
+ * Starts the drag
+ *
+ * @access private
+ * @param obj Event
+ * @return void
+ */
+ startDrag: function( e ) {
+ this.selArea.show();
+ this.clickCoords = this.getCurPos( e );
+
+ this.setAreaCoords( { x1: this.clickCoords.x, y1: this.clickCoords.y, x2: this.clickCoords.x, y2: this.clickCoords.y }, false, false, null );
+
+ this.dragging = true;
+ this.onDrag( e ); // incase the user just clicks once after already making a selection
+ Event.stop( e );
+ },
+
+ /**
+ * Gets the current cursor position relative to the image
+ *
+ * @access private
+ * @param obj Event
+ * @return obj x,y pixels of the cursor
+ */
+ getCurPos: function( e ) {
+ // get the offsets for the wrapper within the document
+ var el = this.imgWrap, wrapOffsets = Position.cumulativeOffset( el );
+ // remove any scrolling that is applied to the wrapper (this may be buggy) - don't count the scroll on the body as that won't affect us
+ while( el.nodeName != 'BODY' ) {
+ wrapOffsets[1] -= el.scrollTop || 0;
+ wrapOffsets[0] -= el.scrollLeft || 0;
+ el = el.parentNode;
+ }
+ return curPos = {
+ x: Event.pointerX(e) - wrapOffsets[0],
+ y: Event.pointerY(e) - wrapOffsets[1]
+ }
+ },
+
+ /**
+ * Performs the drag for both resize & inital draw dragging
+ *
+ * @access private
+ * @param obj Event
+ * @return void
+ */
+ onDrag: function( e ) {
+ if( this.dragging || this.resizing ) {
+
+ var resizeHandle = null;
+ var curPos = this.getCurPos( e );
+ var newCoords = this.cloneCoords( this.areaCoords );
+ var direction = { x: 1, y: 1 };
+
+ if( this.dragging ) {
+ if( curPos.x < this.clickCoords.x ) direction.x = -1;
+ if( curPos.y < this.clickCoords.y ) direction.y = -1;
+
+ this.transformCoords( curPos.x, this.clickCoords.x, newCoords, 'x' );
+ this.transformCoords( curPos.y, this.clickCoords.y, newCoords, 'y' );
+ } else if( this.resizing ) {
+ resizeHandle = this.resizeHandle;
+ // do x movements first
+ if( resizeHandle.match(/E/) ) {
+ // if we're moving an east handle
+ this.transformCoords( curPos.x, this.startCoords.x1, newCoords, 'x' );
+ if( curPos.x < this.startCoords.x1 ) direction.x = -1;
+ } else if( resizeHandle.match(/W/) ) {
+ // if we're moving an west handle
+ this.transformCoords( curPos.x, this.startCoords.x2, newCoords, 'x' );
+ if( curPos.x < this.startCoords.x2 ) direction.x = -1;
+ }
+
+ // do y movements second
+ if( resizeHandle.match(/N/) ) {
+ // if we're moving an north handle
+ this.transformCoords( curPos.y, this.startCoords.y2, newCoords, 'y' );
+ if( curPos.y < this.startCoords.y2 ) direction.y = -1;
+ } else if( resizeHandle.match(/S/) ) {
+ // if we're moving an south handle
+ this.transformCoords( curPos.y, this.startCoords.y1, newCoords, 'y' );
+ if( curPos.y < this.startCoords.y1 ) direction.y = -1;
+ }
+
+ }
+
+ this.setAreaCoords( newCoords, false, e.shiftKey, direction, resizeHandle );
+ this.drawArea();
+ Event.stop( e ); // stop the default event (selecting images & text) in Safari & IE PC
+ }
+ },
+
+ /**
+ * Applies the appropriate transform to supplied co-ordinates, on the
+ * defined axis, depending on the relationship of the supplied values
+ *
+ * @access private
+ * @param int Current value of pointer
+ * @param int Base value to compare current pointer val to
+ * @param obj Coordinates to apply transformation on x1, x2, y1, y2
+ * @param string Axis to apply transformation on 'x' || 'y'
+ * @return void
+ */
+ transformCoords : function( curVal, baseVal, coords, axis ) {
+ var newVals = [ curVal, baseVal ];
+ if( curVal > baseVal ) newVals.reverse();
+ coords[ axis + '1' ] = newVals[0];
+ coords[ axis + '2' ] = newVals[1];
+ },
+
+ /**
+ * Ends the crop & passes the values of the select area on to the appropriate
+ * callback function on completion of a crop
+ *
+ * @access private
+ * @return void
+ */
+ endCrop : function() {
+ this.dragging = false;
+ this.resizing = false;
+
+ this.options.onEndCrop(
+ this.areaCoords,
+ {
+ width: this.calcW(),
+ height: this.calcH()
+ }
+ );
+ },
+
+ /**
+ * Abstract method called on the end of initialization
+ *
+ * @access private
+ * @abstract
+ * @return void
+ */
+ subInitialize: function() {},
+
+ /**
+ * Abstract method called on the end of drawArea()
+ *
+ * @access private
+ * @abstract
+ * @return void
+ */
+ subDrawArea: function() {}
+};
+
+
+
+
+/**
+ * Extend the Cropper.Img class to allow for presentation of a preview image of the resulting crop,
+ * the option for displayOnInit is always overridden to true when displaying a preview image
+ *
+ * Usage:
+ * @param obj Image element to attach to
+ * @param obj Optional options:
+ * - see Cropper.Img for base options
+ *
+ * - previewWrap obj
+ * HTML element that will be used as a container for the preview image
+ */
+Cropper.ImgWithPreview = Class.create();
+
+Object.extend( Object.extend( Cropper.ImgWithPreview.prototype, Cropper.Img.prototype ), {
+
+ /**
+ * Implements the abstract method from Cropper.Img to initialize preview image settings.
+ * Will only attach a preview image is the previewWrap element is defined and the minWidth
+ * & minHeight options are set.
+ *
+ * @see Croper.Img.subInitialize
+ */
+ subInitialize: function() {
+ /**
+ * Whether or not we've attached a preview image
+ * @var boolean
+ */
+ this.hasPreviewImg = false;
+ if( typeof(this.options.previewWrap) != 'undefined'
+ && this.options.minWidth > 0
+ && this.options.minHeight > 0
+ ) {
+ /**
+ * The preview image wrapper element
+ * @var obj HTML element
+ */
+ this.previewWrap = $( this.options.previewWrap );
+ /**
+ * The preview image element
+ * @var obj HTML IMG element
+ */
+ this.previewImg = this.img.cloneNode( false );
+ // set the ID of the preview image to be unique
+ this.previewImg.id = 'imgCrop_' + this.previewImg.id;
+
+
+ // set the displayOnInit option to true so we display the select area at the same time as the thumbnail
+ this.options.displayOnInit = true;
+
+ this.hasPreviewImg = true;
+
+ this.previewWrap.addClassName( 'imgCrop_previewWrap' );
+
+ this.previewWrap.setStyle(
+ {
+ width: this.options.minWidth + 'px',
+ height: this.options.minHeight + 'px'
+ }
+ );
+
+ this.previewWrap.appendChild( this.previewImg );
+ }
+ },
+
+ /**
+ * Implements the abstract method from Cropper.Img to draw the preview image
+ *
+ * @see Croper.Img.subDrawArea
+ */
+ subDrawArea: function() {
+ if( this.hasPreviewImg ) {
+ // get the ratio of the select area to the src image
+ var calcWidth = this.calcW();
+ var calcHeight = this.calcH();
+ // ratios for the dimensions of the preview image
+ var dimRatio = {
+ x: this.imgW / calcWidth,
+ y: this.imgH / calcHeight
+ };
+ //ratios for the positions within the preview
+ var posRatio = {
+ x: calcWidth / this.options.minWidth,
+ y: calcHeight / this.options.minHeight
+ };
+
+ // setting the positions in an obj before apply styles for rendering speed increase
+ var calcPos = {
+ w: Math.ceil( this.options.minWidth * dimRatio.x ) + 'px',
+ h: Math.ceil( this.options.minHeight * dimRatio.y ) + 'px',
+ x: '-' + Math.ceil( this.areaCoords.x1 / posRatio.x ) + 'px',
+ y: '-' + Math.ceil( this.areaCoords.y1 / posRatio.y ) + 'px'
+ }
+
+ var previewStyle = this.previewImg.style;
+ previewStyle.width = calcPos.w;
+ previewStyle.height = calcPos.h;
+ previewStyle.left = calcPos.x;
+ previewStyle.top = calcPos.y;
+ }
+ }
+
+});
diff --git a/htdocs/cropper/lib/builder.js b/htdocs/cropper/lib/builder.js new file mode 100644 index 0000000..5b15ba9 --- /dev/null +++ b/htdocs/cropper/lib/builder.js @@ -0,0 +1,101 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// See scriptaculous.js for full license. + +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + "></" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array)) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + "></" + elementName + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return element; + }, + _text: function(text) { + return document.createTextNode(text); + }, + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute=='className' ? 'class' : attribute) + + '="' + attributes[attribute].toString().escapeHTML() + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e) + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + } +}
\ No newline at end of file diff --git a/htdocs/cropper/lib/controls.js b/htdocs/cropper/lib/controls.js new file mode 100644 index 0000000..de0261e --- /dev/null +++ b/htdocs/cropper/lib/controls.js @@ -0,0 +1,815 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// See scriptaculous.js for full license. + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +var Autocompleter = {} +Autocompleter.Base = function() {}; +Autocompleter.Base.prototype = { + baseInitialize: function(element, update, options) { + this.element = $(element); + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + + if (this.setOptions) + this.setOptions(options); + else + this.options = options || {}; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if (typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (navigator.appVersion.indexOf('MSIE')>0) && + (navigator.userAgent.indexOf('Opera')<0) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + '<iframe id="' + this.update.id + '_iefix" '+ + 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + + 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index-- + else this.index = this.entryCount-1; + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++ + else this.index = 0; + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var lastTokenPos = this.findLastToken(); + if (lastTokenPos != -1) { + var newValue = this.element.value.substr(0, lastTokenPos + 1); + var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value; + } else { + this.element.value = value; + } + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.firstChild); + + if(this.update.firstChild && this.update.firstChild.childNodes) { + this.entryCount = + this.update.firstChild.childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + + this.index = 0; + this.render(); + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + if(this.getToken().length>=this.options.minChars) { + this.startIndicator(); + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + }, + + getToken: function() { + var tokenPos = this.findLastToken(); + if (tokenPos != -1) + var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); + else + var ret = this.element.value; + + return /\n/.test(ret) ? '' : ret; + }, + + findLastToken: function() { + var lastTokenPos = -1; + + for (var i=0; i<this.options.tokens.length; i++) { + var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]); + if (thisTokenPos > lastTokenPos) + lastTokenPos = thisTokenPos; + } + return lastTokenPos; + } +} + +Ajax.Autocompleter = Class.create(); +Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } + +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(); +Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("<li><strong>" + elem.substr(0, entry.length) + "</strong>" + + elem.substr(entry.length) + "</li>"); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("<li>" + elem.substr(0, foundPos) + "<strong>" + + elem.substr(foundPos, entry.length) + "</strong>" + elem.substr( + foundPos + entry.length) + "</li>"); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) + return "<ul>" + ret.join('') + "</ul>"; + } + }, options || {}); + } +}); + +// AJAX in-place editor +// +// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +} + +Ajax.InPlaceEditor = Class.create(); +Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; +Ajax.InPlaceEditor.prototype = { + initialize: function(element, url, options) { + this.url = url; + this.element = $(element); + + this.options = Object.extend({ + okButton: true, + okText: "ok", + cancelLink: true, + cancelText: "cancel", + savingText: "Saving...", + clickToEditText: "Click to edit", + okText: "ok", + rows: 1, + onComplete: function(transport, element) { + new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); + }, + onFailure: function(transport) { + alert("Error communicating with the server: " + transport.responseText.stripTags()); + }, + callback: function(form) { + return Form.serialize(form); + }, + handleLineBreaks: true, + loadingText: 'Loading...', + savingClassName: 'inplaceeditor-saving', + loadingClassName: 'inplaceeditor-loading', + formClassName: 'inplaceeditor-form', + highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, + highlightendcolor: "#FFFFFF", + externalControl: null, + submitOnBlur: false, + ajaxOptions: {}, + evalScripts: false + }, options || {}); + + if(!this.options.formId && this.element.id) { + this.options.formId = this.element.id + "-inplaceeditor"; + if ($(this.options.formId)) { + // there's already a form with that name, don't specify an id + this.options.formId = null; + } + } + + if (this.options.externalControl) { + this.options.externalControl = $(this.options.externalControl); + } + + this.originalBackground = Element.getStyle(this.element, 'background-color'); + if (!this.originalBackground) { + this.originalBackground = "transparent"; + } + + this.element.title = this.options.clickToEditText; + + this.onclickListener = this.enterEditMode.bindAsEventListener(this); + this.mouseoverListener = this.enterHover.bindAsEventListener(this); + this.mouseoutListener = this.leaveHover.bindAsEventListener(this); + Event.observe(this.element, 'click', this.onclickListener); + Event.observe(this.element, 'mouseover', this.mouseoverListener); + Event.observe(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.observe(this.options.externalControl, 'click', this.onclickListener); + Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + }, + enterEditMode: function(evt) { + if (this.saving) return; + if (this.editing) return; + this.editing = true; + this.onEnterEditMode(); + if (this.options.externalControl) { + Element.hide(this.options.externalControl); + } + Element.hide(this.element); + this.createForm(); + this.element.parentNode.insertBefore(this.form, this.element); + Field.scrollFreeActivate(this.editField); + // stop the event to avoid a page refresh in Safari + if (evt) { + Event.stop(evt); + } + return false; + }, + createForm: function() { + this.form = document.createElement("form"); + this.form.id = this.options.formId; + Element.addClassName(this.form, this.options.formClassName) + this.form.onsubmit = this.onSubmit.bind(this); + + this.createEditField(); + + if (this.options.textarea) { + var br = document.createElement("br"); + this.form.appendChild(br); + } + + if (this.options.okButton) { + okButton = document.createElement("input"); + okButton.type = "submit"; + okButton.value = this.options.okText; + okButton.className = 'editor_ok_button'; + this.form.appendChild(okButton); + } + + if (this.options.cancelLink) { + cancelLink = document.createElement("a"); + cancelLink.href = "#"; + cancelLink.appendChild(document.createTextNode(this.options.cancelText)); + cancelLink.onclick = this.onclickCancel.bind(this); + cancelLink.className = 'editor_cancel'; + this.form.appendChild(cancelLink); + } + }, + hasHTMLLineBreaks: function(string) { + if (!this.options.handleLineBreaks) return false; + return string.match(/<br/i) || string.match(/<p>/i); + }, + convertHTMLLineBreaks: function(string) { + return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n").replace(/<\/p>/gi, "\n").replace(/<p>/gi, ""); + }, + createEditField: function() { + var text; + if(this.options.loadTextURL) { + text = this.options.loadingText; + } else { + text = this.getText(); + } + + var obj = this; + + if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { + this.options.textarea = false; + var textField = document.createElement("input"); + textField.obj = this; + textField.type = "text"; + textField.name = "value"; + textField.value = text; + textField.style.backgroundColor = this.options.highlightcolor; + textField.className = 'editor_field'; + var size = this.options.size || this.options.cols || 0; + if (size != 0) textField.size = size; + if (this.options.submitOnBlur) + textField.onblur = this.onSubmit.bind(this); + this.editField = textField; + } else { + this.options.textarea = true; + var textArea = document.createElement("textarea"); + textArea.obj = this; + textArea.name = "value"; + textArea.value = this.convertHTMLLineBreaks(text); + textArea.rows = this.options.rows; + textArea.cols = this.options.cols || 40; + textArea.className = 'editor_field'; + if (this.options.submitOnBlur) + textArea.onblur = this.onSubmit.bind(this); + this.editField = textArea; + } + + if(this.options.loadTextURL) { + this.loadExternalText(); + } + this.form.appendChild(this.editField); + }, + getText: function() { + return this.element.innerHTML; + }, + loadExternalText: function() { + Element.addClassName(this.form, this.options.loadingClassName); + this.editField.disabled = true; + new Ajax.Request( + this.options.loadTextURL, + Object.extend({ + asynchronous: true, + onComplete: this.onLoadedExternalText.bind(this) + }, this.options.ajaxOptions) + ); + }, + onLoadedExternalText: function(transport) { + Element.removeClassName(this.form, this.options.loadingClassName); + this.editField.disabled = false; + this.editField.value = transport.responseText.stripTags(); + }, + onclickCancel: function() { + this.onComplete(); + this.leaveEditMode(); + return false; + }, + onFailure: function(transport) { + this.options.onFailure(transport); + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + this.oldInnerHTML = null; + } + return false; + }, + onSubmit: function() { + // onLoading resets these so we need to save them away for the Ajax call + var form = this.form; + var value = this.editField.value; + + // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... + // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... + // to be displayed indefinitely + this.onLoading(); + + if (this.options.evalScripts) { + new Ajax.Request( + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this), + asynchronous:true, + evalScripts:true + }, this.options.ajaxOptions)); + } else { + new Ajax.Updater( + { success: this.element, + // don't update on failure (this could be an option) + failure: null }, + this.url, Object.extend({ + parameters: this.options.callback(form, value), + onComplete: this.onComplete.bind(this), + onFailure: this.onFailure.bind(this) + }, this.options.ajaxOptions)); + } + // stop the event to avoid a page refresh in Safari + if (arguments.length > 1) { + Event.stop(arguments[0]); + } + return false; + }, + onLoading: function() { + this.saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + showSaving: function() { + this.oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + Element.addClassName(this.element, this.options.savingClassName); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + }, + removeForm: function() { + if(this.form) { + if (this.form.parentNode) Element.remove(this.form); + this.form = null; + } + }, + enterHover: function() { + if (this.saving) return; + this.element.style.backgroundColor = this.options.highlightcolor; + if (this.effect) { + this.effect.cancel(); + } + Element.addClassName(this.element, this.options.hoverClassName) + }, + leaveHover: function() { + if (this.options.backgroundColor) { + this.element.style.backgroundColor = this.oldBackground; + } + Element.removeClassName(this.element, this.options.hoverClassName) + if (this.saving) return; + this.effect = new Effect.Highlight(this.element, { + startcolor: this.options.highlightcolor, + endcolor: this.options.highlightendcolor, + restorecolor: this.originalBackground + }); + }, + leaveEditMode: function() { + Element.removeClassName(this.element, this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this.originalBackground; + Element.show(this.element); + if (this.options.externalControl) { + Element.show(this.options.externalControl); + } + this.editing = false; + this.saving = false; + this.oldInnerHTML = null; + this.onLeaveEditMode(); + }, + onComplete: function(transport) { + this.leaveEditMode(); + this.options.onComplete.bind(this)(transport, this.element); + }, + onEnterEditMode: function() {}, + onLeaveEditMode: function() {}, + dispose: function() { + if (this.oldInnerHTML) { + this.element.innerHTML = this.oldInnerHTML; + } + this.leaveEditMode(); + Event.stopObserving(this.element, 'click', this.onclickListener); + Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); + if (this.options.externalControl) { + Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); + Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); + Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); + } + } +}; + +Ajax.InPlaceCollectionEditor = Class.create(); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); +Object.extend(Ajax.InPlaceCollectionEditor.prototype, { + createEditField: function() { + if (!this.cached_selectTag) { + var selectTag = document.createElement("select"); + var collection = this.options.collection || []; + var optionTag; + collection.each(function(e,i) { + optionTag = document.createElement("option"); + optionTag.value = (e instanceof Array) ? e[0] : e; + if(this.options.value==optionTag.value) optionTag.selected = true; + optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); + selectTag.appendChild(optionTag); + }.bind(this)); + this.cached_selectTag = selectTag; + } + + this.editField = this.cached_selectTag; + if(this.options.loadTextURL) this.loadExternalText(); + this.form.appendChild(this.editField); + this.options.callback = function(form, value) { + return "value=" + encodeURIComponent(value); + } + } +}); + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create(); +Form.Element.DelayedObserver.prototype = { + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}; diff --git a/htdocs/cropper/lib/dragdrop.js b/htdocs/cropper/lib/dragdrop.js new file mode 100644 index 0000000..be2a30f --- /dev/null +++ b/htdocs/cropper/lib/dragdrop.js @@ -0,0 +1,915 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// See scriptaculous.js for full license. + +/*--------------------------------------------------------------------------*/ + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || {}); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if((typeof containment == 'object') && + (containment.constructor == Array)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var affected = []; + + if(this.last_active) this.deactivate(this.last_active); + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) { + drop = Droppables.findDeepestChild(affected); + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) + this.last_active.onDrop(element, this.last_active.element, event); + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +} + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +} + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create(); +Draggable.prototype = { + initialize: function(element) { + var options = Object.extend({ + handle: false, + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + }, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur}); + }, + endeffect: function(element) { + var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0 + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity}); + }, + zindex: 1000, + revert: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } + }, arguments[1] || {}); + + this.element = $(element); + + if(options.handle && (typeof options.handle == 'string')) { + var h = Element.childrenWithClassName(this.element, options.handle, true); + if(h.length>0) this.handle = h[0]; + } + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) + options.scroll = $(options.scroll); + + Element.makePositioned(this.element); // fix IE + + this.delta = this.currentDelta(); + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if(src.tagName && ( + src.tagName=='INPUT' || + src.tagName=='SELECT' || + src.tagName=='OPTION' || + src.tagName=='BUTTON' || + src.tagName=='TEXTAREA')) return; + + if(this.element._revert) { + this.element._revert.cancel(); + this.element._revert = null; + } + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + Position.prepare(); + Droppables.show(pointer, this.element); + Draggables.notify('onDrag', this, event); + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft; + p[1] += this.options.scroll.scrollTop; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.ghosting) { + Position.relativize(this.element); + Element.remove(this._clone); + this._clone = null; + } + + if(success) Droppables.fire(event, this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && typeof revert == 'function') revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(typeof this.options.snap == 'function') { + p = this.options.snap(p[0],p[1],this); + } else { + if(this.options.snap instanceof Array) { + p = p.map( function(v, i) { + return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) + } else { + p = p.map( function(v) { + return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight + } + } + return { top: T, left: L, width: W, height: H }; + } +} + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create(); +SortableObserver.prototype = { + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +} + +var Sortable = { + sortables: {}, + + _findRootElement: function(element) { + while (element.tagName != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + var s = Sortable.options(element); + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + hoverclass: null, + ghosting: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: /^[^_]*_(.*)$/, + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || {}); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + //greedy: !options.dropOnEmpty + } + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + } + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (this.findElements(element, options) || []).each( function(e) { + // handles are per-draggable + var handle = options.handle ? + Element.childrenWithClassName(e, options.handle)[0] : e; + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Element.hide(Sortable._marker); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = $('dropmarker') || document.createElement('DIV'); + Element.hide(Sortable._marker); + Element.addClassName(Sortable._marker, 'dropmarker'); + Sortable._marker.style.position = 'absolute'; + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.style.left = offsets[0] + 'px'; + Sortable._marker.style.top = offsets[1] + 'px'; + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px'; + else + Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'; + + Element.show(Sortable._marker); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: new Array, + position: parent.children.length, + container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) + } + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child) + + parent.children.push (child); + } + + return parent; + }, + + /* Finds the first element of the given tag type within a parent element. + Used for finding the first LI[ST] within a L[IST]I[TEM].*/ + _findChildrenElement: function (element, containerTag) { + if (element && element.hasChildNodes) + for (var i = 0; i < element.childNodes.length; ++i) + if (element.childNodes[i].tagName == containerTag) + return element.childNodes[i]; + + return null; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || {}); + + var root = { + id: null, + parent: null, + children: new Array, + container: element, + position: 0 + } + + return Sortable._tree (element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || {}); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || {}); + + var nodeMap = {}; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || {}); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +} + +/* Returns true if child is contained within element */ +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + + if (child.parentNode == element) return true; + + return Element.isParent(child.parentNode, element); +} + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +} + +Element.offsetSize = function (element, type) { + if (type == 'vertical' || type == 'height') + return element.offsetHeight; + else + return element.offsetWidth; +}
\ No newline at end of file diff --git a/htdocs/cropper/lib/effects.js b/htdocs/cropper/lib/effects.js new file mode 100644 index 0000000..0864323 --- /dev/null +++ b/htdocs/cropper/lib/effects.js @@ -0,0 +1,958 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// See scriptaculous.js for full license. + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if(this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if(this.slice(0,1) == '#') { + if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if(this.length==7) color = this.toLowerCase(); + } + } + return(color.length==7 ? color : (arguments[0] || this)); +} + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +} + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +} + +Element.setContentZoom = function(element, percent) { + element = $(element); + Element.setStyle(element, {fontSize: (percent/100) + 'em'}); + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); +} + +Element.getOpacity = function(element){ + var opacity; + if (opacity = Element.getStyle(element, 'opacity')) + return parseFloat(opacity); + if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) + if(opacity[1]) return parseFloat(opacity[1]) / 100; + return 1.0; +} + +Element.setOpacity = function(element, value){ + element= $(element); + if (value == 1){ + Element.setStyle(element, { opacity: + (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? + 0.999999 : null }); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); + } else { + if(value < 0.00001) value = 0; + Element.setStyle(element, {opacity: value}); + if(/MSIE/.test(navigator.userAgent)) + Element.setStyle(element, + { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + + 'alpha(opacity='+value*100+')' }); + } +} + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +} + +Element.childrenWithClassName = function(element, className, findFirst) { + var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)"); + var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { + return (c.className && c.className.match(classNameRegExp)); + }); + if(!results) results = []; + return results; +} + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +Array.prototype.call = function() { + var args = arguments; + this.each(function(f){ f.apply(this, args) }); +} + +/*--------------------------------------------------------------------------*/ + +var Effect = { + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; + element = $(element); + $A(element.childNodes).each( function(child) { + if(child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + Builder.node('span',{style: tagifyStyle}, + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if(((typeof element == 'object') || + (typeof element == 'function')) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || {}); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || {}); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +var Effect2 = Effect; // deprecated + +/* ------------- transitions ------------- */ + +Effect.Transitions = {} + +Effect.Transitions.linear = function(pos) { + return pos; +} +Effect.Transitions.sinoidal = function(pos) { + return (-Math.cos(pos*Math.PI)/2) + 0.5; +} +Effect.Transitions.reverse = function(pos) { + return 1-pos; +} +Effect.Transitions.flicker = function(pos) { + return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; +} +Effect.Transitions.wobble = function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; +} +Effect.Transitions.pulse = function(pos) { + return (Math.floor(pos*10) % 2 == 0 ? + (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); +} +Effect.Transitions.none = function(pos) { + return 0; +} +Effect.Transitions.full = function(pos) { + return 1; +} + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(); +Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = (typeof effect.options.queue == 'string') ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if(!this.interval) + this.interval = setInterval(this.loop.bind(this), 40); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if(this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + this.effects.invoke('loop', timePos); + } +}); + +Effect.Queues = { + instances: $H(), + get: function(queueName) { + if(typeof queueName != 'string') return queueName; + + if(!this.instances[queueName]) + this.instances[queueName] = new Effect.ScopedQueue(); + + return this.instances[queueName]; + } +} +Effect.Queue = Effect.Queues.get('global'); + +Effect.DefaultOptions = { + transition: Effect.Transitions.sinoidal, + duration: 1.0, // seconds + fps: 25.0, // max. 25fps due to Effect.Queue implementation + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' +} + +Effect.Base = function() {}; +Effect.Base.prototype = { + position: null, + start: function(options) { + this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); + this.currentFrame = 0; + this.state = 'idle'; + this.startOn = this.options.delay*1000; + this.finishOn = this.startOn + (this.options.duration*1000); + this.event('beforeStart'); + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).add(this); + }, + loop: function(timePos) { + if(timePos >= this.startOn) { + if(timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if(this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); + var frame = Math.round(pos * this.options.fps * this.options.duration); + if(frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + render: function(pos) { + if(this.state == 'idle') { + this.state = 'running'; + this.event('beforeSetup'); + if(this.setup) this.setup(); + this.event('afterSetup'); + } + if(this.state == 'running') { + if(this.options.transition) pos = this.options.transition(pos); + pos *= (this.options.to-this.options.from); + pos += this.options.from; + this.position = pos; + this.event('beforeUpdate'); + if(this.update) this.update(pos); + this.event('afterUpdate'); + } + }, + cancel: function() { + if(!this.options.sync) + Effect.Queues.get(typeof this.options.queue == 'string' ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if(this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + return '#<Effect:' + $H(this).inspect() + ',options:' + $H(this.options).inspect() + '>'; + } +} + +Effect.Parallel = Class.create(); +Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if(effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Opacity = Class.create(); +Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + // make this work on IE on elements without 'layout' + if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || {}); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(); +Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Bug in Opera: Opera returns the "real" position of a static element or + // relative element that does not have top/left explicitly set. + // ==> Always set top and left for position relative elements in your stylesheets + // (to 0 if you do not need them) + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if(this.options.mode == 'absolute') { + // absolute movement, so we need to calc deltaX and deltaY + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: this.options.x * position + this.originalLeft + 'px', + top: this.options.y * position + this.originalTop + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); +}; + +Effect.Scale = Class.create(); +Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { + initialize: function(element, percent) { + this.element = $(element) + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or {} with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || {}); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = {}; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%'].each( function(fontSizeType) { + if(fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if(this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if(/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if(!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if(this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = {}; + if(this.options.scaleX) d.width = width + 'px'; + if(this.options.scaleY) d.height = height + 'px'; + if(this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if(this.elementPositioning == 'absolute') { + if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if(this.options.scaleY) d.top = -topd + 'px'; + if(this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(); +Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if(this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { + backgroundImage: this.element.getStyle('background-image') }; + this.element.setStyle({backgroundImage: 'none'}); + if(!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if(!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = Class.create(); +Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { + initialize: function(element) { + this.element = $(element); + this.start(arguments[1] || {}); + }, + setup: function() { + Position.prepare(); + var offsets = Position.cumulativeOffset(this.element); + if(this.options.offset) offsets[1] += this.options.offset; + var max = window.innerHeight ? + window.height - window.innerHeight : + document.body.scrollHeight - + (document.documentElement.clientHeight ? + document.documentElement.clientHeight : document.body.clientHeight); + this.scrollStart = Position.deltaY; + this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; + }, + update: function(position) { + Position.prepare(); + window.scrollTo(Position.deltaX, + this.scrollStart + (position*this.delta)); + } +}); + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if(effect.options.to!=0) return; + effect.element.hide(); + effect.element.setStyle({opacity: oldOpacity}); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from); + effect.element.show(); + }}, arguments[1] || {}); + return new Effect.Opacity(element,options); +} + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + effect.effects[0].element.setStyle({position: 'absolute'}); }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.setStyle(oldStyle); } + }, arguments[1] || {}) + ); +} + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, + Object.extend({ scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping(); + effect.element.setStyle({height: '0px'}); + effect.element.show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || {}) + ); +} + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, { + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned(); + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.undoPositioned(); + effect.element.setStyle({opacity: oldOpacity}); + } + }) + } + }); +} + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); + } + }, arguments[1] || {})); +} + +Effect.Shake = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { + effect.element.undoPositioned(); + effect.element.setStyle(oldStyle); + }}) }}) }}) }}) }}) }}); +} + +Effect.SlideDown = function(element) { + element = $(element); + element.cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = $(element.firstChild).getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.firstChild.makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping(); + effect.element.setStyle({height: '0px'}); + effect.element.show(); }, + afterUpdateInternal: function(effect) { + effect.element.firstChild.setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + // IE will crash if child is undoPositioned first + if(/MSIE/.test(navigator.userAgent)){ + effect.element.undoPositioned(); + effect.element.firstChild.undoPositioned(); + }else{ + effect.element.firstChild.undoPositioned(); + effect.element.undoPositioned(); + } + effect.element.firstChild.setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +Effect.SlideUp = function(element) { + element = $(element); + element.cleanWhitespace(); + var oldInnerBottom = $(element.firstChild).getStyle('bottom'); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + restoreAfterFinish: true, + beforeStartInternal: function(effect) { + effect.element.makePositioned(); + effect.element.firstChild.makePositioned(); + if(window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping(); + effect.element.show(); }, + afterUpdateInternal: function(effect) { + effect.element.firstChild.setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.firstChild.undoPositioned(); + effect.element.undoPositioned(); + effect.element.setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || {}) + ); +} + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, + { restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(effect.element); }, + afterFinishInternal: function(effect) { + effect.element.hide(effect.element); + effect.element.undoClipping(effect.element); } + }); +} + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide(); + effect.element.makeClipping(); + effect.element.makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}); + effect.effects[0].element.show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); + } + }, options) + ) + } + }); +} + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || {}); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned(); + effect.effects[0].element.makeClipping(); }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide(); + effect.effects[0].element.undoClipping(); + effect.effects[0].element.undoPositioned(); + effect.effects[0].element.setStyle(oldStyle); } + }, options) + ); +} + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || {}; + var oldOpacity = element.getInlineOpacity(); + var transition = options.transition || Effect.Transitions.sinoidal; + var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; + reverser.bind(transition); + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 3.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +} + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + Element.makeClipping(element); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide(); + effect.element.undoClipping(); + effect.element.setStyle(oldStyle); + } }); + }}, arguments[1] || {})); +}; + +['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', + 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( + function(f) { Element.Methods[f] = Element[f]; } +); + +Element.Methods.visualEffect = function(element, effect, options) { + s = effect.gsub(/_/, '-').camelize(); + effect_class = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[effect_class](element, options); + return $(element); +}; + +Element.addMethods();
\ No newline at end of file diff --git a/htdocs/cropper/lib/prototype.js b/htdocs/cropper/lib/prototype.js new file mode 100644 index 0000000..0caf9cd --- /dev/null +++ b/htdocs/cropper/lib/prototype.js @@ -0,0 +1,2006 @@ +/* Prototype JavaScript framework, version 1.5.0_rc0 + * (c) 2005 Sam Stephenson <sam@conio.net> + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://prototype.conio.net/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.0_rc0', + ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', + + emptyFunction: function() {}, + K: function(x) {return x} +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.inspect = function(object) { + try { + if (object == undefined) return 'undefined'; + if (object == null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } +} + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this; + return function(event) { + return __method.call(object, event || window.event); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + var digits = this.toString(16); + if (this < 16) return '0' + digits; + return digits; + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + } +}); + +var Try = { + these: function() { + var returnValue; + + for (var i = 0; i < arguments.length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(); + } finally { + this.currentlyExecuting = false; + } + } + } +} +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += (replacement(match) || '').toString(); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var div = document.createElement('div'); + var text = document.createTextNode(this); + div.appendChild(text); + return div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; + }, + + toQueryParams: function() { + var pairs = this.match(/^\??(.*)$/)[1].split('&'); + return pairs.inject({}, function(params, pairString) { + var pair = pairString.split('='); + params[pair[0]] = pair[1]; + return params; + }); + }, + + toArray: function() { + return this.split(''); + }, + + camelize: function() { + var oStringList = this.split('-'); + if (oStringList.length == 1) return oStringList[0]; + + var camelizedString = this.indexOf('-') == 0 + ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) + : oStringList[0]; + + for (var i = 1, len = oStringList.length; i < len; i++) { + var s = oStringList[i]; + camelizedString += s.charAt(0).toUpperCase() + s.substring(1); + } + + return camelizedString; + }, + + inspect: function() { + return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; + } +}); + +String.prototype.gsub.prepareReplacement = function(replacement) { + if (typeof replacement == 'function') return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; +} + +String.prototype.parseQuery = String.prototype.toQueryParams; + +var Template = Class.create(); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; +Template.prototype = { + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + return this.template.gsub(this.pattern, function(match) { + var before = match[1]; + if (before == '\\') return match[2]; + return before + (object[match[3]] || '').toString(); + }); + } +} + +var $break = new Object(); +var $continue = new Object(); + +var Enumerable = { + each: function(iterator) { + var index = 0; + try { + this._each(function(value) { + try { + iterator(value, index++); + } catch (e) { + if (e != $continue) throw e; + } + }); + } catch (e) { + if (e != $break) throw e; + } + }, + + all: function(iterator) { + var result = true; + this.each(function(value, index) { + result = result && !!(iterator || Prototype.K)(value, index); + if (!result) throw $break; + }); + return result; + }, + + any: function(iterator) { + var result = true; + this.each(function(value, index) { + if (result = !!(iterator || Prototype.K)(value, index)) + throw $break; + }); + return result; + }, + + collect: function(iterator) { + var results = []; + this.each(function(value, index) { + results.push(iterator(value, index)); + }); + return results; + }, + + detect: function (iterator) { + var result; + this.each(function(value, index) { + if (iterator(value, index)) { + result = value; + throw $break; + } + }); + return result; + }, + + findAll: function(iterator) { + var results = []; + this.each(function(value, index) { + if (iterator(value, index)) + results.push(value); + }); + return results; + }, + + grep: function(pattern, iterator) { + var results = []; + this.each(function(value, index) { + var stringValue = value.toString(); + if (stringValue.match(pattern)) + results.push((iterator || Prototype.K)(value, index)); + }) + return results; + }, + + include: function(object) { + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + }, + + inject: function(memo, iterator) { + this.each(function(value, index) { + memo = iterator(memo, value, index); + }); + return memo; + }, + + invoke: function(method) { + var args = $A(arguments).slice(1); + return this.collect(function(value) { + return value[method].apply(value, args); + }); + }, + + max: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value >= result) + result = value; + }); + return result; + }, + + min: function(iterator) { + var result; + this.each(function(value, index) { + value = (iterator || Prototype.K)(value, index); + if (result == undefined || value < result) + result = value; + }); + return result; + }, + + partition: function(iterator) { + var trues = [], falses = []; + this.each(function(value, index) { + ((iterator || Prototype.K)(value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + }, + + pluck: function(property) { + var results = []; + this.each(function(value, index) { + results.push(value[property]); + }); + return results; + }, + + reject: function(iterator) { + var results = []; + this.each(function(value, index) { + if (!iterator(value, index)) + results.push(value); + }); + return results; + }, + + sortBy: function(iterator) { + return this.collect(function(value, index) { + return {value: value, criteria: iterator(value, index)}; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + }, + + toArray: function() { + return this.collect(Prototype.K); + }, + + zip: function() { + var iterator = Prototype.K, args = $A(arguments); + if (typeof args.last() == 'function') + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + }, + + inspect: function() { + return '#<Enumerable:' + this.toArray().inspect() + '>'; + } +} + +Object.extend(Enumerable, { + map: Enumerable.collect, + find: Enumerable.detect, + select: Enumerable.findAll, + member: Enumerable.include, + entries: Enumerable.toArray +}); +var $A = Array.from = function(iterable) { + if (!iterable) return []; + if (iterable.toArray) { + return iterable.toArray(); + } else { + var results = []; + for (var i = 0; i < iterable.length; i++) + results.push(iterable[i]); + return results; + } +} + +Object.extend(Array.prototype, Enumerable); + +if (!Array.prototype._reverse) + Array.prototype._reverse = Array.prototype.reverse; + +Object.extend(Array.prototype, { + _each: function(iterator) { + for (var i = 0; i < this.length; i++) + iterator(this[i]); + }, + + clear: function() { + this.length = 0; + return this; + }, + + first: function() { + return this[0]; + }, + + last: function() { + return this[this.length - 1]; + }, + + compact: function() { + return this.select(function(value) { + return value != undefined || value != null; + }); + }, + + flatten: function() { + return this.inject([], function(array, value) { + return array.concat(value && value.constructor == Array ? + value.flatten() : [value]); + }); + }, + + without: function() { + var values = $A(arguments); + return this.select(function(value) { + return !values.include(value); + }); + }, + + indexOf: function(object) { + for (var i = 0; i < this.length; i++) + if (this[i] == object) return i; + return -1; + }, + + reverse: function(inline) { + return (inline !== false ? this : this.toArray())._reverse(); + }, + + inspect: function() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } +}); +var Hash = { + _each: function(iterator) { + for (var key in this) { + var value = this[key]; + if (typeof value == 'function') continue; + + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + }, + + keys: function() { + return this.pluck('key'); + }, + + values: function() { + return this.pluck('value'); + }, + + merge: function(hash) { + return $H(hash).inject($H(this), function(mergedHash, pair) { + mergedHash[pair.key] = pair.value; + return mergedHash; + }); + }, + + toQueryString: function() { + return this.map(function(pair) { + return pair.map(encodeURIComponent).join('='); + }).join('&'); + }, + + inspect: function() { + return '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + } +} + +function $H(object) { + var hash = Object.extend({}, object || {}); + Object.extend(hash, Enumerable); + Object.extend(hash, Hash); + return hash; +} +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + do { + iterator(value); + value = value.succ(); + } while (this.include(value)); + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responderToAdd) { + if (!this.include(responderToAdd)) + this.responders.push(responderToAdd); + }, + + unregister: function(responderToRemove) { + this.responders = this.responders.without(responderToRemove); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (responder[callback] && typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + parameters: '' + } + Object.extend(this.options, options || {}); + }, + + responseIsSuccess: function() { + return this.transport.status == undefined + || this.transport.status == 0 + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + responseIsFailure: function() { + return !this.responseIsSuccess(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + var parameters = this.options.parameters || ''; + if (parameters.length > 0) parameters += '&_='; + + try { + this.url = url; + if (this.options.method == 'get' && parameters.length > 0) + this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; + + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.options.method, this.url, + this.options.asynchronous); + + if (this.options.asynchronous) { + this.transport.onreadystatechange = this.onStateChange.bind(this); + setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); + } + + this.setRequestHeaders(); + + var body = this.options.postBody ? this.options.postBody : parameters; + this.transport.send(this.options.method == 'post' ? body : null); + + } catch (e) { + this.dispatchException(e); + } + }, + + setRequestHeaders: function() { + var requestHeaders = + ['X-Requested-With', 'XMLHttpRequest', + 'X-Prototype-Version', Prototype.Version, + 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; + + if (this.options.method == 'post') { + requestHeaders.push('Content-type', this.options.contentType); + + /* Force "Connection: close" for Mozilla browsers to work around + * a bug where XMLHttpReqeuest sends an incorrect Content-length + * header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType) + requestHeaders.push('Connection', 'close'); + } + + if (this.options.requestHeaders) + requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); + + for (var i = 0; i < requestHeaders.length; i += 2) + this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState != 1) + this.respondToReadyState(this.transport.readyState); + }, + + header: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) {} + }, + + evalJSON: function() { + try { + return eval('(' + this.header('X-JSON') + ')'); + } catch (e) {} + }, + + evalResponse: function() { + try { + return eval(this.transport.responseText); + } catch (e) { + this.dispatchException(e); + } + }, + + respondToReadyState: function(readyState) { + var event = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (event == 'Complete') { + try { + (this.options['on' + this.transport.status] + || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + if ((this.header('Content-type') || '').match(/^text\/javascript/i)) + this.evalResponse(); + } + + try { + (this.options['on' + event] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + event, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ + if (event == 'Complete') + this.transport.onreadystatechange = Prototype.emptyFunction; + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.containers = { + success: container.success ? $(container.success) : $(container), + failure: container.failure ? $(container.failure) : + (container.success ? null : $(container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, object) { + this.updateContent(); + onComplete(transport, object); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.responseIsSuccess() ? + this.containers.success : this.containers.failure; + var response = this.transport.responseText; + + if (!this.options.evalScripts) + response = response.stripScripts(); + + if (receiver) { + if (this.options.insertion) { + new this.options.insertion(receiver, response); + } else { + Element.update(receiver, response); + } + } + + if (this.responseIsSuccess()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $() { + var results = [], element; + for (var i = 0; i < arguments.length; i++) { + element = arguments[i]; + if (typeof element == 'string') + element = document.getElementById(element); + results.push(Element.extend(element)); + } + return results.length < 2 ? results[0] : results; +} + +document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + return $A(children).inject([], function(elements, child) { + if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + elements.push(Element.extend(child)); + return elements; + }); +} + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) + var Element = new Object(); + +Element.extend = function(element) { + if (!element) return; + if (_nativeExtensions) return element; + + if (!element._extended && element.tagName && element != window) { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + element[property] = cache.findOrStore(value); + } + } + + element._extended = true; + return element; +} + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + Element[Element.visible(element) ? 'hide' : 'show'](element); + } + }, + + hide: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = 'none'; + } + }, + + show: function() { + for (var i = 0; i < arguments.length; i++) { + var element = $(arguments[i]); + element.style.display = ''; + } + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + }, + + update: function(element, html) { + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + }, + + replace: function(element, html) { + element = $(element); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + }, + + getHeight: function(element) { + element = $(element); + return element.offsetHeight; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).include(className); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).add(className); + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + return Element.classNames(element).remove(className); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + for (var i = 0; i < element.childNodes.length; i++) { + var node = element.childNodes[i]; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + Element.remove(node); + } + }, + + empty: function(element) { + return $(element).innerHTML.match(/^\s*$/); + }, + + childOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var x = element.x ? element.x : element.offsetLeft, + y = element.y ? element.y : element.offsetTop; + window.scrollTo(x, y); + }, + + getStyle: function(element, style) { + element = $(element); + var value = element.style[style.camelize()]; + if (!value) { + if (document.defaultView && document.defaultView.getComputedStyle) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css.getPropertyValue(style) : null; + } else if (element.currentStyle) { + value = element.currentStyle[style.camelize()]; + } + } + + if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) + if (Element.getStyle(element, 'position') == 'static') value = 'auto'; + + return value == 'auto' ? null : value; + }, + + setStyle: function(element, style) { + element = $(element); + for (var name in style) + element.style[name.camelize()] = style[name]; + }, + + getDimensions: function(element) { + element = $(element); + if (Element.getStyle(element, 'display') != 'none') + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = ''; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = 'none'; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return; + element._overflow = element.style.overflow; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + }, + + undoClipping: function(element) { + element = $(element); + if (element._overflow) return; + element.style.overflow = element._overflow; + element._overflow = undefined; + } +} + +Object.extend(Element, Element.Methods); + +var _nativeExtensions = false; + +if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + var HTMLElement = {} + HTMLElement.prototype = document.createElement('div').__proto__; +} + +Element.addMethods = function(methods) { + Object.extend(Element.Methods, methods || {}); + + if(typeof HTMLElement != 'undefined') { + var methods = Element.Methods, cache = Element.extend.cache; + for (property in methods) { + var value = methods[property]; + if (typeof value == 'function') + HTMLElement.prototype[property] = cache.findOrStore(value); + } + _nativeExtensions = true; + } +} + +Element.addMethods(); + +var Toggle = new Object(); +Toggle.display = Element.toggle; + +/*--------------------------------------------------------------------------*/ + +Abstract.Insertion = function(adjacency) { + this.adjacency = adjacency; +} + +Abstract.Insertion.prototype = { + initialize: function(element, content) { + this.element = $(element); + this.content = content.stripScripts(); + + if (this.adjacency && this.element.insertAdjacentHTML) { + try { + this.element.insertAdjacentHTML(this.adjacency, this.content); + } catch (e) { + var tagName = this.element.tagName.toLowerCase(); + if (tagName == 'tbody' || tagName == 'tr') { + this.insertContent(this.contentFromAnonymousTable()); + } else { + throw e; + } + } + } else { + this.range = this.element.ownerDocument.createRange(); + if (this.initializeRange) this.initializeRange(); + this.insertContent([this.range.createContextualFragment(this.content)]); + } + + setTimeout(function() {content.evalScripts()}, 10); + }, + + contentFromAnonymousTable: function() { + var div = document.createElement('div'); + div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>'; + return $A(div.childNodes[0].childNodes[0].childNodes); + } +} + +var Insertion = new Object(); + +Insertion.Before = Class.create(); +Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { + initializeRange: function() { + this.range.setStartBefore(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, this.element); + }).bind(this)); + } +}); + +Insertion.Top = Class.create(); +Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(true); + }, + + insertContent: function(fragments) { + fragments.reverse(false).each((function(fragment) { + this.element.insertBefore(fragment, this.element.firstChild); + }).bind(this)); + } +}); + +Insertion.Bottom = Class.create(); +Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { + initializeRange: function() { + this.range.selectNodeContents(this.element); + this.range.collapse(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.appendChild(fragment); + }).bind(this)); + } +}); + +Insertion.After = Class.create(); +Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { + initializeRange: function() { + this.range.setStartAfter(this.element); + }, + + insertContent: function(fragments) { + fragments.each((function(fragment) { + this.element.parentNode.insertBefore(fragment, + this.element.nextSibling); + }).bind(this)); + } +}); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set(this.toArray().concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set(this.select(function(className) { + return className != classNameToRemove; + }).join(' ')); + }, + + toString: function() { + return this.toArray().join(' '); + } +} + +Object.extend(Element.ClassNames.prototype, Enumerable); +var Selector = Class.create(); +Selector.prototype = { + initialize: function(expression) { + this.params = {classNames: []}; + this.expression = expression.toString().strip(); + this.parseExpression(); + this.compileMatcher(); + }, + + parseExpression: function() { + function abort(message) { throw 'Parse error in selector: ' + message; } + + if (this.expression == '') abort('empty expression'); + + var params = this.params, expr = this.expression, match, modifier, clause, rest; + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { + params.attributes = params.attributes || []; + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); + expr = match[1]; + } + + if (expr == '*') return this.params.wildcard = true; + + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { + modifier = match[1], clause = match[2], rest = match[3]; + switch (modifier) { + case '#': params.id = clause; break; + case '.': params.classNames.push(clause); break; + case '': + case undefined: params.tagName = clause.toUpperCase(); break; + default: abort(expr.inspect()); + } + expr = rest; + } + + if (expr.length > 0) abort(expr.inspect()); + }, + + buildMatchExpression: function() { + var params = this.params, conditions = [], clause; + + if (params.wildcard) + conditions.push('true'); + if (clause = params.id) + conditions.push('element.id == ' + clause.inspect()); + if (clause = params.tagName) + conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); + if ((clause = params.classNames).length > 0) + for (var i = 0; i < clause.length; i++) + conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); + if (clause = params.attributes) { + clause.each(function(attribute) { + var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; + var splitValueBy = function(delimiter) { + return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; + } + + switch (attribute.operator) { + case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; + case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; + case '|=': conditions.push( + splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() + ); break; + case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; + case '': + case undefined: conditions.push(value + ' != null'); break; + default: throw 'Unknown operator ' + attribute.operator + ' in selector'; + } + }); + } + + return conditions.join(' && '); + }, + + compileMatcher: function() { + this.match = new Function('element', 'if (!element.tagName) return false; \ + return ' + this.buildMatchExpression()); + }, + + findElements: function(scope) { + var element; + + if (element = $(this.params.id)) + if (this.match(element)) + if (!scope || Element.childOf(element, scope)) + return [element]; + + scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); + + var results = []; + for (var i = 0; i < scope.length; i++) + if (this.match(element = scope[i])) + results.push(Element.extend(element)); + + return results; + }, + + toString: function() { + return this.expression; + } +} + +function $$() { + return $A(arguments).map(function(expression) { + return expression.strip().split(/\s+/).inject([null], function(results, expr) { + var selector = new Selector(expr); + return results.map(selector.findElements.bind(selector)).flatten(); + }); + }).flatten(); +} +var Field = { + clear: function() { + for (var i = 0; i < arguments.length; i++) + $(arguments[i]).value = ''; + }, + + focus: function(element) { + $(element).focus(); + }, + + present: function() { + for (var i = 0; i < arguments.length; i++) + if ($(arguments[i]).value == '') return false; + return true; + }, + + select: function(element) { + $(element).select(); + }, + + activate: function(element) { + element = $(element); + element.focus(); + if (element.select) + element.select(); + } +} + +/*--------------------------------------------------------------------------*/ + +var Form = { + serialize: function(form) { + var elements = Form.getElements($(form)); + var queryComponents = new Array(); + + for (var i = 0; i < elements.length; i++) { + var queryComponent = Form.Element.serialize(elements[i]); + if (queryComponent) + queryComponents.push(queryComponent); + } + + return queryComponents.join('&'); + }, + + getElements: function(form) { + form = $(form); + var elements = new Array(); + + for (var tagName in Form.Element.Serializers) { + var tagElements = form.getElementsByTagName(tagName); + for (var j = 0; j < tagElements.length; j++) + elements.push(tagElements[j]); + } + return elements; + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) + return inputs; + + var matchingInputs = new Array(); + for (var i = 0; i < inputs.length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || + (name && input.name != name)) + continue; + matchingInputs.push(input); + } + + return matchingInputs; + }, + + disable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.blur(); + element.disabled = 'true'; + } + }, + + enable: function(form) { + var elements = Form.getElements(form); + for (var i = 0; i < elements.length; i++) { + var element = elements[i]; + element.disabled = ''; + } + }, + + findFirstElement: function(form) { + return Form.getElements(form).find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + Field.activate(Form.findFirstElement(form)); + }, + + reset: function(form) { + $(form).reset(); + } +} + +Form.Element = { + serialize: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) { + var key = encodeURIComponent(parameter[0]); + if (key.length == 0) return; + + if (parameter[1].constructor != Array) + parameter[1] = [parameter[1]]; + + return parameter[1].map(function(value) { + return key + '=' + encodeURIComponent(value); + }).join('&'); + } + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + var parameter = Form.Element.Serializers[method](element); + + if (parameter) + return parameter[1]; + } +} + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'submit': + case 'hidden': + case 'password': + case 'text': + return Form.Element.Serializers.textarea(element); + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + } + return false; + }, + + inputSelector: function(element) { + if (element.checked) + return [element.name, element.value]; + }, + + textarea: function(element) { + return [element.name, element.value]; + }, + + select: function(element) { + return Form.Element.Serializers[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var value = '', opt, index = element.selectedIndex; + if (index >= 0) { + opt = element.options[index]; + value = opt.value || opt.text; + } + return [element.name, value]; + }, + + selectMany: function(element) { + var value = []; + for (var i = 0; i < element.length; i++) { + var opt = element.options[i]; + if (opt.selected) + value.push(opt.value || opt.text); + } + return [element.name, value]; + } +} + +/*--------------------------------------------------------------------------*/ + +var $F = Form.Element.getValue; + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + var elements = Form.getElements(this.element); + for (var i = 0; i < elements.length; i++) + this.registerCallback(elements[i]); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + case 'password': + case 'text': + case 'textarea': + case 'select-one': + case 'select-multiple': + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + + element: function(event) { + return event.target || event.srcElement; + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0; i < Event.observers.length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.attachEvent)) + name = 'keydown'; + + this._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + var element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (navigator.appVersion.match(/Konqueror|Safari|KHTML/) + || element.detachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + element.detachEvent('on' + name, observer); + } + } +}); + +/* prevent memory leaks in IE */ +if (navigator.appVersion.match(/\bMSIE\b/)) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + clone: function(source, target) { + source = $(source); + target = $(target); + target.style.position = 'absolute'; + var offsets = this.cumulativeOffset(source); + target.style.top = offsets[1] + 'px'; + target.style.left = offsets[0] + 'px'; + target.style.width = source.offsetWidth + 'px'; + target.style.height = source.offsetHeight + 'px'; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent==document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px';; + element.style.left = left + 'px';; + element.style.width = width + 'px';; + element.style.height = height + 'px';; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +}
\ No newline at end of file diff --git a/htdocs/cropper/lib/scriptaculous.js b/htdocs/cropper/lib/scriptaculous.js new file mode 100644 index 0000000..f61fc57 --- /dev/null +++ b/htdocs/cropper/lib/scriptaculous.js @@ -0,0 +1,47 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +var Scriptaculous = { + Version: '1.6.1', + require: function(libraryName) { + // inserting via DOM fails in Safari 2.0, so brute force approach + document.write('<script type="text/javascript" src="'+libraryName+'"></script>'); + }, + load: function() { + if((typeof Prototype=='undefined') || + (typeof Element == 'undefined') || + (typeof Element.Methods=='undefined') || + parseFloat(Prototype.Version.split(".")[0] + "." + + Prototype.Version.split(".")[1]) < 1.5) + throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0"); + + $A(document.getElementsByTagName("script")).findAll( function(s) { + return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/)) + }).each( function(s) { + var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,''); + var includes = s.src.match(/\?.*load=([a-z,]*)/); + (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each( + function(include) { Scriptaculous.require(path+include+'.js') }); + }); + } +} + +Scriptaculous.load();
\ No newline at end of file diff --git a/htdocs/cropper/lib/slider.js b/htdocs/cropper/lib/slider.js new file mode 100644 index 0000000..c0f1fc0 --- /dev/null +++ b/htdocs/cropper/lib/slider.js @@ -0,0 +1,283 @@ +// Copyright (c) 2005 Marty Haught, Thomas Fuchs +// +// See http://script.aculo.us for more info +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +if(!Control) var Control = {}; +Control.Slider = Class.create(); + +// options: +// axis: 'vertical', or 'horizontal' (default) +// +// callbacks: +// onChange(value) +// onSlide(value) +Control.Slider.prototype = { + initialize: function(handle, track, options) { + var slider = this; + + if(handle instanceof Array) { + this.handles = handle.collect( function(e) { return $(e) }); + } else { + this.handles = [$(handle)]; + } + + this.track = $(track); + this.options = options || {}; + + this.axis = this.options.axis || 'horizontal'; + this.increment = this.options.increment || 1; + this.step = parseInt(this.options.step || '1'); + this.range = this.options.range || $R(0,1); + + this.value = 0; // assure backwards compat + this.values = this.handles.map( function() { return 0 }); + this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; + this.options.startSpan = $(this.options.startSpan || null); + this.options.endSpan = $(this.options.endSpan || null); + + this.restricted = this.options.restricted || false; + + this.maximum = this.options.maximum || this.range.end; + this.minimum = this.options.minimum || this.range.start; + + // Will be used to align the handle onto the track, if necessary + this.alignX = parseInt(this.options.alignX || '0'); + this.alignY = parseInt(this.options.alignY || '0'); + + this.trackLength = this.maximumOffset() - this.minimumOffset(); + this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth; + + this.active = false; + this.dragging = false; + this.disabled = false; + + if(this.options.disabled) this.setDisabled(); + + // Allowed values array + this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; + if(this.allowedValues) { + this.minimum = this.allowedValues.min(); + this.maximum = this.allowedValues.max(); + } + + this.eventMouseDown = this.startDrag.bindAsEventListener(this); + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.update.bindAsEventListener(this); + + // Initialize handles in reverse (make sure first handle is active) + this.handles.each( function(h,i) { + i = slider.handles.length-1-i; + slider.setValue(parseFloat( + (slider.options.sliderValue instanceof Array ? + slider.options.sliderValue[i] : slider.options.sliderValue) || + slider.range.start), i); + Element.makePositioned(h); // fix IE + Event.observe(h, "mousedown", slider.eventMouseDown); + }); + + Event.observe(this.track, "mousedown", this.eventMouseDown); + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + + this.initialized = true; + }, + dispose: function() { + var slider = this; + Event.stopObserving(this.track, "mousedown", this.eventMouseDown); + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + this.handles.each( function(h) { + Event.stopObserving(h, "mousedown", slider.eventMouseDown); + }); + }, + setDisabled: function(){ + this.disabled = true; + }, + setEnabled: function(){ + this.disabled = false; + }, + getNearestValue: function(value){ + if(this.allowedValues){ + if(value >= this.allowedValues.max()) return(this.allowedValues.max()); + if(value <= this.allowedValues.min()) return(this.allowedValues.min()); + + var offset = Math.abs(this.allowedValues[0] - value); + var newValue = this.allowedValues[0]; + this.allowedValues.each( function(v) { + var currentOffset = Math.abs(v - value); + if(currentOffset <= offset){ + newValue = v; + offset = currentOffset; + } + }); + return newValue; + } + if(value > this.range.end) return this.range.end; + if(value < this.range.start) return this.range.start; + return value; + }, + setValue: function(sliderValue, handleIdx){ + if(!this.active) { + this.activeHandle = this.handles[handleIdx]; + this.activeHandleIdx = handleIdx; + this.updateStyles(); + } + handleIdx = handleIdx || this.activeHandleIdx || 0; + if(this.initialized && this.restricted) { + if((handleIdx>0) && (sliderValue<this.values[handleIdx-1])) + sliderValue = this.values[handleIdx-1]; + if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1])) + sliderValue = this.values[handleIdx+1]; + } + sliderValue = this.getNearestValue(sliderValue); + this.values[handleIdx] = sliderValue; + this.value = this.values[0]; // assure backwards compat + + this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = + this.translateToPx(sliderValue); + + this.drawSpans(); + if(!this.dragging || !this.event) this.updateFinished(); + }, + setValueBy: function(delta, handleIdx) { + this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, + handleIdx || this.activeHandleIdx || 0); + }, + translateToPx: function(value) { + return Math.round( + ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * + (value - this.range.start)) + "px"; + }, + translateToValue: function(offset) { + return ((offset/(this.trackLength-this.handleLength) * + (this.range.end-this.range.start)) + this.range.start); + }, + getRange: function(range) { + var v = this.values.sortBy(Prototype.K); + range = range || 0; + return $R(v[range],v[range+1]); + }, + minimumOffset: function(){ + return(this.isVertical() ? this.alignY : this.alignX); + }, + maximumOffset: function(){ + return(this.isVertical() ? + this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX); + }, + isVertical: function(){ + return (this.axis == 'vertical'); + }, + drawSpans: function() { + var slider = this; + if(this.spans) + $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); + if(this.options.startSpan) + this.setSpan(this.options.startSpan, + $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); + if(this.options.endSpan) + this.setSpan(this.options.endSpan, + $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); + }, + setSpan: function(span, range) { + if(this.isVertical()) { + span.style.top = this.translateToPx(range.start); + span.style.height = this.translateToPx(range.end - range.start + this.range.start); + } else { + span.style.left = this.translateToPx(range.start); + span.style.width = this.translateToPx(range.end - range.start + this.range.start); + } + }, + updateStyles: function() { + this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); + Element.addClassName(this.activeHandle, 'selected'); + }, + startDrag: function(event) { + if(Event.isLeftClick(event)) { + if(!this.disabled){ + this.active = true; + + var handle = Event.element(event); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + if(handle==this.track) { + var offsets = Position.cumulativeOffset(this.track); + this.event = event; + this.setValue(this.translateToValue( + (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) + )); + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } else { + // find the handle (prevents issues with Safari) + while((this.handles.indexOf(handle) == -1) && handle.parentNode) + handle = handle.parentNode; + + this.activeHandle = handle; + this.activeHandleIdx = this.handles.indexOf(this.activeHandle); + this.updateStyles(); + + var offsets = Position.cumulativeOffset(this.activeHandle); + this.offsetX = (pointer[0] - offsets[0]); + this.offsetY = (pointer[1] - offsets[1]); + } + } + Event.stop(event); + } + }, + update: function(event) { + if(this.active) { + if(!this.dragging) this.dragging = true; + this.draw(event); + // fix AppleWebKit rendering + if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); + Event.stop(event); + } + }, + draw: function(event) { + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var offsets = Position.cumulativeOffset(this.track); + pointer[0] -= this.offsetX + offsets[0]; + pointer[1] -= this.offsetY + offsets[1]; + this.event = event; + this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); + if(this.initialized && this.options.onSlide) + this.options.onSlide(this.values.length>1 ? this.values : this.value, this); + }, + endDrag: function(event) { + if(this.active && this.dragging) { + this.finishDrag(event, true); + Event.stop(event); + } + this.active = false; + this.dragging = false; + }, + finishDrag: function(event, success) { + this.active = false; + this.dragging = false; + this.updateFinished(); + }, + updateFinished: function() { + if(this.initialized && this.options.onChange) + this.options.onChange(this.values.length>1 ? this.values : this.value, this); + this.event = null; + } +}
\ No newline at end of file diff --git a/htdocs/cropper/lib/unittest.js b/htdocs/cropper/lib/unittest.js new file mode 100644 index 0000000..d2c2d81 --- /dev/null +++ b/htdocs/cropper/lib/unittest.js @@ -0,0 +1,383 @@ +// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005 Jon Tirsen (http://www.tirsen.com) +// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// experimental, Firefox-only +Event.simulateMouse = function(element, eventName) { + var options = Object.extend({ + pointerX: 0, + pointerY: 0, + buttons: 0 + }, arguments[2] || {}); + var oEvent = document.createEvent("MouseEvents"); + oEvent.initMouseEvent(eventName, true, true, document.defaultView, + options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, + false, false, false, false, 0, $(element)); + + if(this.mark) Element.remove(this.mark); + this.mark = document.createElement('div'); + this.mark.appendChild(document.createTextNode(" ")); + document.body.appendChild(this.mark); + this.mark.style.position = 'absolute'; + this.mark.style.top = options.pointerY + "px"; + this.mark.style.left = options.pointerX + "px"; + this.mark.style.width = "5px"; + this.mark.style.height = "5px;"; + this.mark.style.borderTop = "1px solid red;" + this.mark.style.borderLeft = "1px solid red;" + + if(this.step) + alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options)); + + $(element).dispatchEvent(oEvent); +}; + +// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2. +// You need to downgrade to 1.0.4 for now to get this working +// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much +Event.simulateKey = function(element, eventName) { + var options = Object.extend({ + ctrlKey: false, + altKey: false, + shiftKey: false, + metaKey: false, + keyCode: 0, + charCode: 0 + }, arguments[2] || {}); + + var oEvent = document.createEvent("KeyEvents"); + oEvent.initKeyEvent(eventName, true, true, window, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.keyCode, options.charCode ); + $(element).dispatchEvent(oEvent); +}; + +Event.simulateKeys = function(element, command) { + for(var i=0; i<command.length; i++) { + Event.simulateKey(element,'keypress',{charCode:command.charCodeAt(i)}); + } +}; + +var Test = {} +Test.Unit = {}; + +// security exception workaround +Test.Unit.inspect = Object.inspect; + +Test.Unit.Logger = Class.create(); +Test.Unit.Logger.prototype = { + initialize: function(log) { + this.log = $(log); + if (this.log) { + this._createLogTable(); + } + }, + start: function(testName) { + if (!this.log) return; + this.testName = testName; + this.lastLogLine = document.createElement('tr'); + this.statusCell = document.createElement('td'); + this.nameCell = document.createElement('td'); + this.nameCell.appendChild(document.createTextNode(testName)); + this.messageCell = document.createElement('td'); + this.lastLogLine.appendChild(this.statusCell); + this.lastLogLine.appendChild(this.nameCell); + this.lastLogLine.appendChild(this.messageCell); + this.loglines.appendChild(this.lastLogLine); + }, + finish: function(status, summary) { + if (!this.log) return; + this.lastLogLine.className = status; + this.statusCell.innerHTML = status; + this.messageCell.innerHTML = this._toHTML(summary); + }, + message: function(message) { + if (!this.log) return; + this.messageCell.innerHTML = this._toHTML(message); + }, + summary: function(summary) { + if (!this.log) return; + this.logsummary.innerHTML = this._toHTML(summary); + }, + _createLogTable: function() { + this.log.innerHTML = + '<div id="logsummary"></div>' + + '<table id="logtable">' + + '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' + + '<tbody id="loglines"></tbody>' + + '</table>'; + this.logsummary = $('logsummary') + this.loglines = $('loglines'); + }, + _toHTML: function(txt) { + return txt.escapeHTML().replace(/\n/g,"<br/>"); + } +} + +Test.Unit.Runner = Class.create(); +Test.Unit.Runner.prototype = { + initialize: function(testcases) { + this.options = Object.extend({ + testLog: 'testlog' + }, arguments[1] || {}); + this.options.resultsURL = this.parseResultsURLQueryParameter(); + if (this.options.testLog) { + this.options.testLog = $(this.options.testLog) || null; + } + if(this.options.tests) { + this.tests = []; + for(var i = 0; i < this.options.tests.length; i++) { + if(/^test/.test(this.options.tests[i])) { + this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); + } + } + } else { + if (this.options.test) { + this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; + } else { + this.tests = []; + for(var testcase in testcases) { + if(/^test/.test(testcase)) { + this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"])); + } + } + } + } + this.currentTest = 0; + this.logger = new Test.Unit.Logger(this.options.testLog); + setTimeout(this.runTests.bind(this), 1000); + }, + parseResultsURLQueryParameter: function() { + return window.location.search.parseQuery()["resultsURL"]; + }, + // Returns: + // "ERROR" if there was an error, + // "FAILURE" if there was a failure, or + // "SUCCESS" if there was neither + getResult: function() { + var hasFailure = false; + for(var i=0;i<this.tests.length;i++) { + if (this.tests[i].errors > 0) { + return "ERROR"; + } + if (this.tests[i].failures > 0) { + hasFailure = true; + } + } + if (hasFailure) { + return "FAILURE"; + } else { + return "SUCCESS"; + } + }, + postResults: function() { + if (this.options.resultsURL) { + new Ajax.Request(this.options.resultsURL, + { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); + } + }, + runTests: function() { + var test = this.tests[this.currentTest]; + if (!test) { + // finished! + this.postResults(); + this.logger.summary(this.summary()); + return; + } + if(!test.isWaiting) { + this.logger.start(test.name); + } + test.run(); + if(test.isWaiting) { + this.logger.message("Waiting for " + test.timeToWait + "ms"); + setTimeout(this.runTests.bind(this), test.timeToWait || 1000); + } else { + this.logger.finish(test.status(), test.summary()); + this.currentTest++; + // tail recursive, hopefully the browser will skip the stackframe + this.runTests(); + } + }, + summary: function() { + var assertions = 0; + var failures = 0; + var errors = 0; + var messages = []; + for(var i=0;i<this.tests.length;i++) { + assertions += this.tests[i].assertions; + failures += this.tests[i].failures; + errors += this.tests[i].errors; + } + return ( + this.tests.length + " tests, " + + assertions + " assertions, " + + failures + " failures, " + + errors + " errors"); + } +} + +Test.Unit.Assertions = Class.create(); +Test.Unit.Assertions.prototype = { + initialize: function() { + this.assertions = 0; + this.failures = 0; + this.errors = 0; + this.messages = []; + }, + summary: function() { + return ( + this.assertions + " assertions, " + + this.failures + " failures, " + + this.errors + " errors" + "\n" + + this.messages.join("\n")); + }, + pass: function() { + this.assertions++; + }, + fail: function(message) { + this.failures++; + this.messages.push("Failure: " + message); + }, + info: function(message) { + this.messages.push("Info: " + message); + }, + error: function(error) { + this.errors++; + this.messages.push(error.name + ": "+ error.message + "(" + Test.Unit.inspect(error) +")"); + }, + status: function() { + if (this.failures > 0) return 'failed'; + if (this.errors > 0) return 'error'; + return 'passed'; + }, + assert: function(expression) { + var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; + try { expression ? this.pass() : + this.fail(message); } + catch(e) { this.error(e); } + }, + assertEqual: function(expected, actual) { + var message = arguments[2] || "assertEqual"; + try { (expected == actual) ? this.pass() : + this.fail(message + ': expected "' + Test.Unit.inspect(expected) + + '", actual "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertEnumEqual: function(expected, actual) { + var message = arguments[2] || "assertEnumEqual"; + try { $A(expected).length == $A(actual).length && + expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ? + this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + + ', actual ' + Test.Unit.inspect(actual)); } + catch(e) { this.error(e); } + }, + assertNotEqual: function(expected, actual) { + var message = arguments[2] || "assertNotEqual"; + try { (expected != actual) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } + catch(e) { this.error(e); } + }, + assertNull: function(obj) { + var message = arguments[1] || 'assertNull' + try { (obj==null) ? this.pass() : + this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } + catch(e) { this.error(e); } + }, + assertHidden: function(element) { + var message = arguments[1] || 'assertHidden'; + this.assertEqual("none", element.style.display, message); + }, + assertNotNull: function(object) { + var message = arguments[1] || 'assertNotNull'; + this.assert(object != null, message); + }, + assertInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertInstanceOf'; + try { + (actual instanceof expected) ? this.pass() : + this.fail(message + ": object was not an instance of the expected type"); } + catch(e) { this.error(e); } + }, + assertNotInstanceOf: function(expected, actual) { + var message = arguments[2] || 'assertNotInstanceOf'; + try { + !(actual instanceof expected) ? this.pass() : + this.fail(message + ": object was an instance of the not expected type"); } + catch(e) { this.error(e); } + }, + _isVisible: function(element) { + element = $(element); + if(!element.parentNode) return true; + this.assertNotNull(element); + if(element.style && Element.getStyle(element, 'display') == 'none') + return false; + + return this._isVisible(element.parentNode); + }, + assertNotVisible: function(element) { + this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); + }, + assertVisible: function(element) { + this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); + }, + benchmark: function(operation, iterations) { + var startAt = new Date(); + (iterations || 1).times(operation); + var timeTaken = ((new Date())-startAt); + this.info((arguments[2] || 'Operation') + ' finished ' + + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); + return timeTaken; + } +} + +Test.Unit.Testcase = Class.create(); +Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { + initialize: function(name, test, setup, teardown) { + Test.Unit.Assertions.prototype.initialize.bind(this)(); + this.name = name; + this.test = test || function() {}; + this.setup = setup || function() {}; + this.teardown = teardown || function() {}; + this.isWaiting = false; + this.timeToWait = 1000; + }, + wait: function(time, nextPart) { + this.isWaiting = true; + this.test = nextPart; + this.timeToWait = time; + }, + run: function() { + try { + try { + if (!this.isWaiting) this.setup.bind(this)(); + this.isWaiting = false; + this.test.bind(this)(); + } finally { + if(!this.isWaiting) { + this.teardown.bind(this)(); + } + } + } + catch(e) { this.error(e); } + } +}); diff --git a/htdocs/cropper/licence.txt b/htdocs/cropper/licence.txt new file mode 100644 index 0000000..f696f25 --- /dev/null +++ b/htdocs/cropper/licence.txt @@ -0,0 +1,12 @@ +Copyright (c) 2006, David Spurr (www.defusion.org.uk) +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +http://www.opensource.org/licenses/bsd-license.php
\ No newline at end of file diff --git a/htdocs/cropper/marqueeHoriz.gif b/htdocs/cropper/marqueeHoriz.gif Binary files differnew file mode 100644 index 0000000..25317e5 --- /dev/null +++ b/htdocs/cropper/marqueeHoriz.gif diff --git a/htdocs/cropper/marqueeVert.gif b/htdocs/cropper/marqueeVert.gif Binary files differnew file mode 100644 index 0000000..354070b --- /dev/null +++ b/htdocs/cropper/marqueeVert.gif diff --git a/htdocs/js/smokeping_zoom.js b/htdocs/cropper/smokeping-cropper.js index df90e85..3419088 100644 --- a/htdocs/js/smokeping_zoom.js +++ b/htdocs/cropper/smokeping-cropper.js @@ -1,21 +1,3 @@ -<!-- - -/* - * This code replaces images in the smokeping website with ajax - * - * The jquery toolkit (version 1.1.3.1) was used for platform - * independency. The URL parsing part was taken from the - * bonsaj.js script. - * - * Copyright (c) 2007 Roman Plessl <roman.plessl@oetiker.ch> - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date: 2007-08-15 17:14:56 +0200 $ - * $Rev: 36 $ - * - */ - /*++ from bonsai.js ++ urlObj +++++++++++++++++++++++++++++++++++++++++*/ function urlObj(url) { var urlBaseAndParameters; @@ -79,51 +61,23 @@ function JSToISODate(mydate) { return encodeURI(isodate); } -var mySelectTop = 0; -var mySelectLeft = 0; -var mySelectRight = 0; -var mySelectBottom = 0; - -$(document).ready(function() { - - var rrdimg = jQuery("img#zoom"); - if (rrdimg.length){ // only do this if we actually have an zoom image - StartDateString = 0; - EndDateString = 0; - jQuery('body',document).append('<div id="selector" oncontextmenu="return false"></div>') - var selector = jQuery("div#selector"); - - selector.Selectable({ - opacity : 1, - helperclass : 'selecthelper' - }); - - selector.css({ - cursor: 'crosshair', - top : rrdimg.offset().top+30 + 'px', - width : rrdimg.width()-95 + 'px', - left : rrdimg.offset().left+68 + 'px', - height : rrdimg.height()-110 + 'px', - position: 'absolute', - background: '#fefefe', - opacity: 0.1, - margin: 0, - padding: 0, - 'z-index': 1000 - }); - }; -}); +// example with minimum dimensions +var myCropper; + // will be started by modified iSelect (StopApply Function) -function changeRRDImage(){ +var StartDateString = 0; +var EndDateString = 0; - var RRDLeftDiff = 0; // difference between left border of RRD image and content - var RRDRightDiff = 0; // difference between right border of RRD image and content +function changeRRDImage(coords,dimensions){ + + var RRDLeftDiff = 50; // difference between left border of RRD image and content + var RRDRightDiff = 30; // difference between right border of RRD image and content var RRDImgWidth = 697; // Width of the Smokeping RRD Graphik var RRDImgUsable = 596; // 598 = 697 - 68 - 33; - - var oldimg = $("img#zoom"); - + var mySelectLeft = coords.x1; + var mySelectRight = coords.x2; + myURLObj = new urlObj(document.URL); // parse start and stop parameter from URL @@ -157,14 +111,26 @@ function changeRRDImage(){ var MinuteGenStart = ( Math.floor(floorGenStart / 60) * 60 ); var MinuteGenStop = ( Math.floor(floorGenStop / 60) * 60 ); - // create new image based on old image and fetched data - var newimg = new Image(); - newimg = oldimg; - StartDateString = JSToISODate(StartDate); EndDateString = JSToISODate(StopDate); // construct Image URL - newimg.attr("src",myURL + "?displaymode=a;start=" + StartDateString+ ";end=" + EndDateString + ";target=" + myRawTarget + ";serial=" + mySerial); + $('zoom').src = myURL + "?displaymode=a;start=" + StartDateString+ ";end=" + EndDateString + ";target=" + myRawTarget + ";serial=" + mySerial; + myCropper.setParams(); }; +Event.observe( + window, + 'load', + function() { + myCropper = new Cropper.Img( + 'zoom', + { + minHeight: 321, + maxHeight: 321, + onEndCrop: changeRRDImage + } + ) + } + ); + diff --git a/htdocs/js/idrag.js b/htdocs/js/idrag.js deleted file mode 100644 index d4b2c72..0000000 --- a/htdocs/js/idrag.js +++ /dev/null @@ -1,588 +0,0 @@ -/** - * Interface Elements for jQuery - * Draggable - * - * http://interface.eyecon.ro - * - * Copyright (c) 2006 Stefan Petre - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - */ - -/** - * Create a draggable element with a number of advanced options including callback, Google Maps type draggables, - * reversion, ghosting, and grid dragging. - * - * @name Draggable - * @descr Creates draggable elements that can be moved across the page. - * @param Hash hash A hash of parameters. All parameters are optional. - * @option String handle (optional) The jQuery selector matching the handle that starts the draggable - * @option DOMElement handle (optional) The DOM Element of the handle that starts the draggable - * @option Boolean revert (optional) When true, on stop-drag the element returns to initial position - * @option Boolean ghosting (optional) When true, a copy of the element is moved - * @option Integer zIndex (optional) zIndex depth for the element while it is being dragged - * @option Float opacity (optional) A number between 0 and 1 that indicates the opacity of the element while being dragged - * @option Integer grid (optional) (optional) A number of pixels indicating the grid that the element should snap to - * @option Array grid (optional) A number of x-pixels and y-pixels indicating the grid that the element should snap to - * @option Integer fx (optional) Duration for the effect (like ghosting or revert) applied to the draggable - * @option String containment (optional) Define the zone where the draggable can be moved. 'parent' moves it inside parent - * element, while 'document' prevents it from leaving the document and forcing additional - * scrolling - * @option Array containment An 4-element array (left, top, width, height) indicating the containment of the element - * @option String axis (optional) Set an axis: vertical (with 'vertically') or horizontal (with 'horizontally') - * @option Function onStart (optional) Callback function triggered when the dragging starts - * @option Function onStop (optional) Callback function triggered when the dragging stops - * @option Function onChange (optional) Callback function triggered when the dragging stop *and* the element was moved at least - * one pixel - * @option Function onDrag (optional) Callback function triggered while the element is dragged. Receives two parameters: x and y - * coordinates. You can return an object with new coordinates {x: x, y: y} so this way you can - * interact with the dragging process (for instance, build your containment) - * @option Boolean insideParent Forces the element to remain inside its parent when being dragged (like Google Maps) - * @option Integer snapDistance (optional) The element is not moved unless it is dragged more than snapDistance. You can prevent - * accidental dragging and keep regular clicking enabled (for links or form elements, - * for instance) - * @option Object cursorAt (optional) The dragged element is moved to the cursor position with the offset specified. Accepts value - * for top, left, right and bottom offset. Basically, this forces the cursor to a particular - * position during the entire drag operation. - * @option Boolean autoSize (optional) When true, the drag helper is resized to its content, instead of the dragged element's sizes - * @option String frameClass (optional) When is set the cloned element is hidden so only a frame is dragged - * @type jQuery - * @cat Plugins/Interface - * @author Stefan Petre - */ - -jQuery.iDrag = { - helper : null, - dragged: null, - destroy : function() - { - return this.each( - function () - { - if (this.isDraggable) { - this.dragCfg.dhe.unbind('mousedown', jQuery.iDrag.draginit); - this.dragCfg = null; - this.isDraggable = false; - if(jQuery.browser.msie) { - this.unselectable = "off"; - } else { - this.style.MozUserSelect = ''; - this.style.KhtmlUserSelect = ''; - this.style.userSelect = ''; - } - } - } - ); - }, - draginit : function (e) - { - if (jQuery.iDrag.dragged != null) { - jQuery.iDrag.dragstop(e); - return false; - } - var elm = this.dragElem; - jQuery(document) - .bind('mousemove', jQuery.iDrag.dragmove) - .bind('mouseup', jQuery.iDrag.dragstop); - elm.dragCfg.pointer = jQuery.iUtil.getPointer(e); - elm.dragCfg.currentPointer = elm.dragCfg.pointer; - elm.dragCfg.init = false; - elm.dragCfg.fromHandler = this != this.dragElem; - jQuery.iDrag.dragged = elm; - if (elm.dragCfg.si && this != this.dragElem) { - parentPos = jQuery.iUtil.getPosition(elm.parentNode); - sliderSize = jQuery.iUtil.getSize(elm); - sliderPos = { - x : parseInt(jQuery.css(elm,'left')) || 0, - y : parseInt(jQuery.css(elm,'top')) || 0 - }; - dx = elm.dragCfg.currentPointer.x - parentPos.x - sliderSize.wb/2 - sliderPos.x; - dy = elm.dragCfg.currentPointer.y - parentPos.y - sliderSize.hb/2 - sliderPos.y; - jQuery.iSlider.dragmoveBy(elm, [dx, dy]); - } - return jQuery.selectKeyHelper||false; - }, - - dragstart : function(e) - { - var elm = jQuery.iDrag.dragged; - elm.dragCfg.init = true; - - var dEs = elm.style; - - elm.dragCfg.oD = jQuery.css(elm,'display'); - elm.dragCfg.oP = jQuery.css(elm,'position'); - if (!elm.dragCfg.initialPosition) - elm.dragCfg.initialPosition = elm.dragCfg.oP; - - elm.dragCfg.oR = { - x : parseInt(jQuery.css(elm,'left')) || 0, - y : parseInt(jQuery.css(elm,'top')) || 0 - }; - elm.dragCfg.diffX = 0; - elm.dragCfg.diffY = 0; - if (jQuery.browser.msie) { - var oldBorder = jQuery.iUtil.getBorder(elm, true); - elm.dragCfg.diffX = oldBorder.l||0; - elm.dragCfg.diffY = oldBorder.t||0; - } - - elm.dragCfg.oC = jQuery.extend( - jQuery.iUtil.getPosition(elm), - jQuery.iUtil.getSize(elm) - ); - if (elm.dragCfg.oP != 'relative' && elm.dragCfg.oP != 'absolute') { - dEs.position = 'relative'; - } - - jQuery.iDrag.helper.empty(); - var clonedEl = elm.cloneNode(true); - - jQuery(clonedEl).css( - { - display: 'block', - left: '0px', - top: '0px' - } - ); - clonedEl.style.marginTop = '0'; - clonedEl.style.marginRight = '0'; - clonedEl.style.marginBottom = '0'; - clonedEl.style.marginLeft = '0'; - jQuery.iDrag.helper.append(clonedEl); - - var dhs = jQuery.iDrag.helper.get(0).style; - - if (elm.dragCfg.autoSize) { - dhs.width = 'auto'; - dhs.height = 'auto'; - } else { - dhs.height = elm.dragCfg.oC.hb + 'px'; - dhs.width = elm.dragCfg.oC.wb + 'px'; - } - - dhs.display = 'block'; - dhs.marginTop = '0px'; - dhs.marginRight = '0px'; - dhs.marginBottom = '0px'; - dhs.marginLeft = '0px'; - - //remeasure the clone to check if the size was changed by user's functions - jQuery.extend( - elm.dragCfg.oC, - jQuery.iUtil.getSize(clonedEl) - ); - - if (elm.dragCfg.cursorAt) { - if (elm.dragCfg.cursorAt.left) { - elm.dragCfg.oR.x += elm.dragCfg.pointer.x - elm.dragCfg.oC.x - elm.dragCfg.cursorAt.left; - elm.dragCfg.oC.x = elm.dragCfg.pointer.x - elm.dragCfg.cursorAt.left; - } - if (elm.dragCfg.cursorAt.top) { - elm.dragCfg.oR.y += elm.dragCfg.pointer.y - elm.dragCfg.oC.y - elm.dragCfg.cursorAt.top; - elm.dragCfg.oC.y = elm.dragCfg.pointer.y - elm.dragCfg.cursorAt.top; - } - if (elm.dragCfg.cursorAt.right) { - elm.dragCfg.oR.x += elm.dragCfg.pointer.x - elm.dragCfg.oC.x -elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.right; - elm.dragCfg.oC.x = elm.dragCfg.pointer.x - elm.dragCfg.oC.wb + elm.dragCfg.cursorAt.right; - } - if (elm.dragCfg.cursorAt.bottom) { - elm.dragCfg.oR.y += elm.dragCfg.pointer.y - elm.dragCfg.oC.y - elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.bottom; - elm.dragCfg.oC.y = elm.dragCfg.pointer.y - elm.dragCfg.oC.hb + elm.dragCfg.cursorAt.bottom; - } - } - elm.dragCfg.nx = elm.dragCfg.oR.x; - elm.dragCfg.ny = elm.dragCfg.oR.y; - - if (elm.dragCfg.insideParent || elm.dragCfg.containment == 'parent') { - parentBorders = jQuery.iUtil.getBorder(elm.parentNode, true); - elm.dragCfg.oC.x = elm.offsetLeft + (jQuery.browser.msie ? 0 : jQuery.browser.opera ? -parentBorders.l : parentBorders.l); - elm.dragCfg.oC.y = elm.offsetTop + (jQuery.browser.msie ? 0 : jQuery.browser.opera ? -parentBorders.t : parentBorders.t); - jQuery(elm.parentNode).append(jQuery.iDrag.helper.get(0)); - } - if (elm.dragCfg.containment) { - jQuery.iDrag.getContainment(elm); - elm.dragCfg.onDragModifier.containment = jQuery.iDrag.fitToContainer; - } - - if (elm.dragCfg.si) { - jQuery.iSlider.modifyContainer(elm); - } - - dhs.left = elm.dragCfg.oC.x - elm.dragCfg.diffX + 'px'; - dhs.top = elm.dragCfg.oC.y - elm.dragCfg.diffY + 'px'; - //resize the helper to fit the clone - dhs.width = elm.dragCfg.oC.wb + 'px'; - dhs.height = elm.dragCfg.oC.hb + 'px'; - - jQuery.iDrag.dragged.dragCfg.prot = false; - - if (elm.dragCfg.gx) { - elm.dragCfg.onDragModifier.grid = jQuery.iDrag.snapToGrid; - } - if (elm.dragCfg.zIndex != false) { - jQuery.iDrag.helper.css('zIndex', elm.dragCfg.zIndex); - } - if (elm.dragCfg.opacity) { - jQuery.iDrag.helper.css('opacity', elm.dragCfg.opacity); - if (window.ActiveXObject) { - jQuery.iDrag.helper.css('filter', 'alpha(opacity=' + elm.dragCfg.opacity * 100 + ')'); - } - } - - if(elm.dragCfg.frameClass) { - jQuery.iDrag.helper.addClass(elm.dragCfg.frameClass); - jQuery.iDrag.helper.get(0).firstChild.style.display = 'none'; - } - if (elm.dragCfg.onStart) - elm.dragCfg.onStart.apply(elm, [clonedEl, elm.dragCfg.oR.x, elm.dragCfg.oR.y]); - if (jQuery.iDrop && jQuery.iDrop.count > 0 ){ - jQuery.iDrop.highlight(elm); - } - if (elm.dragCfg.ghosting == false) { - dEs.display = 'none'; - } - return false; - }, - - getContainment : function(elm) - { - if (elm.dragCfg.containment.constructor == String) { - if (elm.dragCfg.containment == 'parent') { - elm.dragCfg.cont = jQuery.extend( - {x:0,y:0}, - jQuery.iUtil.getSize(elm.parentNode) - ); - var contBorders = jQuery.iUtil.getBorder(elm.parentNode, true); - elm.dragCfg.cont.w = elm.dragCfg.cont.wb - contBorders.l - contBorders.r; - elm.dragCfg.cont.h = elm.dragCfg.cont.hb - contBorders.t - contBorders.b; - } else if (elm.dragCfg.containment == 'document') { - var clnt = jQuery.iUtil.getClient(); - elm.dragCfg.cont = { - x : 0, - y : 0, - w : clnt.w, - h : clnt.h - }; - } - } else if (elm.dragCfg.containment.constructor == Array) { - elm.dragCfg.cont = { - x : parseInt(elm.dragCfg.containment[0])||0, - y : parseInt(elm.dragCfg.containment[1])||0, - w : parseInt(elm.dragCfg.containment[2])||0, - h : parseInt(elm.dragCfg.containment[3])||0 - }; - } - elm.dragCfg.cont.dx = elm.dragCfg.cont.x - elm.dragCfg.oC.x; - elm.dragCfg.cont.dy = elm.dragCfg.cont.y - elm.dragCfg.oC.y; - }, - - hidehelper : function(dragged) - { - if (dragged.dragCfg.insideParent || dragged.dragCfg.containment == 'parent') { - jQuery('body', document).append(jQuery.iDrag.helper.get(0)); - } - jQuery.iDrag.helper.empty().hide().css('opacity', 1); - if (window.ActiveXObject) { - jQuery.iDrag.helper.css('filter', 'alpha(opacity=100)'); - } - }, - - dragstop : function(e) - { - - jQuery(document) - .unbind('mousemove', jQuery.iDrag.dragmove) - .unbind('mouseup', jQuery.iDrag.dragstop); - - if (jQuery.iDrag.dragged == null) { - return; - } - var dragged = jQuery.iDrag.dragged; - - jQuery.iDrag.dragged = null; - - if (dragged.dragCfg.init == false) { - return false; - } - if (dragged.dragCfg.so == true) { - jQuery(dragged).css('position', dragged.dragCfg.oP); - } - var dEs = dragged.style; - - if (dragged.si) { - jQuery.iDrag.helper.css('cursor', 'move'); - } - if(dragged.dragCfg.frameClass) { - jQuery.iDrag.helper.removeClass(dragged.dragCfg.frameClass); - } - - if (dragged.dragCfg.revert == false) { - if (dragged.dragCfg.fx > 0) { - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally') { - var x = new jQuery.fx(dragged,{duration:dragged.dragCfg.fx}, 'left'); - x.custom(dragged.dragCfg.oR.x,dragged.dragCfg.nRx); - } - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically') { - var y = new jQuery.fx(dragged,{duration:dragged.dragCfg.fx}, 'top'); - y.custom(dragged.dragCfg.oR.y,dragged.dragCfg.nRy); - } - } else { - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally') - dragged.style.left = dragged.dragCfg.nRx + 'px'; - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically') - dragged.style.top = dragged.dragCfg.nRy + 'px'; - } - jQuery.iDrag.hidehelper(dragged); - if (dragged.dragCfg.ghosting == false) { - jQuery(dragged).css('display', dragged.dragCfg.oD); - } - } else if (dragged.dragCfg.fx > 0) { - dragged.dragCfg.prot = true; - var dh = false; - if(jQuery.iDrop && jQuery.iSort && dragged.dragCfg.so) { - dh = jQuery.iUtil.getPosition(jQuery.iSort.helper.get(0)); - } - jQuery.iDrag.helper.animate( - { - left : dh ? dh.x : dragged.dragCfg.oC.x, - top : dh ? dh.y : dragged.dragCfg.oC.y - }, - dragged.dragCfg.fx, - function() - { - dragged.dragCfg.prot = false; - if (dragged.dragCfg.ghosting == false) { - dragged.style.display = dragged.dragCfg.oD; - } - jQuery.iDrag.hidehelper(dragged); - } - ); - } else { - jQuery.iDrag.hidehelper(dragged); - if (dragged.dragCfg.ghosting == false) { - jQuery(dragged).css('display', dragged.dragCfg.oD); - } - } - - if (jQuery.iDrop && jQuery.iDrop.count > 0 ){ - jQuery.iDrop.checkdrop(dragged); - } - if (jQuery.iSort && dragged.dragCfg.so) { - jQuery.iSort.check(dragged); - } - if (dragged.dragCfg.onChange && (dragged.dragCfg.nRx != dragged.dragCfg.oR.x || dragged.dragCfg.nRy != dragged.dragCfg.oR.y)){ - dragged.dragCfg.onChange.apply(dragged, dragged.dragCfg.lastSi||[0,0,dragged.dragCfg.nRx,dragged.dragCfg.nRy]); - } - if (dragged.dragCfg.onStop) - dragged.dragCfg.onStop.apply(dragged); - return false; - }, - - snapToGrid : function(x, y, dx, dy) - { - if (dx != 0) - dx = parseInt((dx + (this.dragCfg.gx * dx/Math.abs(dx))/2)/this.dragCfg.gx) * this.dragCfg.gx; - if (dy != 0) - dy = parseInt((dy + (this.dragCfg.gy * dy/Math.abs(dy))/2)/this.dragCfg.gy) * this.dragCfg.gy; - return { - dx : dx, - dy : dy, - x: 0, - y: 0 - }; - }, - - fitToContainer : function(x, y, dx, dy) - { - dx = Math.min( - Math.max(dx,this.dragCfg.cont.dx), - this.dragCfg.cont.w + this.dragCfg.cont.dx - this.dragCfg.oC.wb - ); - dy = Math.min( - Math.max(dy,this.dragCfg.cont.dy), - this.dragCfg.cont.h + this.dragCfg.cont.dy - this.dragCfg.oC.hb - ); - - return { - dx : dx, - dy : dy, - x: 0, - y: 0 - } - }, - - dragmove : function(e) - { - if (jQuery.iDrag.dragged == null || jQuery.iDrag.dragged.dragCfg.prot == true) { - return; - } - - var dragged = jQuery.iDrag.dragged; - - dragged.dragCfg.currentPointer = jQuery.iUtil.getPointer(e); - if (dragged.dragCfg.init == false) { - distance = Math.sqrt(Math.pow(dragged.dragCfg.pointer.x - dragged.dragCfg.currentPointer.x, 2) + Math.pow(dragged.dragCfg.pointer.y - dragged.dragCfg.currentPointer.y, 2)); - if (distance < dragged.dragCfg.snapDistance){ - return; - } else { - jQuery.iDrag.dragstart(e); - } - } - - var dx = dragged.dragCfg.currentPointer.x - dragged.dragCfg.pointer.x; - var dy = dragged.dragCfg.currentPointer.y - dragged.dragCfg.pointer.y; - - for (var i in dragged.dragCfg.onDragModifier) { - var newCoords = dragged.dragCfg.onDragModifier[i].apply(dragged, [dragged.dragCfg.oR.x + dx, dragged.dragCfg.oR.y + dy, dx, dy]); - if (newCoords && newCoords.constructor == Object) { - dx = i != 'user' ? newCoords.dx : (newCoords.x - dragged.dragCfg.oR.x); - dy = i != 'user' ? newCoords.dy : (newCoords.y - dragged.dragCfg.oR.y); - } - } - - dragged.dragCfg.nx = dragged.dragCfg.oC.x + dx - dragged.dragCfg.diffX; - dragged.dragCfg.ny = dragged.dragCfg.oC.y + dy - dragged.dragCfg.diffY; - - if (dragged.dragCfg.si && (dragged.dragCfg.onSlide || dragged.dragCfg.onChange)) { - jQuery.iSlider.onSlide(dragged, dragged.dragCfg.nx, dragged.dragCfg.ny); - } - - if(dragged.dragCfg.onDrag) - dragged.dragCfg.onDrag.apply(dragged, [dragged.dragCfg.oR.x + dx, dragged.dragCfg.oR.y + dy]); - - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'horizontally') { - dragged.dragCfg.nRx = dragged.dragCfg.oR.x + dx; - jQuery.iDrag.helper.get(0).style.left = dragged.dragCfg.nx + 'px'; - } - if (!dragged.dragCfg.axis || dragged.dragCfg.axis == 'vertically') { - dragged.dragCfg.nRy = dragged.dragCfg.oR.y + dy; - jQuery.iDrag.helper.get(0).style.top = dragged.dragCfg.ny + 'px'; - } - - if (jQuery.iDrop && jQuery.iDrop.count > 0 ){ - jQuery.iDrop.checkhover(dragged); - } - return false; - }, - - build : function(o) - { - if (!jQuery.iDrag.helper) { - jQuery('body',document).append('<div id="dragHelper"></div>'); - jQuery.iDrag.helper = jQuery('#dragHelper'); - var el = jQuery.iDrag.helper.get(0); - var els = el.style; - els.position = 'absolute'; - els.display = 'none'; - els.cursor = 'move'; - els.listStyle = 'none'; - els.overflow = 'hidden'; - if (window.ActiveXObject) { - el.unselectable = "on"; - } else { - els.mozUserSelect = 'none'; - els.userSelect = 'none'; - els.KhtmlUserSelect = 'none'; - } - } - if (!o) { - o = {}; - } - return this.each( - function() - { - if (this.isDraggable || !jQuery.iUtil) - return; - if (window.ActiveXObject) { - this.onselectstart = function(){return false;}; - this.ondragstart = function(){return false;}; - } - var el = this; - var dhe = o.handle ? jQuery(this).find(o.handle) : jQuery(this); - if(jQuery.browser.msie) { - dhe.each( - function() - { - this.unselectable = "on"; - } - ); - } else { - dhe.css('-moz-user-select', 'none'); - dhe.css('user-select', 'none'); - dhe.css('-khtml-user-select', 'none'); - } - this.dragCfg = { - dhe: dhe, - revert : o.revert ? true : false, - ghosting : o.ghosting ? true : false, - so : o.so ? o.so : false, - si : o.si ? o.si : false, - insideParent : o.insideParent ? o.insideParent : false, - zIndex : o.zIndex ? parseInt(o.zIndex)||0 : false, - opacity : o.opacity ? parseFloat(o.opacity) : false, - fx : parseInt(o.fx)||null, - hpc : o.hpc ? o.hpc : false, - onDragModifier : {}, - pointer : {}, - onStart : o.onStart && o.onStart.constructor == Function ? o.onStart : false, - onStop : o.onStop && o.onStop.constructor == Function ? o.onStop : false, - onChange : o.onChange && o.onChange.constructor == Function ? o.onChange : false, - axis : /vertically|horizontally/.test(o.axis) ? o.axis : false, - snapDistance : o.snapDistance ? parseInt(o.snapDistance)||0 : 0, - cursorAt: o.cursorAt ? o.cursorAt : false, - autoSize : o.autoSize ? true : false, - frameClass : o.frameClass || false - - }; - if (o.onDragModifier && o.onDragModifier.constructor == Function) - this.dragCfg.onDragModifier.user = o.onDragModifier; - if (o.onDrag && o.onDrag.constructor == Function) - this.dragCfg.onDrag = o.onDrag; - if (o.containment && ((o.containment.constructor == String && (o.containment == 'parent' || o.containment == 'document')) || (o.containment.constructor == Array && o.containment.length == 4) )) { - this.dragCfg.containment = o.containment; - } - if(o.fractions) { - this.dragCfg.fractions = o.fractions; - } - if(o.grid){ - if(typeof o.grid == 'number'){ - this.dragCfg.gx = parseInt(o.grid)||1; - this.dragCfg.gy = parseInt(o.grid)||1; - } else if (o.grid.length == 2) { - this.dragCfg.gx = parseInt(o.grid[0])||1; - this.dragCfg.gy = parseInt(o.grid[1])||1; - } - } - if (o.onSlide && o.onSlide.constructor == Function) { - this.dragCfg.onSlide = o.onSlide; - } - - this.isDraggable = true; - dhe.each( - function(){ - this.dragElem = el; - } - ); - dhe.bind('mousedown', jQuery.iDrag.draginit); - } - ) - } -}; - -/** - * Destroy an existing draggable on a collection of elements - * - * @name DraggableDestroy - * @descr Destroy a draggable - * @type jQuery - * @cat Plugins/Interface - * @example $('#drag2').DraggableDestroy(); - */ - -jQuery.fn.extend( - { - DraggableDestroy : jQuery.iDrag.destroy, - Draggable : jQuery.iDrag.build - } -);
\ No newline at end of file diff --git a/htdocs/js/iutil.js b/htdocs/js/iutil.js deleted file mode 100644 index 05a5b04..0000000 --- a/htdocs/js/iutil.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Interface Elements for jQuery - * utility function - * - * http://interface.eyecon.ro - * - * Copyright (c) 2006 Stefan Petre - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * - */ -eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('9.J={1C:6(e){4 x=0;4 y=0;4 7=e.Y;4 12=1H;c(9(e).8(\'A\')==\'T\'){4 N=7.B;4 Q=7.z;12=1f;7.B=\'1r\';7.A=\'1q\';7.z=\'1d\'}4 3=e;R(3){x+=3.1h+(3.O&&!9.1m.1i?d(3.O.17)||0:0);y+=3.1n+(3.O&&!9.1m.1i?d(3.O.18)||0:0);3=3.1t}3=e;R(3&&3.1e&&3.1e.16()!=\'f\'){x-=3.u||0;y-=3.F||0;3=3.1D}c(12==1f){7.A=\'T\';7.z=Q;7.B=N}a{x:x,y:y}},1B:6(3){4 x=0,y=0;R(3){x+=3.1h||0;y+=3.1n||0;3=3.1t}a{x:x,y:y}},1s:6(e){4 w=9.8(e,\'1E\');4 h=9.8(e,\'1G\');4 o=0;4 q=0;4 7=e.Y;c(9(e).8(\'A\')!=\'T\'){o=e.V;q=e.U}p{4 N=7.B;4 Q=7.z;7.B=\'1r\';7.A=\'1q\';7.z=\'1d\';o=e.V;q=e.U;7.A=\'T\';7.z=Q;7.B=N}a{w:w,h:h,o:o,q:q}},1F:6(3){a{o:3.V||0,q:3.U||0}},1I:6(e){4 h,w,C;c(e){w=e.I;h=e.G}p{C=5.j;w=1c.14||P.14||(C&&C.I)||5.f.I;h=1c.10||P.10||(C&&C.G)||5.f.G}a{w:w,h:h}},1p:6(e){4 t=0,l=0,w=0,h=0,s=0,E=0;c(e&&e.1u.16()!=\'f\'){t=e.F;l=e.u;w=e.15;h=e.W;s=0;E=0}p{c(5.j){t=5.j.F;l=5.j.u;w=5.j.15;h=5.j.W}p c(5.f){t=5.f.F;l=5.f.u;w=5.f.15;h=5.f.W}s=P.14||5.j.I||5.f.I||0;E=P.10||5.j.G||5.f.G||0}a{t:t,l:l,w:w,h:h,s:s,E:E}},1v:6(e,D){4 3=9(e);4 t=3.8(\'1w\')||\'\';4 r=3.8(\'1x\')||\'\';4 b=3.8(\'1A\')||\'\';4 l=3.8(\'1z\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)};p a{t:t,r:r,b:b,l:l}},1y:6(e,D){4 3=9(e);4 t=3.8(\'1J\')||\'\';4 r=3.8(\'1M\')||\'\';4 b=3.8(\'27\')||\'\';4 l=3.8(\'28\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)};p a{t:t,r:r,b:b,l:l}},26:6(e,D){4 3=9(e);4 t=3.8(\'18\')||\'\';4 r=3.8(\'22\')||\'\';4 b=3.8(\'23\')||\'\';4 l=3.8(\'17\')||\'\';c(D)a{t:d(t)||0,r:d(r)||0,b:d(b)||0,l:d(l)||0};p a{t:t,r:r,b:b,l:l}},2e:6(L){4 x=L.2d||(L.2b+(5.j.u||5.f.u))||0;4 y=L.2c||(L.29+(5.j.F||5.f.F))||0;a{x:x,y:y}},X:6(g,13){13(g);g=g.1O;R(g){9.J.X(g,13);g=g.1L}},1N:6(g){9.J.X(g,6(3){19(4 Z 1T 3){c(1Z 3[Z]===\'6\'){3[Z]=1a}}})},1X:6(3,H){4 k=9.J.1p();4 11=9.J.1s(3);c(!H||H==\'1W\')9(3).8({1U:k.t+((1g.1o(k.h,k.E)-k.t-11.q)/2)+\'1j\'});c(!H||H==\'20\')9(3).8({1Y:k.l+((1g.1o(k.w,k.s)-k.l-11.o)/2)+\'1j\'})},2f:6(3,1l){4 1k=9(\'25[@M*="S"]\',3||5),S;1k.24(6(){S=K.M;K.M=1l;K.Y.2a="21:1R.1P.1V(M=\'"+S+"\')"})}};[].1b||(1S.1Q.1b=6(v,n){n=(n==1a)?0:n;4 m=K.1K;19(4 i=n;i<m;i++)c(K[i]==v)a i;a-1});',62,140,'|||el|var|document|function|es|css|jQuery|return||if|parseInt||body|nodeEl|||documentElement|clientScroll||||wb|else|hb||iw||scrollLeft|||||position|display|visibility|de|toInteger|ih|scrollTop|clientHeight|axis|clientWidth|iUtil|this|event|src|oldVisibility|currentStyle|self|oldPosition|while|png|none|offsetHeight|offsetWidth|scrollHeight|traverseDOM|style|attr|innerHeight|windowSize|restoreStyles|func|innerWidth|scrollWidth|toLowerCase|borderLeftWidth|borderTopWidth|for|null|indexOf|window|absolute|tagName|true|Math|offsetLeft|opera|px|images|emptyGIF|browser|offsetTop|max|getScroll|block|hidden|getSize|offsetParent|nodeName|getMargins|marginTop|marginRight|getPadding|marginLeft|marginBottom|getPositionLite|getPosition|parentNode|width|getSizeLite|height|false|getClient|paddingTop|length|nextSibling|paddingRight|purgeEvents|firstChild|Microsoft|prototype|DXImageTransform|Array|in|top|AlphaImageLoader|vertically|centerEl|left|typeof|horizontally|progid|borderRightWidth|borderBottomWidth|each|img|getBorder|paddingBottom|paddingLeft|clientY|filter|clientX|pageY|pageX|getPointer|fixPNG'.split('|'),0,{})) diff --git a/htdocs/js/jquery.dimensions.js b/htdocs/js/jquery.dimensions.js deleted file mode 100644 index 967049a..0000000 --- a/htdocs/js/jquery.dimensions.js +++ /dev/null @@ -1,12 +0,0 @@ -/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) - * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) - * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. - * - * $LastChangedDate: 2007-08-17 13:14:11 -0500 (Fri, 17 Aug 2007) $ - * $Rev: 2759 $ - * - * Version: 1.1.2 - * - * Requires: jQuery 1.1.3+ - */ -eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(9($){l e=$.1q.C,r=$.1q.r;$.1q.M({C:9(){3(!1[0])f();3(1[0]==p)3($.7.O||($.7.E&&U($.7.13)>11))6 n.19-(($(5).C()>n.19)?i():0);k 3($.7.E)6 n.19;k 6 $.I&&5.P.1E||5.o.1E;3(1[0]==5)6 1C.1y(($.I&&5.P.1w||5.o.1w),5.o.1u);6 e.1T(1,1P)},r:9(){3(!1[0])f();3(1[0]==p)3($.7.O||($.7.E&&U($.7.13)>11))6 n.1b-(($(5).r()>n.1b)?i():0);k 3($.7.E)6 n.1b;k 6 $.I&&5.P.1N||5.o.1N;3(1[0]==5)3($.7.1M){l a=n.1p;n.1a(27,n.1o);l b=n.1p;n.1a(a,n.1o);6 5.o.1c+b}k 6 1C.1y((($.I&&!$.7.E)&&5.P.1L||5.o.1L),5.o.1c);6 r.1T(1,1P)},19:9(){3(!1[0])f();6 1[0]==p||1[0]==5?1.C():1.14(\':N\')?1[0].1u-h(1,\'q\')-h(1,\'1I\'):1.C()+h(1,\'1h\')+h(1,\'1H\')},1b:9(){3(!1[0])f();6 1[0]==p||1[0]==5?1.r():1.14(\':N\')?1[0].1c-h(1,\'s\')-h(1,\'1F\'):1.r()+h(1,\'1v\')+h(1,\'1D\')},21:9(a){3(!1[0])f();a=$.M({A:w},a||{});6 1[0]==p||1[0]==5?1.C():1.14(\':N\')?1[0].1u+(a.A?(h(1,\'L\')+h(1,\'1x\')):0):1.C()+h(1,\'q\')+h(1,\'1I\')+h(1,\'1h\')+h(1,\'1H\')+(a.A?(h(1,\'L\')+h(1,\'1x\')):0)},1Y:9(a){3(!1[0])f();a=$.M({A:w},a||{});6 1[0]==p||1[0]==5?1.r():1.14(\':N\')?1[0].1c+(a.A?(h(1,\'K\')+h(1,\'1U\')):0):1.r()+h(1,\'s\')+h(1,\'1F\')+h(1,\'1v\')+h(1,\'1D\')+(a.A?(h(1,\'K\')+h(1,\'1U\')):0)},m:9(a){3(!1[0])f();3(a!=1S)6 1.1Q(9(){3(1==p||1==5)p.1a(a,$(p).u());k 1.m=a});3(1[0]==p||1[0]==5)6 n.1p||$.I&&5.P.m||5.o.m;6 1[0].m},u:9(a){3(!1[0])f();3(a!=1S)6 1.1Q(9(){3(1==p||1==5)p.1a($(p).m(),a);k 1.u=a});3(1[0]==p||1[0]==5)6 n.1o||$.I&&5.P.u||5.o.u;6 1[0].u},12:9(a){6 1.1O({A:w,J:w,v:1.z()},a)},1O:9(b,c){3(!1[0])f();l x=0,y=0,H=0,G=0,8=1[0],4=1[0],T,10,Z=$.D(8,\'12\'),F=$.7.1M,S=$.7.26,18=$.7.O,1n=$.7.E,R=$.7.E&&U($.7.13)>11,1m=w,1l=w,b=$.M({A:Q,15:w,1k:w,J:Q,1K:w,v:5.o},b||{});3(b.1K)6 1.1J(b,c);3(b.v.1j)b.v=b.v[0];3(8.B==\'Y\'){x=8.V;y=8.X;3(F){x+=h(8,\'K\')+(h(8,\'s\')*2);y+=h(8,\'L\')+(h(8,\'q\')*2)}k 3(18){x+=h(8,\'K\');y+=h(8,\'L\')}k 3((S&&1g.I)){x+=h(8,\'s\');y+=h(8,\'q\')}k 3(R){x+=h(8,\'K\')+h(8,\'s\');y+=h(8,\'L\')+h(8,\'q\')}}k{17{10=$.D(4,\'12\');x+=4.V;y+=4.X;3((F&&!4.B.1G(/^t[d|h]$/i))||S||R){x+=h(4,\'s\');y+=h(4,\'q\');3(F&&10==\'1i\')1m=Q;3(S&&10==\'25\')1l=Q}T=4.z||5.o;3(b.J||F){17{3(b.J){H+=4.m;G+=4.u}3(18&&($.D(4,\'24\')||\'\').1G(/23-22|20/)){H=H-((4.m==4.V)?4.m:0);G=G-((4.u==4.X)?4.u:0)}3(F&&4!=8&&$.D(4,\'1e\')!=\'N\'){x+=h(4,\'s\');y+=h(4,\'q\')}4=4.1B}W(4!=T)}4=T;3(4==b.v&&!(4.B==\'Y\'||4.B==\'1d\')){3(F&&4!=8&&$.D(4,\'1e\')!=\'N\'){x+=h(4,\'s\');y+=h(4,\'q\')}3(((1n&&!R)||18)&&10!=\'1r\'){x-=h(T,\'s\');y-=h(T,\'q\')}1A}3(4.B==\'Y\'||4.B==\'1d\'){3(((1n&&!R)||(S&&$.I))&&Z!=\'1i\'&&Z!=\'1z\'){x+=h(4,\'K\');y+=h(4,\'L\')}3(R||(F&&!1m&&Z!=\'1z\')||(S&&Z==\'1r\'&&!1l)){x+=h(4,\'s\');y+=h(4,\'q\')}1A}}W(4)}l a=j(8,b,x,y,H,G);3(c){$.M(c,a);6 1}k{6 a}},1J:9(b,c){3(!1[0])f();l x=0,y=0,H=0,G=0,4=1[0],z,b=$.M({A:Q,15:w,1k:w,J:Q,v:5.o},b||{});3(b.v.1j)b.v=b.v[0];17{x+=4.V;y+=4.X;z=4.z||5.o;3(b.J){17{H+=4.m;G+=4.u;4=4.1B}W(4!=z)}4=z}W(4&&4.B!=\'Y\'&&4.B!=\'1d\'&&4!=b.v);l a=j(1[0],b,x,y,H,G);3(c){$.M(c,a);6 1}k{6 a}},z:9(){3(!1[0])f();l a=1[0].z;W(a&&(a.B!=\'Y\'&&$.D(a,\'12\')==\'1r\'))a=a.z;6 $(a)}});l f=9(){1Z"1X: 1g 1W 14 1V";};l h=9(a,b){6 U($.D(a.1j?a[0]:a,b))||0};l j=9(a,b,x,y,d,c){3(!b.A){x-=h(a,\'K\');y-=h(a,\'L\')}3(b.15&&(($.7.E&&U($.7.13)<11)||$.7.O)){x+=h(a,\'s\');y+=h(a,\'q\')}k 3(!b.15&&!(($.7.E&&U($.7.13)<11)||$.7.O)){x-=h(a,\'s\');y-=h(a,\'q\')}3(b.1k){x+=h(a,\'1v\');y+=h(a,\'1h\')}3(b.J&&(!$.7.O||a.V!=a.m&&a.X!=a.m)){d-=a.m;c-=a.u}6 b.J?{1f:y-c,1t:x-d,u:c,m:d}:{1f:y,1t:x}};l g=0;l i=9(){3(!g){l a=$(\'<1s>\').D({r:16,C:16,1e:\'2d\',12:\'1i\',1f:-1R,1t:-1R}).2c(\'o\');g=16-a.2b(\'<1s>\').2a(\'1s\').D({r:\'16%\',C:29}).r();a.28()}6 g}})(1g);',62,138,'|this||if|parent|document|return|browser|elem|function|||||||||||else|var|scrollLeft|self|body|window|borderTopWidth|width|borderLeftWidth||scrollTop|relativeTo|false|||offsetParent|margin|tagName|height|css|safari|mo|st|sl|boxModel|scroll|marginLeft|marginTop|extend|visible|opera|documentElement|true|sf3|ie|op|parseInt|offsetLeft|while|offsetTop|BODY|elemPos|parPos|520|position|version|is|border|100|do|oa|innerHeight|scrollTo|innerWidth|offsetWidth|HTML|overflow|top|jQuery|paddingTop|absolute|jquery|padding|relparent|absparent|sf|pageYOffset|pageXOffset|fn|static|div|left|offsetHeight|paddingLeft|scrollHeight|marginBottom|max|fixed|break|parentNode|Math|paddingRight|clientHeight|borderRightWidth|match|paddingBottom|borderBottomWidth|offsetLite|lite|scrollWidth|mozilla|clientWidth|offset|arguments|each|1000|undefined|apply|marginRight|empty|collection|Dimensions|outerWidth|throw|inline|outerHeight|row|table|display|relative|msie|99999999|remove|200|find|append|appendTo|auto'.split('|'),0,{}))
\ No newline at end of file diff --git a/htdocs/js/jquery.js b/htdocs/js/jquery.js deleted file mode 100644 index f364720..0000000 --- a/htdocs/js/jquery.js +++ /dev/null @@ -1,11 +0,0 @@ -/* - * jQuery 1.1.3.1 - New Wave Javascript - * - * Copyright (c) 2007 John Resig (jquery.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date: 2007-07-05 00:43:24 -0400 (Thu, 05 Jul 2007) $ - * $Rev: 2243 $ - */ -eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7(1g 18.6=="I"){18.I=18.I;u 6=q(a,c){7(18==9||!9.3X)v 14 6(a,c);v 9.3X(a,c)};7(1g $!="I")6.1I$=$;u $=6;6.11=6.8r={3X:q(a,c){a=a||P;7(6.16(a))v 14 6(P)[6.11.1G?"1G":"1W"](a);7(1g a=="1s"){u m=/^[^<]*(<(.|\\s)+>)[^>]*$/.1V(a);7(m)a=6.31([m[1]]);B v 14 6(c).1L(a)}v 9.4E(a.15==2b&&a||(a.3C||a.C&&a!=18&&!a.1q&&a[0]!=I&&a[0].1q)&&6.2L(a)||[a])},3C:"1.1.3.1",7W:q(){v 9.C},C:0,1M:q(a){v a==I?6.2L(9):9[a]},1Z:q(a){u b=6(a);b.5q=9;v b},4E:q(a){9.C=0;[].R.O(9,a);v 9},F:q(a,b){v 6.F(9,a,b)},2p:q(a){u b=-1;9.F(q(i){7(9==a)b=i});v b},1b:q(f,d,e){u c=f;7(f.15==33)7(d==I)v 9.C&&6[e||"1b"](9[0],f)||I;B{c={};c[f]=d}v 9.F(q(a){E(u b V c)6.1b(e?9.T:9,b,6.4H(9,c[b],e,a,b))})},1f:q(b,a){v 9.1b(b,a,"2z")},2A:q(e){7(1g e=="1s")v 9.2Y().3e(P.66(e));u t="";6.F(e||9,q(){6.F(9.2S,q(){7(9.1q!=8)t+=9.1q!=1?9.5R:6.11.2A([9])})});v t},8b:q(){u a,1S=19;v 9.F(q(){7(!a)a=6.31(1S,9.2O);u b=a[0].3s(K);9.L.2K(b,9);1v(b.1d)b=b.1d;b.4g(9)})},3e:q(){v 9.2F(19,K,1,q(a){9.4g(a)})},5w:q(){v 9.2F(19,K,-1,q(a){9.2K(a,9.1d)})},5t:q(){v 9.2F(19,N,1,q(a){9.L.2K(a,9)})},5s:q(){v 9.2F(19,N,-1,q(a){9.L.2K(a,9.1X)})},2U:q(){v 9.5q||6([])},1L:q(t){u b=6.3k(9,q(a){v 6.1L(t,a)});v 9.1Z(/[^+>] [^+>]/.17(t)||t.J("..")>-1?6.5g(b):b)},7x:q(e){u d=9.1A(9.1L("*"));d.F(q(){9.1I$1a={};E(u a V 9.$1a)9.1I$1a[a]=6.1c({},9.$1a[a])}).3U();u r=9.1Z(6.3k(9,q(a){v a.3s(e!=I?e:K)}));d.F(q(){u b=9.1I$1a;E(u a V b)E(u c V b[a])6.S.1A(9,a,b[a][c],b[a][c].W);9.1I$1a=H});v r},1i:q(t){v 9.1Z(6.16(t)&&6.2s(9,q(b,a){v t.O(b,[a])})||6.2x(t,9))},4Y:q(t){v 9.1Z(t.15==33&&6.2x(t,9,K)||6.2s(9,q(a){v(t.15==2b||t.3C)?6.2w(a,t)<0:a!=t}))},1A:q(t){v 9.1Z(6.1T(9.1M(),t.15==33?6(t).1M():t.C!=I&&(!t.Q||t.Q=="6Z")?t:[t]))},37:q(a){v a?6.2x(a,9).C>0:N},6R:q(a){v a==I?(9.C?9[0].2v:H):9.1b("2v",a)},3F:q(a){v a==I?(9.C?9[0].27:H):9.2Y().3e(a)},2F:q(f,d,g,e){u c=9.C>1,a;v 9.F(q(){7(!a){a=6.31(f,9.2O);7(g<0)a.6E()}u b=9;7(d&&6.Q(9,"1r")&&6.Q(a[0],"2V"))b=9.3R("1z")[0]||9.4g(P.5h("1z"));6.F(a,q(){e.O(b,[c?9.3s(K):9])})})}};6.1c=6.11.1c=q(){u c=19[0],a=1;7(19.C==1){c=9;a=0}u b;1v((b=19[a++])!=H)E(u i V b)c[i]=b[i];v c};6.1c({6n:q(){7(6.1I$)$=6.1I$;v 6},16:q(a){v!!a&&1g a!="1s"&&!a.Q&&a.15!=2b&&/q/i.17(a+"")},40:q(a){v a.4z&&a.2O&&!a.2O.4y},Q:q(b,a){v b.Q&&b.Q.1D()==a.1D()},F:q(a,b,c){7(a.C==I)E(u i V a)b.O(a[i],c||[i,a[i]]);B E(u i=0,4x=a.C;i<4x;i++)7(b.O(a[i],c||[i,a[i]])===N)1F;v a},4H:q(c,b,d,e,a){7(6.16(b))b=b.3D(c,[e]);u f=/z-?2p|5Y-?8p|1e|5U|8i-?1u/i;v b&&b.15==3y&&d=="2z"&&!f.17(a)?b+"4o":b},12:{1A:q(b,c){6.F(c.2R(/\\s+/),q(i,a){7(!6.12.3w(b.12,a))b.12+=(b.12?" ":"")+a})},1E:q(b,c){b.12=c!=I?6.2s(b.12.2R(/\\s+/),q(a){v!6.12.3w(c,a)}).5M(" "):""},3w:q(t,c){v 6.2w(c,(t.12||t).3v().2R(/\\s+/))>-1}},4m:q(e,o,f){E(u i V o){e.T["2N"+i]=e.T[i];e.T[i]=o[i]}f.O(e,[]);E(u i V o)e.T[i]=e.T["2N"+i]},1f:q(e,p){7(p=="1u"||p=="29"){u b={},3r,3p,d=["83","81","80","7Y"];6.F(d,q(){b["7V"+9]=0;b["7T"+9+"7S"]=0});6.4m(e,b,q(){7(6(e).37(\':4f\')){3r=e.7Q;3p=e.7O}B{e=6(e.3s(K)).1L(":4b").5v("2B").2U().1f({48:"1y",3i:"7L",U:"2h",7K:"0",7I:"0"}).5o(e.L)[0];u a=6.1f(e.L,"3i")||"3n";7(a=="3n")e.L.T.3i="7G";3r=e.7E;3p=e.7D;7(a=="3n")e.L.T.3i="3n";e.L.3q(e)}});v p=="1u"?3r:3p}v 6.2z(e,p)},2z:q(e,a,d){u g;7(a=="1e"&&6.M.1h){g=6.1b(e.T,"1e");v g==""?"1":g}7(a.3t(/3x/i))a=6.1U;7(!d&&e.T[a])g=e.T[a];B 7(P.3f&&P.3f.3Y){7(a.3t(/3x/i))a="3x";a=a.1o(/([A-Z])/g,"-$1").2H();u b=P.3f.3Y(e,H);7(b)g=b.57(a);B 7(a=="U")g="1P";B 6.4m(e,{U:"2h"},q(){u c=P.3f.3Y(9,"");g=c&&c.57(a)||""})}B 7(e.3S){u f=a.1o(/\\-(\\w)/g,q(m,c){v c.1D()});g=e.3S[a]||e.3S[f]}v g},31:q(a,c){u r=[];c=c||P;6.F(a,q(i,b){7(!b)v;7(b.15==3y)b=b.3v();7(1g b=="1s"){u s=6.2C(b).2H(),1x=c.5h("1x"),1N=[];u a=!s.J("<1H")&&[1,"<2y>","</2y>"]||!s.J("<7g")&&[1,"<52>","</52>"]||(!s.J("<7c")||!s.J("<1z")||!s.J("<7a")||!s.J("<78"))&&[1,"<1r>","</1r>"]||!s.J("<2V")&&[2,"<1r><1z>","</1z></1r>"]||(!s.J("<75")||!s.J("<74"))&&[3,"<1r><1z><2V>","</2V></1z></1r>"]||!s.J("<73")&&[2,"<1r><4W>","</4W></1r>"]||[0,"",""];1x.27=a[1]+b+a[2];1v(a[0]--)1x=1x.1d;7(6.M.1h){7(!s.J("<1r")&&s.J("<1z")<0)1N=1x.1d&&1x.1d.2S;B 7(a[1]=="<1r>"&&s.J("<1z")<0)1N=1x.2S;E(u n=1N.C-1;n>=0;--n)7(6.Q(1N[n],"1z")&&!1N[n].2S.C)1N[n].L.3q(1N[n])}b=6.2L(1x.2S)}7(0===b.C&&(!6.Q(b,"34")&&!6.Q(b,"2y")))v;7(b[0]==I||6.Q(b,"34")||b.71)r.R(b);B r=6.1T(r,b)});v r},1b:q(c,d,a){u e=6.40(c)?{}:6.3H;7(e[d]){7(a!=I)c[e[d]]=a;v c[e[d]]}B 7(a==I&&6.M.1h&&6.Q(c,"34")&&(d=="70"||d=="6Y"))v c.6W(d).5R;B 7(c.4z){7(a!=I)c.6U(d,a);7(6.M.1h&&/4M|2u/.17(d)&&!6.40(c))v c.35(d,2);v c.35(d)}B{7(d=="1e"&&6.M.1h){7(a!=I){c.5U=1;c.1i=(c.1i||"").1o(/4L\\([^)]*\\)/,"")+(39(a).3v()=="6M"?"":"4L(1e="+a*4X+")")}v c.1i?(39(c.1i.3t(/1e=([^)]*)/)[1])/4X).3v():""}d=d.1o(/-([a-z])/6K,q(z,b){v b.1D()});7(a!=I)c[d]=a;v c[d]}},2C:q(t){v t.1o(/^\\s+|\\s+$/g,"")},2L:q(a){u r=[];7(1g a!="6I")E(u i=0,26=a.C;i<26;i++)r.R(a[i]);B r=a.51(0);v r},2w:q(b,a){E(u i=0,26=a.C;i<26;i++)7(a[i]==b)v i;v-1},1T:q(a,b){E(u i=0;b[i];i++)a.R(b[i]);v a},5g:q(a){u r=[],3P=6.1k++;E(u i=0,4G=a.C;i<4G;i++)7(3P!=a[i].1k){a[i].1k=3P;r.R(a[i])}v r},1k:0,2s:q(c,b,d){7(1g b=="1s")b=14 45("a","i","v "+b);u a=[];E(u i=0,30=c.C;i<30;i++)7(!d&&b(c[i],i)||d&&!b(c[i],i))a.R(c[i]);v a},3k:q(c,b){7(1g b=="1s")b=14 45("a","v "+b);u d=[];E(u i=0,30=c.C;i<30;i++){u a=b(c[i],i);7(a!==H&&a!=I){7(a.15!=2b)a=[a];d=d.6v(a)}}v d}});14 q(){u b=6u.6t.2H();6.M={4D:(b.3t(/.+(?:6s|6q|6o|6m)[\\/: ]([\\d.]+)/)||[])[1],20:/5l/.17(b),2a:/2a/.17(b),1h:/1h/.17(b)&&!/2a/.17(b),3j:/3j/.17(b)&&!/(6h|5l)/.17(b)};6.6g=!6.M.1h||P.6f=="6c";6.1U=6.M.1h?"1U":"5x",6.3H={"E":"68","67":"12","3x":6.1U,5x:6.1U,1U:6.1U,27:"27",12:"12",2v:"2v",2r:"2r",2B:"2B",65:"63",2T:"2T",62:"5Z"}};6.F({4v:"a.L",4p:"6.4p(a)",8o:"6.22(a,2,\'1X\')",8n:"6.22(a,2,\'4t\')",8k:"6.4q(a.L.1d,a)",8h:"6.4q(a.1d)"},q(i,n){6.11[i]=q(a){u b=6.3k(9,n);7(a&&1g a=="1s")b=6.2x(a,b);v 9.1Z(b)}});6.F({5o:"3e",8g:"5w",2K:"5t",8f:"5s"},q(i,n){6.11[i]=q(){u a=19;v 9.F(q(){E(u j=0,26=a.C;j<26;j++)6(a[j])[n](9)})}});6.F({5v:q(a){6.1b(9,a,"");9.8d(a)},8c:q(c){6.12.1A(9,c)},88:q(c){6.12.1E(9,c)},87:q(c){6.12[6.12.3w(9,c)?"1E":"1A"](9,c)},1E:q(a){7(!a||6.1i(a,[9]).r.C)9.L.3q(9)},2Y:q(){1v(9.1d)9.3q(9.1d)}},q(i,n){6.11[i]=q(){v 9.F(n,19)}});6.F(["5Q","5P","5O","5N"],q(i,n){6.11[n]=q(a,b){v 9.1i(":"+n+"("+a+")",b)}});6.F(["1u","29"],q(i,n){6.11[n]=q(h){v h==I?(9.C?6.1f(9[0],n):H):9.1f(n,h.15==33?h:h+"4o")}});6.1c({4n:{"":"m[2]==\'*\'||6.Q(a,m[2])","#":"a.35(\'2m\')==m[2]",":":{5P:"i<m[3]-0",5O:"i>m[3]-0",22:"m[3]-0==i",5Q:"m[3]-0==i",2Q:"i==0",2P:"i==r.C-1",5L:"i%2==0",5K:"i%2","2Q-3u":"a.L.3R(\'*\')[0]==a","2P-3u":"6.22(a.L.5J,1,\'4t\')==a","86-3u":"!6.22(a.L.5J,2,\'4t\')",4v:"a.1d",2Y:"!a.1d",5N:"(a.5H||a.85||\'\').J(m[3])>=0",4f:\'"1y"!=a.G&&6.1f(a,"U")!="1P"&&6.1f(a,"48")!="1y"\',1y:\'"1y"==a.G||6.1f(a,"U")=="1P"||6.1f(a,"48")=="1y"\',84:"!a.2r",2r:"a.2r",2B:"a.2B",2T:"a.2T||6.1b(a,\'2T\')",2A:"\'2A\'==a.G",4b:"\'4b\'==a.G",5F:"\'5F\'==a.G",4l:"\'4l\'==a.G",5E:"\'5E\'==a.G",4k:"\'4k\'==a.G",5D:"\'5D\'==a.G",5C:"\'5C\'==a.G",1J:\'"1J"==a.G||6.Q(a,"1J")\',5B:"/5B|2y|82|1J/i.17(a.Q)"},"[":"6.1L(m[2],a).C"},5A:[/^\\[ *(@)([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(\\[)\\s*(.*?(\\[.*?\\])?[^[]*?)\\s*\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,14 3o("^([:.#]*)("+(6.2J=6.M.20&&6.M.4D<"3.0.0"?"\\\\w":"(?:[\\\\w\\7Z-\\7X*1I-]|\\\\\\\\.)")+"+)")],2x:q(a,c,b){u d,1K=[];1v(a&&a!=d){d=a;u f=6.1i(a,c,b);a=f.t.1o(/^\\s*,\\s*/,"");1K=b?c=f.r:6.1T(1K,f.r)}v 1K},1L:q(t,l){7(1g t!="1s")v[t];7(l&&!l.1q)l=H;l=l||P;7(!t.J("//")){l=l.4h;t=t.2G(2,t.C)}B 7(!t.J("/")&&!l.2O){l=l.4h;t=t.2G(1,t.C);7(t.J("/")>=1)t=t.2G(t.J("/"),t.C)}u b=[l],2j=[],2P;1v(t&&2P!=t){u r=[];2P=t;t=6.2C(t).1o(/^\\/\\//,"");u k=N;u g=14 3o("^[/>]\\\\s*("+6.2J+"+)");u m=g.1V(t);7(m){u o=m[1].1D();E(u i=0;b[i];i++)E(u c=b[i].1d;c;c=c.1X)7(c.1q==1&&(o=="*"||c.Q.1D()==o.1D()))r.R(c);b=r;t=t.1o(g,"");7(t.J(" ")==0)7R;k=K}B{g=/^((\\/?\\.\\.)|([>\\/+~]))\\s*([a-z]*)/i;7((m=g.1V(t))!=H){r=[];u o=m[4],1k=6.1k++;m=m[1];E(u j=0,2e=b.C;j<2e;j++)7(m.J("..")<0){u n=m=="~"||m=="+"?b[j].1X:b[j].1d;E(;n;n=n.1X)7(n.1q==1){7(m=="~"&&n.1k==1k)1F;7(!o||n.Q.1D()==o.1D()){7(m=="~")n.1k=1k;r.R(n)}7(m=="+")1F}}B r.R(b[j].L);b=r;t=6.2C(t.1o(g,""));k=K}}7(t&&!k){7(!t.J(",")){7(l==b[0])b.4e();2j=6.1T(2j,b);r=b=[l];t=" "+t.2G(1,t.C)}B{u h=14 3o("^("+6.2J+"+)(#)("+6.2J+"+)");u m=h.1V(t);7(m){m=[0,m[2],m[3],m[1]]}B{h=14 3o("^([#.]?)("+6.2J+"*)");m=h.1V(t)}m[2]=m[2].1o(/\\\\/g,"");u f=b[b.C-1];7(m[1]=="#"&&f&&f.4d){u p=f.4d(m[2]);7((6.M.1h||6.M.2a)&&p&&1g p.2m=="1s"&&p.2m!=m[2])p=6(\'[@2m="\'+m[2]+\'"]\',f)[0];b=r=p&&(!m[3]||6.Q(p,m[3]))?[p]:[]}B{E(u i=0;b[i];i++){u a=m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&b[i].Q.2H()=="7P")a="2E";r=6.1T(r,b[i].3R(a))}7(m[1]==".")r=6.4c(r,m[2]);7(m[1]=="#"){u e=[];E(u i=0;r[i];i++)7(r[i].35("2m")==m[2]){e=[r[i]];1F}r=e}b=r}t=t.1o(h,"")}}7(t){u d=6.1i(t,r);b=r=d.r;t=6.2C(d.t)}}7(t)b=[];7(b&&l==b[0])b.4e();2j=6.1T(2j,b);v 2j},4c:q(r,m,a){m=" "+m+" ";u b=[];E(u i=0;r[i];i++){u c=(" "+r[i].12+" ").J(m)>=0;7(!a&&c||a&&!c)b.R(r[i])}v b},1i:q(t,r,h){u d;1v(t&&t!=d){d=t;u p=6.5A,m;E(u i=0;p[i];i++){m=p[i].1V(t);7(m){t=t.7N(m[0].C);m[2]=m[2].1o(/\\\\/g,"");1F}}7(!m)1F;7(m[1]==":"&&m[2]=="4Y")r=6.1i(m[3],r,K).r;B 7(m[1]==".")r=6.4c(r,m[2],h);B 7(m[1]=="@"){u g=[],G=m[3];E(u i=0,2e=r.C;i<2e;i++){u a=r[i],z=a[6.3H[m[2]]||m[2]];7(z==H||/4M|2u/.17(m[2]))z=6.1b(a,m[2])||\'\';7((G==""&&!!z||G=="="&&z==m[5]||G=="!="&&z!=m[5]||G=="^="&&z&&!z.J(m[5])||G=="$="&&z.2G(z.C-m[5].C)==m[5]||(G=="*="||G=="~=")&&z.J(m[5])>=0)^h)g.R(a)}r=g}B 7(m[1]==":"&&m[2]=="22-3u"){u e=6.1k++,g=[],17=/(\\d*)n\\+?(\\d*)/.1V(m[3]=="5L"&&"2n"||m[3]=="5K"&&"2n+1"||!/\\D/.17(m[3])&&"n+"+m[3]||m[3]),2Q=(17[1]||1)-0,d=17[2]-0;E(u i=0,2e=r.C;i<2e;i++){u j=r[i],L=j.L;7(e!=L.1k){u c=1;E(u n=L.1d;n;n=n.1X)7(n.1q==1)n.4a=c++;L.1k=e}u b=N;7(2Q==1){7(d==0||j.4a==d)b=K}B 7((j.4a+d)%2Q==0)b=K;7(b^h)g.R(j)}r=g}B{u f=6.4n[m[1]];7(1g f!="1s")f=6.4n[m[1]][m[2]];49("f = q(a,i){v "+f+"}");r=6.2s(r,f,h)}}v{r:r,t:t}},4p:q(c){u b=[];u a=c.L;1v(a&&a!=P){b.R(a);a=a.L}v b},22:q(a,e,c,b){e=e||1;u d=0;E(;a;a=a[c])7(a.1q==1&&++d==e)1F;v a},4q:q(n,a){u r=[];E(;n;n=n.1X){7(n.1q==1&&(!a||n!=a))r.R(n)}v r}});6.S={1A:q(d,e,c,b){7(6.M.1h&&d.3m!=I)d=18;7(!c.1Q)c.1Q=9.1Q++;7(b!=I){u f=c;c=q(){v f.O(9,19)};c.W=b;c.1Q=f.1Q}7(!d.$1a)d.$1a={};7(!d.$1p)d.$1p=q(){u a;7(1g 6=="I"||6.S.47)v a;a=6.S.1p.O(d,19);v a};u g=d.$1a[e];7(!g){g=d.$1a[e]={};7(d.46)d.46(e,d.$1p,N);B d.7M("5r"+e,d.$1p)}g[c.1Q]=c;7(!9.Y[e])9.Y[e]=[];7(6.2w(d,9.Y[e])==-1)9.Y[e].R(d)},1Q:1,Y:{},1E:q(b,c,a){u d=b.$1a,1Y,2p;7(d){7(c&&c.G){a=c.44;c=c.G}7(!c){E(c V d)9.1E(b,c)}B 7(d[c]){7(a)3l d[c][a.1Q];B E(a V b.$1a[c])3l d[c][a];E(1Y V d[c])1F;7(!1Y){7(b.43)b.43(c,b.$1p,N);B b.7J("5r"+c,b.$1p);1Y=H;3l d[c];1v(9.Y[c]&&((2p=6.2w(b,9.Y[c]))>=0))3l 9.Y[c][2p]}}E(1Y V d)1F;7(!1Y)b.$1p=b.$1a=H}},1t:q(c,b,d){b=6.2L(b||[]);7(!d)6.F(9.Y[c]||[],q(){6.S.1t(c,b,9)});B{u a,1Y,11=6.16(d[c]||H);b.5p(9.42({G:c,1O:d}));7(6.16(d.$1p)&&(a=d.$1p.O(d,b))!==N)9.47=K;7(11&&a!==N&&!6.Q(d,\'a\'))d[c]();9.47=N}},1p:q(b){u a;b=6.S.42(b||18.S||{});u c=9.$1a&&9.$1a[b.G],1S=[].51.3D(19,1);1S.5p(b);E(u j V c){1S[0].44=c[j];1S[0].W=c[j].W;7(c[j].O(9,1S)===N){b.2d();b.2D();a=N}}7(6.M.1h)b.1O=b.2d=b.2D=b.44=b.W=H;v a},42:q(c){u a=c;c=6.1c({},a);c.2d=q(){7(a.2d)v a.2d();a.7H=N};c.2D=q(){7(a.2D)v a.2D();a.7F=K};7(!c.1O&&c.5n)c.1O=c.5n;7(6.M.20&&c.1O.1q==3)c.1O=a.1O.L;7(!c.41&&c.4j)c.41=c.4j==c.1O?c.7C:c.4j;7(c.5k==H&&c.5j!=H){u e=P.4h,b=P.4y;c.5k=c.5j+(e&&e.5i||b.5i);c.7z=c.7y+(e&&e.5f||b.5f)}7(!c.3h&&(c.5e||c.5d))c.3h=c.5e||c.5d;7(!c.5c&&c.5b)c.5c=c.5b;7(!c.3h&&c.1J)c.3h=(c.1J&1?1:(c.1J&2?3:(c.1J&4?2:0)));v c}};6.11.1c({3g:q(c,a,b){v c=="3z"?9.3Z(c,a,b):9.F(q(){6.S.1A(9,c,b||a,b&&a)})},3Z:q(d,b,c){v 9.F(q(){6.S.1A(9,d,q(a){6(9).3U(a);v(c||b).O(9,19)},c&&b)})},3U:q(a,b){v 9.F(q(){6.S.1E(9,a,b)})},1t:q(a,b){v 9.F(q(){6.S.1t(a,b,9)})},1R:q(){u a=19;v 9.5a(q(e){9.4u=0==9.4u?1:0;e.2d();v a[9.4u].O(9,[e])||N})},7w:q(f,g){q 3W(e){u p=e.41;1v(p&&p!=9)2g{p=p.L}25(e){p=9};7(p==9)v N;v(e.G=="3V"?f:g).O(9,[e])}v 9.3V(3W).59(3W)},1G:q(f){7(6.3d)f.O(P,[6]);B 6.2q.R(q(){v f.O(9,[6])});v 9}});6.1c({3d:N,2q:[],1G:q(){7(!6.3d){6.3d=K;7(6.2q){6.F(6.2q,q(){9.O(P)});6.2q=H}7(6.M.3j||6.M.2a)P.43("58",6.1G,N);7(!18.7v.C)6(18).1W(q(){6("#3T").1E()})}}});14 q(){6.F(("7u,7t,1W,7s,7r,3z,5a,7q,"+"7p,7o,7n,3V,59,7m,2y,"+"4k,7l,7k,7j,2c").2R(","),q(i,o){6.11[o]=q(f){v f?9.3g(o,f):9.1t(o)}});7(6.M.3j||6.M.2a)P.46("58",6.1G,N);B 7(6.M.1h){P.7i("<7h"+"7f 2m=3T 7e=K "+"2u=//:><\\/3b>");u a=P.4d("3T");7(a)a.7d=q(){7(9.3a!="1n")v;6.1G()};a=H}B 7(6.M.20)6.3N=3m(q(){7(P.3a=="79"||P.3a=="1n"){3M(6.3N);6.3N=H;6.1G()}},10);6.S.1A(18,"1W",6.1G)};7(6.M.1h)6(18).3Z("3z",q(){u a=6.S.Y;E(u b V a){u c=a[b],i=c.C;7(i&&b!=\'3z\')77 c[i-1]&&6.S.1E(c[i-1],b);1v(--i)}});6.11.1c({76:q(c,b,a){9.1W(c,b,a,1)},1W:q(g,d,c,e){7(6.16(g))v 9.3g("1W",g);c=c||q(){};u f="3K";7(d)7(6.16(d)){c=d;d=H}B{d=6.2E(d);f="50"}u h=9;6.2Z({1C:g,G:f,W:d,2t:e,1n:q(a,b){7(b=="28"||!e&&b=="4V")h.1b("27",a.3c).3J().F(c,[a.3c,b,a]);B c.O(h,[a.3c,b,a])}});v 9},72:q(){v 6.2E(9)},3J:q(){v 9.1L("3b").F(q(){7(9.2u)6.4U(9.2u);B 6.3I(9.2A||9.5H||9.27||"")}).2U()}});6.F("4T,4I,4S,4R,4Q,4P".2R(","),q(i,o){6.11[o]=q(f){v 9.3g(o,f)}});6.1c({1M:q(e,c,a,d,b){7(6.16(c)){a=c;c=H}v 6.2Z({G:"3K",1C:e,W:c,28:a,3G:d,2t:b})},6X:q(d,b,a,c){v 6.1M(d,b,a,c,1)},4U:q(b,a){v 6.1M(b,H,a,"3b")},6V:q(c,b,a){v 6.1M(c,b,a,"4N")},6T:q(d,b,a,c){7(6.16(b)){a=b;b={}}v 6.2Z({G:"50",1C:d,W:b,28:a,3G:c})},6S:q(a){6.36.21=a},6Q:q(a){6.1c(6.36,a)},36:{Y:K,G:"3K",21:0,4O:"6P/x-6O-34-6N",4K:K,38:K,W:H},32:{},2Z:q(s){s=6.1c({},6.36,s);7(s.W){7(s.4K&&1g s.W!="1s")s.W=6.2E(s.W);7(s.G.2H()=="1M"){s.1C+=((s.1C.J("?")>-1)?"&":"?")+s.W;s.W=H}}7(s.Y&&!6.3L++)6.S.1t("4T");u f=N;u h=18.4Z?14 4Z("6L.6J"):14 4J();h.7b(s.G,s.1C,s.38);7(s.W)h.3Q("6H-6G",s.4O);7(s.2t)h.3Q("6F-3O-6D",6.32[s.1C]||"6C, 6B 6A 6z 4r:4r:4r 6y");h.3Q("X-6x-6w","4J");7(s.56)s.56(h);7(s.Y)6.S.1t("4P",[h,s]);u g=q(d){7(h&&(h.3a==4||d=="21")){f=K;7(i){3M(i);i=H}u c;2g{c=6.54(h)&&d!="21"?s.2t&&6.4F(h,s.1C)?"4V":"28":"2c";7(c!="2c"){u b;2g{b=h.3E("53-3O")}25(e){}7(s.2t&&b)6.32[s.1C]=b;u a=6.55(h,s.3G);7(s.28)s.28(a,c);7(s.Y)6.S.1t("4Q",[h,s])}B 6.2X(s,h,c)}25(e){c="2c";6.2X(s,h,c,e)}7(s.Y)6.S.1t("4S",[h,s]);7(s.Y&&!--6.3L)6.S.1t("4I");7(s.1n)s.1n(h,c);7(s.38)h=H}};u i=3m(g,13);7(s.21>0)4C(q(){7(h){h.6r();7(!f)g("21")}},s.21);2g{h.6p(s.W)}25(e){6.2X(s,h,H,e)}7(!s.38)g();v h},2X:q(s,a,b,e){7(s.2c)s.2c(a,b,e);7(s.Y)6.S.1t("4R",[a,s,e])},3L:0,54:q(r){2g{v!r.23&&7A.7B=="4l:"||(r.23>=5u&&r.23<6l)||r.23==5m||6.M.20&&r.23==I}25(e){}v N},4F:q(a,c){2g{u b=a.3E("53-3O");v a.23==5m||b==6.32[c]||6.M.20&&a.23==I}25(e){}v N},55:q(r,b){u c=r.3E("6k-G");u a=!b&&c&&c.J("4B")>=0;a=b=="4B"||a?r.6j:r.3c;7(b=="3b")6.3I(a);7(b=="4N")a=49("("+a+")");7(b=="3F")6("<1x>").3F(a).3J();v a},2E:q(a){u s=[];7(a.15==2b||a.3C)6.F(a,q(){s.R(2l(9.6i)+"="+2l(9.2v))});B E(u j V a)7(a[j]&&a[j].15==2b)6.F(a[j],q(){s.R(2l(j)+"="+2l(9))});B s.R(2l(j)+"="+2l(a[j]));v s.5M("&")},3I:q(a){7(18.4A)18.4A(a);B 7(6.M.20)18.4C(a,0);B 49.3D(18,a)}});6.11.1c({1m:q(b,a){v b?9.1w({1u:"1m",29:"1m",1e:"1m"},b,a):9.1i(":1y").F(q(){9.T.U=9.2i?9.2i:"";7(6.1f(9,"U")=="1P")9.T.U="2h"}).2U()},1j:q(b,a){v b?9.1w({1u:"1j",29:"1j",1e:"1j"},b,a):9.1i(":4f").F(q(){9.2i=9.2i||6.1f(9,"U");7(9.2i=="1P")9.2i="2h";9.T.U="1P"}).2U()},5G:6.11.1R,1R:q(a,b){v 6.16(a)&&6.16(b)?9.5G(a,b):a?9.1w({1u:"1R",29:"1R",1e:"1R"},a,b):9.F(q(){6(9)[6(9).37(":1y")?"1m":"1j"]()})},6e:q(b,a){v 9.1w({1u:"1m"},b,a)},6d:q(b,a){v 9.1w({1u:"1j"},b,a)},6b:q(b,a){v 9.1w({1u:"1R"},b,a)},6a:q(b,a){v 9.1w({1e:"1m"},b,a)},69:q(b,a){v 9.1w({1e:"1j"},b,a)},7U:q(c,a,b){v 9.1w({1e:a},c,b)},1w:q(d,h,f,g){v 9.1l(q(){u c=6(9).37(":1y"),1H=6.5z(h,f,g),5y=9;E(u p V d){7(d[p]=="1j"&&c||d[p]=="1m"&&!c)v 6.16(1H.1n)&&1H.1n.O(9);7(p=="1u"||p=="29"){1H.U=6.1f(9,"U");1H.2f=9.T.2f}}7(1H.2f!=H)9.T.2f="1y";9.2k=6.1c({},d);6.F(d,q(a,b){u e=14 6.2M(5y,1H,a);7(b.15==3y)e.2W(e.1K(),b);B e[b=="1R"?c?"1m":"1j":b](d)})})},1l:q(a,b){7(!b){b=a;a="2M"}v 9.F(q(){7(!9.1l)9.1l={};7(!9.1l[a])9.1l[a]=[];9.1l[a].R(b);7(9.1l[a].C==1)b.O(9)})}});6.1c({5z:q(b,a,c){u d=b&&b.15==64?b:{1n:c||!c&&a||6.16(b)&&b,1B:b,2I:c&&a||a&&a.15!=45&&a||(6.2I.4i?"4i":"4w")};d.1B=(d.1B&&d.1B.15==3y?d.1B:{61:60,89:5u}[d.1B])||8a;d.2N=d.1n;d.1n=q(){6.5I(9,"2M");7(6.16(d.2N))d.2N.O(9)};v d},2I:{4w:q(p,n,b,a){v b+a*p},4i:q(p,n,b,a){v((-5W.5X(p*5W.8e)/2)+0.5)*a+b}},1l:{},5I:q(b,a){a=a||"2M";7(b.1l&&b.1l[a]){b.1l[a].4e();u f=b.1l[a][0];7(f)f.O(b)}},3B:[],2M:q(f,e,g){u z=9;u y=f.T;z.a=q(){7(e.3A)e.3A.O(f,[z.2o]);7(g=="1e")6.1b(y,"1e",z.2o);B{y[g]=8m(z.2o)+"4o";y.U="2h"}};z.5V=q(){v 39(6.1f(f,g))};z.1K=q(){u r=39(6.2z(f,g));v r&&r>-8l?r:z.5V()};z.2W=q(c,b){z.4s=(14 5T()).5S();z.2o=c;z.a();6.3B.R(q(){v z.3A(c,b)});7(6.3B.C==1){u d=3m(q(){u a=6.3B;E(u i=0;i<a.C;i++)7(!a[i]())a.8j(i--,1);7(!a.C)3M(d)},13)}};z.1m=q(){7(!f.24)f.24={};f.24[g]=6.1b(f.T,g);e.1m=K;z.2W(0,9.1K());7(g!="1e")y[g]="8q";6(f).1m()};z.1j=q(){7(!f.24)f.24={};f.24[g]=6.1b(f.T,g);e.1j=K;z.2W(9.1K(),0)};z.3A=q(a,c){u t=(14 5T()).5S();7(t>e.1B+z.4s){z.2o=c;z.a();7(f.2k)f.2k[g]=K;u b=K;E(u i V f.2k)7(f.2k[i]!==K)b=N;7(b){7(e.U!=H){y.2f=e.2f;y.U=e.U;7(6.1f(f,"U")=="1P")y.U="2h"}7(e.1j)y.U="1P";7(e.1j||e.1m)E(u p V f.2k)6.1b(y,p,f.24[p])}7(b&&6.16(e.1n))e.1n.O(f);v N}B{u n=t-9.4s;u p=n/e.1B;z.2o=6.2I[e.2I](p,n,a,(c-a),e.1B);z.a()}v K}}})}',62,524,'||||||jQuery|if||this|||||||||||||||||function||||var|return||||||else|length||for|each|type|null|undefined|indexOf|true|parentNode|browser|false|apply|document|nodeName|push|event|style|display|in|data||global|||fn|className||new|constructor|isFunction|test|window|arguments|events|attr|extend|firstChild|opacity|css|typeof|msie|filter|hide|mergeNum|queue|show|complete|replace|handle|nodeType|table|string|trigger|height|while|animate|div|hidden|tbody|add|duration|url|toUpperCase|remove|break|ready|opt|_|button|cur|find|get|tb|target|none|guid|toggle|args|merge|styleFloat|exec|load|nextSibling|ret|pushStack|safari|timeout|nth|status|orig|catch|al|innerHTML|success|width|opera|Array|error|preventDefault|rl|overflow|try|block|oldblock|done|curAnim|encodeURIComponent|id||now|index|readyList|disabled|grep|ifModified|src|value|inArray|multiFilter|select|curCSS|text|checked|trim|stopPropagation|param|domManip|substr|toLowerCase|easing|chars|insertBefore|makeArray|fx|old|ownerDocument|last|first|split|childNodes|selected|end|tr|custom|handleError|empty|ajax|el|clean|lastModified|String|form|getAttribute|ajaxSettings|is|async|parseFloat|readyState|script|responseText|isReady|append|defaultView|bind|which|position|mozilla|map|delete|setInterval|static|RegExp|oWidth|removeChild|oHeight|cloneNode|match|child|toString|has|float|Number|unload|step|timers|jquery|call|getResponseHeader|html|dataType|props|globalEval|evalScripts|GET|active|clearInterval|safariTimer|Modified|num|setRequestHeader|getElementsByTagName|currentStyle|__ie_init|unbind|mouseover|handleHover|init|getComputedStyle|one|isXMLDoc|relatedTarget|fix|removeEventListener|handler|Function|addEventListener|triggered|visibility|eval|nodeIndex|radio|classFilter|getElementById|shift|visible|appendChild|documentElement|swing|fromElement|submit|file|swap|expr|px|parents|sibling|00|startTime|previousSibling|lastToggle|parent|linear|ol|body|tagName|execScript|xml|setTimeout|version|setArray|httpNotModified|fl|prop|ajaxStop|XMLHttpRequest|processData|alpha|href|json|contentType|ajaxSend|ajaxSuccess|ajaxError|ajaxComplete|ajaxStart|getScript|notmodified|colgroup|100|not|ActiveXObject|POST|slice|fieldset|Last|httpSuccess|httpData|beforeSend|getPropertyValue|DOMContentLoaded|mouseout|click|ctrlKey|metaKey|keyCode|charCode|scrollTop|unique|createElement|scrollLeft|clientX|pageX|webkit|304|srcElement|appendTo|unshift|prevObject|on|after|before|200|removeAttr|prepend|cssFloat|self|speed|parse|input|reset|image|password|checkbox|_toggle|textContent|dequeue|lastChild|odd|even|join|contains|gt|lt|eq|nodeValue|getTime|Date|zoom|max|Math|cos|font|maxLength|600|slow|maxlength|readOnly|Object|readonly|createTextNode|class|htmlFor|fadeOut|fadeIn|slideToggle|CSS1Compat|slideUp|slideDown|compatMode|boxModel|compatible|name|responseXML|content|300|ie|noConflict|ra|send|it|abort|rv|userAgent|navigator|concat|With|Requested|GMT|1970|Jan|01|Thu|Since|reverse|If|Type|Content|array|XMLHTTP|ig|Microsoft|NaN|urlencoded|www|application|ajaxSetup|val|ajaxTimeout|post|setAttribute|getJSON|getAttributeNode|getIfModified|method|FORM|action|options|serialize|col|th|td|loadIfModified|do|colg|loaded|tfoot|open|thead|onreadystatechange|defer|ipt|leg|scr|write|keyup|keypress|keydown|change|mousemove|mouseup|mousedown|dblclick|scroll|resize|focus|blur|frames|hover|clone|clientY|pageY|location|protocol|toElement|clientWidth|clientHeight|cancelBubble|relative|returnValue|left|detachEvent|right|absolute|attachEvent|substring|offsetWidth|object|offsetHeight|continue|Width|border|fadeTo|padding|size|uFFFF|Left|u0128|Right|Bottom|textarea|Top|enabled|innerText|only|toggleClass|removeClass|fast|400|wrap|addClass|removeAttribute|PI|insertAfter|prependTo|children|line|splice|siblings|10000|parseInt|prev|next|weight|1px|prototype'.split('|'),0,{}))
\ No newline at end of file diff --git a/htdocs/js/smokeping_iselect.js b/htdocs/js/smokeping_iselect.js deleted file mode 100644 index 905b8c3..0000000 --- a/htdocs/js/smokeping_iselect.js +++ /dev/null @@ -1,287 +0,0 @@ -/**
- * Interface Elements for jQuery
- * Selectables
- *
- * http://interface.eyecon.ro
- *
- * Copyright (c) 2006 Stefan Petre
- * Dual licensed under the MIT (MIT-LICENSE.txt)
- * and GPL (GPL-LICENSE.txt) licenses.
- *
- * Modified for smokeping ... we hacked in the call
- * we need after the area is selected. Yes there is
- * certainly a much better way todo this! Let us know!
- *
- */
-
-jQuery.selectHelper = null;
-jQuery.selectKeyHelper = false;
-jQuery.selectdrug = null;
-jQuery.selectCurrent = []; // For current selection
-jQuery.selectKeyDown = function(e) {
- var pressedKey = e.charCode || e.keyCode || -1;
- if (pressedKey == 17 || pressedKey == 16) {
- jQuery.selectKeyHelper = true;
- }
-};
-jQuery.selectKeyUp = function(e) {
- jQuery.selectKeyHelper = false;
-};
-jQuery.selectstart = function(e) {
- this.f.pointer = jQuery.iUtil.getPointer(e);
- this.f.pos = jQuery.extend(
- jQuery.iUtil.getPosition(this),
- jQuery.iUtil.getSize(this)
- );
-
- this.f.scr = jQuery.iUtil.getScroll(this);
- this.f.pointer.x -= this.f.pos.x;
- this.f.pointer.y -= this.f.pos.y;
- jQuery(this).append(jQuery.selectHelper.get(0));
- if (this.f.hc)
- jQuery.selectHelper.addClass(this.f.hc).css('display','block');
- jQuery.selectHelper.css(
- {
- display: 'block',
- width: '0px',
- height: '0px'
- }
- );
- if (this.f.o) {
- jQuery.selectHelper.css('opacity', this.f.o);
- }
-
- jQuery.selectdrug = this;
- jQuery.selectedone = false;
- jQuery.selectCurrent = []; // For current selection state
- this.f.el.each(
- function ()
- {
- this.pos = {
- x: this.offsetLeft + (this.currentStyle && !jQuery.browser.opera ?parseInt(this.currentStyle.borderLeftWidth)||0:0) + (jQuery.selectdrug.scrollLeft||0),
- y: this.offsetTop + (this.currentStyle && !jQuery.browser.opera ?parseInt(this.currentStyle.borderTopWidth)||0:0) + (jQuery.selectdrug.scrollTop||0),
- wb: this.offsetWidth,
- hb: this.offsetHeight
- };
- if (this.s == true) {
- if (jQuery.selectKeyHelper == false) {
- this.s = false;
- jQuery(this).removeClass(jQuery.selectdrug.f.sc);
- } else {
- jQuery.selectedone = true;
-
- // Save current state
- jQuery.selectCurrent[jQuery.selectCurrent.length] = jQuery.attr(this,'id');
- }
- }
- }
- );
- jQuery.selectcheck.apply(this, [e]);
- jQuery(document)
- .bind('mousemove', jQuery.selectcheck)
- .bind('mouseup', jQuery.selectstop);
- return false;
-};
-jQuery.selectcheck = function(e)
-{
- if(!jQuery.selectdrug)
- return;
- jQuery.selectcheckApply.apply(jQuery.selectdrug, [e]);
-};
-jQuery.selectcheckApply = function(e)
-{
- if(!jQuery.selectdrug)
- return;
- var pointer = jQuery.iUtil.getPointer(e);
-
- var scr = jQuery.iUtil.getScroll(jQuery.selectdrug);
- pointer.x += scr.l - this.f.scr.l - this.f.pos.x;
- pointer.y += scr.t - this.f.scr.t - this.f.pos.y;
-
- var sx = Math.min(pointer.x, this.f.pointer.x);
- var sw = Math.min(Math.abs(pointer.x - this.f.pointer.x), Math.abs(this.f.scr.w - sx));
- var sy = Math.min(pointer.y, this.f.pointer.y);
- var sh = Math.min(Math.abs(pointer.y - this.f.pointer.y), Math.abs(this.f.scr.h - sy));
- if (this.scrollTop > 0 && pointer.y - 20 < this.scrollTop) {
- var diff = Math.min(scr.t, 10);
- sy -= diff;
- sh += diff;
- this.scrollTop -= diff;
- } else if (this.scrollTop+ this.f.pos.h < this.f.scr.h && pointer.y + 20 > this.scrollTop + this.f.pos.h) {
- var diff = Math.min(this.f.scr.h - this.scrollTop, 10);
- this.scrollTop += diff;
- if (this.scrollTop != scr.t)
- sh += diff;
- }
- if (this.scrollLeft > 0 && pointer.x - 20 < this.scrollLeft) {
- var diff = Math.min(scr.l, 10);
- sx -= diff;
- sw += diff;
- this.scrollLeft -= diff;
- } else if (this.scrollLeft+ this.f.pos.w < this.f.scr.w && pointer.x + 20 > this.scrollLeft + this.f.pos.w) {
- var diff = Math.min(this.f.scr.w - this.scrollLeft, 10);
- this.scrollLeft += diff;
- if (this.scrollLeft != scr.l)
- sw += diff;
- }
- jQuery.selectHelper.css(
- {
- left: sx + 'px',
- top: sy + 'px',
- width: sw + 'px',
- height: sh + 'px'
- }
- );
- jQuery.selectHelper.l = sx + this.f.scr.l;
- jQuery.selectHelper.t = sy + this.f.scr.t;
- jQuery.selectHelper.r = jQuery.selectHelper.l + sw;
- jQuery.selectHelper.b = jQuery.selectHelper.t + sh;
-
- jQuery.selectedone = false;
- this.f.el.each(
- function () {
- // Locate the current element in the current selection
- iIndex = jQuery.selectCurrent.indexOf(jQuery.attr(this, 'id'));
- // In case we are currently OVER an item
- if (
- ! ( this.pos.x > jQuery.selectHelper.r
- || (this.pos.x + this.pos.wb) < jQuery.selectHelper.l
- || this.pos.y > jQuery.selectHelper.b
- || (this.pos.y + this.pos.hb) < jQuery.selectHelper.t
- )
- )
- {
- jQuery.selectedone = true;
- if (this.s != true) {
- this.s = true;
- jQuery(this).addClass(jQuery.selectdrug.f.sc);
- }
-
- // Check to see if this item was previously selected, if so, unselect it
- if (iIndex != -1) {
- this.s = false;
- jQuery(this).removeClass(jQuery.selectdrug.f.sc);
- }
- } else if (
- (this.s == true) &&
- (iIndex == -1)
- ) {
- // If the item was marked as selected, but it was not selected when you started dragging unselect it.
- this.s = false;
- jQuery(this).removeClass(jQuery.selectdrug.f.sc);
- } else if (
- (!this.s) &&
- (jQuery.selectKeyHelper == true) &&
- (iIndex != -1)
- ) {
- // Reselect the item if:
- // - we ARE multiselecting,
- // - dragged over an allready selected object (so it got unselected)
- // - But then dragged the selection out of it again.
- this.s = true;
- jQuery(this).addClass(jQuery.selectdrug.f.sc);
- }
- }
- );
- return false;
-};
-jQuery.selectstop = function(e)
-{
- if(!jQuery.selectdrug)
- return;
- jQuery.selectstopApply.apply(jQuery.selectdrug, [e]);
-};
-jQuery.selectstopApply = function(e)
-{
- jQuery(document)
- .unbind('mousemove', jQuery.selectcheck)
- .unbind('mouseup', jQuery.selectstop);
- if(!jQuery.selectdrug)
- return;
- jQuery.selectHelper.css('display','none');
- if (this.f.hc)
- jQuery.selectHelper.removeClass(this.f.hc);
- jQuery.selectdrug = false;
- jQuery('body').append(jQuery.selectHelper.get(0));
-
- /* added by Roman Plessl -- rp */
- mySelectTop = jQuery.selectHelper.t;
- mySelectLeft = jQuery.selectHelper.l;
- mySelectRight = jQuery.selectHelper.r;
- mySelectBottom = jQuery.selectHelper.b;
-
- changeRRDImage();
-
- // In case we have selected some new items..
- if (jQuery.selectedone == true) {
- if (this.f.onselect)
- this.f.onselect(jQuery.Selectserialize(jQuery.attr(this,'id')));
- } else {
- if (this.f.onselectstop)
- this.f.onselectstop(jQuery.Selectserialize(jQuery.attr(this,'id')));
- }
- // Reset current selection
- jQuery.selectCurrent = [];
-};
-
-jQuery.Selectserialize = function(s)
-{
- var h = '';
- var o = [];
- if (a = jQuery('#' + s)) {
- a.get(0).f.el.each(
- function ()
- {
- if (this.s == true) {
- if (h.length > 0) {
- h += '&';
- }
- h += s + '[]=' + jQuery.attr(this,'id');
- o[o.length] = jQuery.attr(this,'id');
- }
- }
- );
- }
- return {hash:h, o:o};
-};
-jQuery.fn.Selectable = function(o)
-{
- if (!jQuery.selectHelper) {
- jQuery('body',document).append('<div id="selectHelper"></div>').bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
- jQuery.selectHelper = jQuery('#selectHelper');
- jQuery.selectHelper.css(
- {
- position: 'absolute',
- display: 'none'
- }
- );
-
- if (window.event) {
- jQuery('body',document).bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
- } else {
- jQuery(document).bind('keydown', jQuery.selectKeyDown).bind('keyup', jQuery.selectKeyUp);
- }
- }
-
- if (!o) {
- o = {};
- }
- return this.each(
- function()
- {
- if (this.isSelectable)
- return;
- this.isSelectable = true;
- this.f = {
- a : o.accept,
- o : o.opacity ? parseFloat(o.opacity) : false,
- sc : o.selectedclass ? o.selectedclass : false,
- hc : o.helperclass ? o.helperclass : false,
- onselect : o.onselect ? o.onselect : false,
- onselectstop : o.onselectstop ? o.onselectstop : false
- };
- this.f.el = jQuery('.' + o.accept);
- jQuery(this).bind('mousedown', jQuery.selectstart).css('position', 'relative');
- }
- );
-}; |