diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2018-03-10 19:10:16 -0500 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2018-03-10 19:10:23 -0500 |
commit | f0ba08ced62b6fb3d1d5c7f1c1dd18b9b880a515 (patch) | |
tree | 4d1b83b544d48f04f78a6a1f52c903c32e2bd9dc /themes/mantra/resources/js | |
parent | Update akismet 4.0.2 (diff) | |
download | blogs-gentoo-f0ba08ced62b6fb3d1d5c7f1c1dd18b9b880a515.tar.gz blogs-gentoo-f0ba08ced62b6fb3d1d5c7f1c1dd18b9b880a515.tar.bz2 blogs-gentoo-f0ba08ced62b6fb3d1d5c7f1c1dd18b9b880a515.zip |
Update mantra 3.0.4
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'themes/mantra/resources/js')
22 files changed, 9950 insertions, 0 deletions
diff --git a/themes/mantra/resources/js/PIE/PIE.htc b/themes/mantra/resources/js/PIE/PIE.htc new file mode 100644 index 00000000..ca3b5470 --- /dev/null +++ b/themes/mantra/resources/js/PIE/PIE.htc @@ -0,0 +1,96 @@ +<!-- +PIE: CSS3 rendering for IE +Version 1.0.0 +http://css3pie.com +Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. +--> +<PUBLIC:COMPONENT lightWeight="true"> +<!-- saved from url=(0014)about:internet --> +<PUBLIC:ATTACH EVENT="oncontentready" FOR="element" ONEVENT="init()" /> +<PUBLIC:ATTACH EVENT="ondocumentready" FOR="element" ONEVENT="init()" /> +<PUBLIC:ATTACH EVENT="ondetach" FOR="element" ONEVENT="cleanup()" /> + +<script type="text/javascript"> +var doc = element.document;var f=window.PIE; +if(!f){f=window.PIE={F:"-pie-",nb:"Pie",La:"pie_",Ac:{TD:1,TH:1},cc:{TABLE:1,THEAD:1,TBODY:1,TFOOT:1,TR:1,INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,IMG:1,HR:1},fc:{A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},Gd:{submit:1,button:1,reset:1},aa:function(){}};try{doc.execCommand("BackgroundImageCache",false,true)}catch(aa){}for(var ba=4,Z=doc.createElement("div"),ca=Z.getElementsByTagName("i"),ga;Z.innerHTML="<!--[if gt IE "+ ++ba+"]><i></i><![endif]--\>",ca[0];);f.O=ba;if(ba===6)f.F=f.F.replace(/^-/,"");f.ja= +doc.documentMode||f.O;Z.innerHTML='<v:shape adj="1"/>';ga=Z.firstChild;ga.style.behavior="url(#default#VML)";f.zc=typeof ga.adj==="object";(function(){var a,b=0,c={};f.p={Za:function(d){if(!a){a=doc.createDocumentFragment();a.namespaces.add("css3vml","urn:schemas-microsoft-com:vml")}return a.createElement("css3vml:"+d)},Ba:function(d){return d&&d._pieId||(d._pieId="_"+ ++b)},Eb:function(d){var e,g,j,i,h=arguments;e=1;for(g=h.length;e<g;e++){i=h[e];for(j in i)if(i.hasOwnProperty(j))d[j]=i[j]}return d}, +Rb:function(d,e,g){var j=c[d],i,h;if(j)Object.prototype.toString.call(j)==="[object Array]"?j.push([e,g]):e.call(g,j);else{h=c[d]=[[e,g]];i=new Image;i.onload=function(){j=c[d]={h:i.width,f:i.height};for(var k=0,n=h.length;k<n;k++)h[k][0].call(h[k][1],j);i.onload=null};i.src=d}}}})();f.Na={gc:function(a,b,c,d){function e(){k=j>=90&&j<270?b:0;n=j<180?c:0;m=b-k;p=c-n}function g(){for(;j<0;)j+=360;j%=360}var j=d.sa;d=d.zb;var i,h,k,n,m,p,r,t;if(d){d=d.coords(a,b,c);i=d.x;h=d.y}if(j){j=j.jd();g();e(); +if(!d){i=k;h=n}d=f.Na.tc(i,h,j,m,p);a=d[0];d=d[1]}else if(d){a=b-i;d=c-h}else{i=h=a=0;d=c}r=a-i;t=d-h;if(j===void 0){j=!r?t<0?90:270:!t?r<0?180:0:-Math.atan2(t,r)/Math.PI*180;g();e()}return{sa:j,xc:i,yc:h,td:a,ud:d,Wd:k,Xd:n,rd:m,sd:p,kd:r,ld:t,rc:f.Na.dc(i,h,a,d)}},tc:function(a,b,c,d,e){if(c===0||c===180)return[d,b];else if(c===90||c===270)return[a,e];else{c=Math.tan(-c*Math.PI/180);a=c*a-b;b=-1/c;d=b*d-e;e=b-c;return[(d-a)/e,(c*d-b*a)/e]}},dc:function(a,b,c,d){a=c-a;b=d-b;return Math.abs(a===0? +b:b===0?a:Math.sqrt(a*a+b*b))}};f.ea=function(){this.Gb=[];this.oc={}};f.ea.prototype={ba:function(a){var b=f.p.Ba(a),c=this.oc,d=this.Gb;if(!(b in c)){c[b]=d.length;d.push(a)}},Ha:function(a){a=f.p.Ba(a);var b=this.oc;if(a&&a in b){delete this.Gb[b[a]];delete b[a]}},xa:function(){for(var a=this.Gb,b=a.length;b--;)a[b]&&a[b]()}};f.Oa=new f.ea;f.Oa.Rd=function(){var a=this,b;if(!a.Sd){b=doc.documentElement.currentStyle.getAttribute(f.F+"poll-interval")||250;(function c(){a.xa();setTimeout(c,b)})(); +a.Sd=1}};(function(){function a(){f.L.xa();window.detachEvent("onunload",a);window.PIE=null}f.L=new f.ea;window.attachEvent("onunload",a);f.L.ta=function(b,c,d){b.attachEvent(c,d);this.ba(function(){b.detachEvent(c,d)})}})();f.Qa=new f.ea;f.L.ta(window,"onresize",function(){f.Qa.xa()});(function(){function a(){f.mb.xa()}f.mb=new f.ea;f.L.ta(window,"onscroll",a);f.Qa.ba(a)})();(function(){function a(){c=f.kb.md()}function b(){if(c){for(var d=0,e=c.length;d<e;d++)f.attach(c[d]);c=0}}var c;if(f.ja<9){f.L.ta(window, +"onbeforeprint",a);f.L.ta(window,"onafterprint",b)}})();f.lb=new f.ea;f.L.ta(doc,"onmouseup",function(){f.lb.xa()});f.he=function(){function a(h){this.Y=h}var b=doc.createElement("length-calc"),c=doc.body||doc.documentElement,d=b.style,e={},g=["mm","cm","in","pt","pc"],j=g.length,i={};d.position="absolute";d.top=d.left="-9999px";for(c.appendChild(b);j--;){d.width="100"+g[j];e[g[j]]=b.offsetWidth/100}c.removeChild(b);d.width="1em";a.prototype={Kb:/(px|em|ex|mm|cm|in|pt|pc|%)$/,ic:function(){var h= +this.Jd;if(h===void 0)h=this.Jd=parseFloat(this.Y);return h},yb:function(){var h=this.ae;if(!h)h=this.ae=(h=this.Y.match(this.Kb))&&h[0]||"px";return h},a:function(h,k){var n=this.ic(),m=this.yb();switch(m){case "px":return n;case "%":return n*(typeof k==="function"?k():k)/100;case "em":return n*this.xb(h);case "ex":return n*this.xb(h)/2;default:return n*e[m]}},xb:function(h){var k=h.currentStyle.fontSize,n,m;if(k.indexOf("px")>0)return parseFloat(k);else if(h.tagName in f.cc){m=this;n=h.parentNode; +return f.n(k).a(n,function(){return m.xb(n)})}else{h.appendChild(b);k=b.offsetWidth;b.parentNode===h&&h.removeChild(b);return k}}};f.n=function(h){return i[h]||(i[h]=new a(h))};return a}();f.Ja=function(){function a(e){this.X=e}var b=f.n("50%"),c={top:1,center:1,bottom:1},d={left:1,center:1,right:1};a.prototype={zd:function(){if(!this.ac){var e=this.X,g=e.length,j=f.v,i=j.qa,h=f.n("0");i=i.na;h=["left",h,"top",h];if(g===1){e.push(new j.ob(i,"center"));g++}if(g===2){i&(e[0].k|e[1].k)&&e[0].d in c&& +e[1].d in d&&e.push(e.shift());if(e[0].k&i)if(e[0].d==="center")h[1]=b;else h[0]=e[0].d;else if(e[0].W())h[1]=f.n(e[0].d);if(e[1].k&i)if(e[1].d==="center")h[3]=b;else h[2]=e[1].d;else if(e[1].W())h[3]=f.n(e[1].d)}this.ac=h}return this.ac},coords:function(e,g,j){var i=this.zd(),h=i[1].a(e,g);e=i[3].a(e,j);return{x:i[0]==="right"?g-h:h,y:i[2]==="bottom"?j-e:e}}};return a}();f.Ka=function(){function a(b,c){this.h=b;this.f=c}a.prototype={a:function(b,c,d,e,g){var j=this.h,i=this.f,h=c/d;e=e/g;if(j=== +"contain"){j=e>h?c:d*e;i=e>h?c/e:d}else if(j==="cover"){j=e<h?c:d*e;i=e<h?c/e:d}else if(j==="auto"){i=i==="auto"?g:i.a(b,d);j=i*e}else{j=j.a(b,c);i=i==="auto"?j/e:i.a(b,d)}return{h:j,f:i}}};a.Kc=new a("auto","auto");return a}();f.Ec=function(){function a(b){this.Y=b}a.prototype={Kb:/[a-z]+$/i,yb:function(){return this.ad||(this.ad=this.Y.match(this.Kb)[0].toLowerCase())},jd:function(){var b=this.Vc,c;if(b===undefined){b=this.yb();c=parseFloat(this.Y,10);b=this.Vc=b==="deg"?c:b==="rad"?c/Math.PI*180: +b==="grad"?c/400*360:b==="turn"?c*360:0}return b}};return a}();f.Jc=function(){function a(c){this.Y=c}var b={};a.Qd=/\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/;a.Fb={aliceblue:"F0F8FF",antiquewhite:"FAEBD7",aqua:"0FF",aquamarine:"7FFFD4",azure:"F0FFFF",beige:"F5F5DC",bisque:"FFE4C4",black:"000",blanchedalmond:"FFEBCD",blue:"00F",blueviolet:"8A2BE2",brown:"A52A2A",burlywood:"DEB887",cadetblue:"5F9EA0",chartreuse:"7FFF00",chocolate:"D2691E",coral:"FF7F50",cornflowerblue:"6495ED", +cornsilk:"FFF8DC",crimson:"DC143C",cyan:"0FF",darkblue:"00008B",darkcyan:"008B8B",darkgoldenrod:"B8860B",darkgray:"A9A9A9",darkgreen:"006400",darkkhaki:"BDB76B",darkmagenta:"8B008B",darkolivegreen:"556B2F",darkorange:"FF8C00",darkorchid:"9932CC",darkred:"8B0000",darksalmon:"E9967A",darkseagreen:"8FBC8F",darkslateblue:"483D8B",darkslategray:"2F4F4F",darkturquoise:"00CED1",darkviolet:"9400D3",deeppink:"FF1493",deepskyblue:"00BFFF",dimgray:"696969",dodgerblue:"1E90FF",firebrick:"B22222",floralwhite:"FFFAF0", +forestgreen:"228B22",fuchsia:"F0F",gainsboro:"DCDCDC",ghostwhite:"F8F8FF",gold:"FFD700",goldenrod:"DAA520",gray:"808080",green:"008000",greenyellow:"ADFF2F",honeydew:"F0FFF0",hotpink:"FF69B4",indianred:"CD5C5C",indigo:"4B0082",ivory:"FFFFF0",khaki:"F0E68C",lavender:"E6E6FA",lavenderblush:"FFF0F5",lawngreen:"7CFC00",lemonchiffon:"FFFACD",lightblue:"ADD8E6",lightcoral:"F08080",lightcyan:"E0FFFF",lightgoldenrodyellow:"FAFAD2",lightgreen:"90EE90",lightgrey:"D3D3D3",lightpink:"FFB6C1",lightsalmon:"FFA07A", +lightseagreen:"20B2AA",lightskyblue:"87CEFA",lightslategray:"789",lightsteelblue:"B0C4DE",lightyellow:"FFFFE0",lime:"0F0",limegreen:"32CD32",linen:"FAF0E6",magenta:"F0F",maroon:"800000",mediumauqamarine:"66CDAA",mediumblue:"0000CD",mediumorchid:"BA55D3",mediumpurple:"9370D8",mediumseagreen:"3CB371",mediumslateblue:"7B68EE",mediumspringgreen:"00FA9A",mediumturquoise:"48D1CC",mediumvioletred:"C71585",midnightblue:"191970",mintcream:"F5FFFA",mistyrose:"FFE4E1",moccasin:"FFE4B5",navajowhite:"FFDEAD", +navy:"000080",oldlace:"FDF5E6",olive:"808000",olivedrab:"688E23",orange:"FFA500",orangered:"FF4500",orchid:"DA70D6",palegoldenrod:"EEE8AA",palegreen:"98FB98",paleturquoise:"AFEEEE",palevioletred:"D87093",papayawhip:"FFEFD5",peachpuff:"FFDAB9",peru:"CD853F",pink:"FFC0CB",plum:"DDA0DD",powderblue:"B0E0E6",purple:"800080",red:"F00",rosybrown:"BC8F8F",royalblue:"4169E1",saddlebrown:"8B4513",salmon:"FA8072",sandybrown:"F4A460",seagreen:"2E8B57",seashell:"FFF5EE",sienna:"A0522D",silver:"C0C0C0",skyblue:"87CEEB", +slateblue:"6A5ACD",slategray:"708090",snow:"FFFAFA",springgreen:"00FF7F",steelblue:"4682B4",tan:"D2B48C",teal:"008080",thistle:"D8BFD8",tomato:"FF6347",turquoise:"40E0D0",violet:"EE82EE",wheat:"F5DEB3",white:"FFF",whitesmoke:"F5F5F5",yellow:"FF0",yellowgreen:"9ACD32"};a.prototype={parse:function(){if(!this.Ua){var c=this.Y,d;if(d=c.match(a.Qd)){this.Ua="rgb("+d[1]+","+d[2]+","+d[3]+")";this.Yb=parseFloat(d[4])}else{if((d=c.toLowerCase())in a.Fb)c="#"+a.Fb[d];this.Ua=c;this.Yb=c==="transparent"?0: +1}}},U:function(c){this.parse();return this.Ua==="currentColor"?c.currentStyle.color:this.Ua},fa:function(){this.parse();return this.Yb}};f.ha=function(c){return b[c]||(b[c]=new a(c))};return a}();f.v=function(){function a(c){this.$a=c;this.ch=0;this.X=[];this.Ga=0}var b=a.qa={Ia:1,Wb:2,z:4,Lc:8,Xb:16,na:32,K:64,oa:128,pa:256,Ra:512,Tc:1024,URL:2048};a.ob=function(c,d){this.k=c;this.d=d};a.ob.prototype={Ca:function(){return this.k&b.K||this.k&b.oa&&this.d==="0"},W:function(){return this.Ca()||this.k& +b.Ra}};a.prototype={de:/\s/,Kd:/^[\+\-]?(\d*\.)?\d+/,url:/^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i,nc:/^\-?[_a-z][\w-]*/i,Yd:/^("([^"]*)"|'([^']*)')/,Bd:/^#([\da-f]{6}|[\da-f]{3})/i,be:{px:b.K,em:b.K,ex:b.K,mm:b.K,cm:b.K,"in":b.K,pt:b.K,pc:b.K,deg:b.Ia,rad:b.Ia,grad:b.Ia},fd:{rgb:1,rgba:1,hsl:1,hsla:1},next:function(c){function d(p,r){p=new a.ob(p,r);if(!c){k.X.push(p);k.Ga++}return p}function e(){k.Ga++;return null}var g,j,i,h,k=this;if(this.Ga<this.X.length)return this.X[this.Ga++];for(;this.de.test(this.$a.charAt(this.ch));)this.ch++; +if(this.ch>=this.$a.length)return e();j=this.ch;g=this.$a.substring(this.ch);i=g.charAt(0);switch(i){case "#":if(h=g.match(this.Bd)){this.ch+=h[0].length;return d(b.z,h[0])}break;case '"':case "'":if(h=g.match(this.Yd)){this.ch+=h[0].length;return d(b.Tc,h[2]||h[3]||"")}break;case "/":case ",":this.ch++;return d(b.pa,i);case "u":if(h=g.match(this.url)){this.ch+=h[0].length;return d(b.URL,h[2]||h[3]||h[4]||"")}}if(h=g.match(this.Kd)){i=h[0];this.ch+=i.length;if(g.charAt(i.length)==="%"){this.ch++; +return d(b.Ra,i+"%")}if(h=g.substring(i.length).match(this.nc)){i+=h[0];this.ch+=h[0].length;return d(this.be[h[0].toLowerCase()]||b.Lc,i)}return d(b.oa,i)}if(h=g.match(this.nc)){i=h[0];this.ch+=i.length;if(i.toLowerCase()in f.Jc.Fb||i==="currentColor"||i==="transparent")return d(b.z,i);if(g.charAt(i.length)==="("){this.ch++;if(i.toLowerCase()in this.fd){g=function(p){return p&&p.k&b.oa};h=function(p){return p&&p.k&(b.oa|b.Ra)};var n=function(p,r){return p&&p.d===r},m=function(){return k.next(1)}; +if((i.charAt(0)==="r"?h(m()):g(m()))&&n(m(),",")&&h(m())&&n(m(),",")&&h(m())&&(i==="rgb"||i==="hsa"||n(m(),",")&&g(m()))&&n(m(),")"))return d(b.z,this.$a.substring(j,this.ch));return e()}return d(b.Xb,i)}return d(b.na,i)}this.ch++;return d(b.Wb,i)},D:function(){return this.X[this.Ga-- -2]},all:function(){for(;this.next(););return this.X},ma:function(c,d){for(var e=[],g,j;g=this.next();){if(c(g)){j=true;this.D();break}e.push(g)}return d&&!j?null:e}};return a}();var ha=function(a){this.e=a};ha.prototype= +{Z:0,Od:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.x!==b.x||a.y!==b.y)},Td:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.h!==b.h||a.f!==b.f)},hc:function(){var a=this.e,b=a.getBoundingClientRect(),c=f.ja===9,d=f.O===7,e=b.right-b.left;return{x:b.left,y:b.top,h:c||d?a.offsetWidth:e,f:c||d?a.offsetHeight:b.bottom-b.top,Hd:d&&e?a.offsetWidth/e:1}},o:function(){return this.Z?this.Va||(this.Va=this.hc()):this.hc()},Ad:function(){return!!this.qb},cb:function(){++this.Z},hb:function(){if(!--this.Z){if(this.Va)this.qb= +this.Va;this.Va=null}}};(function(){function a(b){var c=f.p.Ba(b);return function(){if(this.Z){var d=this.$b||(this.$b={});return c in d?d[c]:(d[c]=b.call(this))}else return b.call(this)}}f.B={Z:0,ka:function(b){function c(d){this.e=d;this.Zb=this.ia()}f.p.Eb(c.prototype,f.B,b);c.$c={};return c},j:function(){var b=this.ia(),c=this.constructor.$c;return b?b in c?c[b]:(c[b]=this.la(b)):null},ia:a(function(){var b=this.e,c=this.constructor,d=b.style;b=b.currentStyle;var e=this.wa,g=this.Fa,j=c.Yc||(c.Yc= +f.F+e);c=c.Zc||(c.Zc=f.nb+g.charAt(0).toUpperCase()+g.substring(1));return d[c]||b.getAttribute(j)||d[g]||b.getAttribute(e)}),i:a(function(){return!!this.j()}),H:a(function(){var b=this.ia(),c=b!==this.Zb;this.Zb=b;return c}),va:a,cb:function(){++this.Z},hb:function(){--this.Z||delete this.$b}}})();f.Sb=f.B.ka({wa:f.F+"background",Fa:f.nb+"Background",cd:{scroll:1,fixed:1,local:1},fb:{"repeat-x":1,"repeat-y":1,repeat:1,"no-repeat":1},sc:{"padding-box":1,"border-box":1,"content-box":1},Pd:{top:1,right:1, +bottom:1,left:1,center:1},Ud:{contain:1,cover:1},eb:{Ma:"backgroundClip",z:"backgroundColor",da:"backgroundImage",Pa:"backgroundOrigin",S:"backgroundPosition",T:"backgroundRepeat",Sa:"backgroundSize"},la:function(a){function b(s){return s&&s.W()||s.k&k&&s.d in t}function c(s){return s&&(s.W()&&f.n(s.d)||s.d==="auto"&&"auto")}var d=this.e.currentStyle,e,g,j,i=f.v.qa,h=i.pa,k=i.na,n=i.z,m,p,r=0,t=this.Pd,v,l,q={M:[]};if(this.wb()){e=new f.v(a);for(j={};g=e.next();){m=g.k;p=g.d;if(!j.P&&m&i.Xb&&p=== +"linear-gradient"){v={ca:[],P:p};for(l={};g=e.next();){m=g.k;p=g.d;if(m&i.Wb&&p===")"){l.color&&v.ca.push(l);v.ca.length>1&&f.p.Eb(j,v);break}if(m&n){if(v.sa||v.zb){g=e.D();if(g.k!==h)break;e.next()}l={color:f.ha(p)};g=e.next();if(g.W())l.db=f.n(g.d);else e.D()}else if(m&i.Ia&&!v.sa&&!l.color&&!v.ca.length)v.sa=new f.Ec(g.d);else if(b(g)&&!v.zb&&!l.color&&!v.ca.length){e.D();v.zb=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&h&&p===","){if(l.color){v.ca.push(l);l={}}}else break}}else if(!j.P&& +m&i.URL){j.Ab=p;j.P="image"}else if(b(g)&&!j.$){e.D();j.$=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&k)if(p in this.fb&&!j.bb)j.bb=p;else if(p in this.sc&&!j.Wa){j.Wa=p;if((g=e.next())&&g.k&k&&g.d in this.sc)j.ub=g.d;else{j.ub=p;e.D()}}else if(p in this.cd&&!j.bc)j.bc=p;else return null;else if(m&n&&!q.color)q.color=f.ha(p);else if(m&h&&p==="/"&&!j.Xa&&j.$){g=e.next();if(g.k&k&&g.d in this.Ud)j.Xa=new f.Ka(g.d);else if(g=c(g)){m=c(e.next());if(!m){m=g;e.D()}j.Xa=new f.Ka(g,m)}else return null}else if(m& +h&&p===","&&j.P){j.Hb=a.substring(r,e.ch-1);r=e.ch;q.M.push(j);j={}}else return null}if(j.P){j.Hb=a.substring(r);q.M.push(j)}}else this.Bc(f.ja<9?function(){var s=this.eb,o=d[s.S+"X"],u=d[s.S+"Y"],x=d[s.da],y=d[s.z];if(y!=="transparent")q.color=f.ha(y);if(x!=="none")q.M=[{P:"image",Ab:(new f.v(x)).next().d,bb:d[s.T],$:new f.Ja((new f.v(o+" "+u)).all())}]}:function(){var s=this.eb,o=/\s*,\s*/,u=d[s.da].split(o),x=d[s.z],y,z,B,E,D,C;if(x!=="transparent")q.color=f.ha(x);if((E=u.length)&&u[0]!=="none"){x= +d[s.T].split(o);y=d[s.S].split(o);z=d[s.Pa].split(o);B=d[s.Ma].split(o);s=d[s.Sa].split(o);q.M=[];for(o=0;o<E;o++)if((D=u[o])&&D!=="none"){C=s[o].split(" ");q.M.push({Hb:D+" "+x[o]+" "+y[o]+" / "+s[o]+" "+z[o]+" "+B[o],P:"image",Ab:(new f.v(D)).next().d,bb:x[o],$:new f.Ja((new f.v(y[o])).all()),Wa:z[o],ub:B[o],Xa:new f.Ka(C[0],C[1])})}}});return q.color||q.M[0]?q:null},Bc:function(a){var b=f.ja>8,c=this.eb,d=this.e.runtimeStyle,e=d[c.da],g=d[c.z],j=d[c.T],i,h,k,n;if(e)d[c.da]="";if(g)d[c.z]="";if(j)d[c.T]= +"";if(b){i=d[c.Ma];h=d[c.Pa];n=d[c.S];k=d[c.Sa];if(i)d[c.Ma]="";if(h)d[c.Pa]="";if(n)d[c.S]="";if(k)d[c.Sa]=""}a=a.call(this);if(e)d[c.da]=e;if(g)d[c.z]=g;if(j)d[c.T]=j;if(b){if(i)d[c.Ma]=i;if(h)d[c.Pa]=h;if(n)d[c.S]=n;if(k)d[c.Sa]=k}return a},ia:f.B.va(function(){return this.wb()||this.Bc(function(){var a=this.e.currentStyle,b=this.eb;return a[b.z]+" "+a[b.da]+" "+a[b.T]+" "+a[b.S+"X"]+" "+a[b.S+"Y"]})}),wb:f.B.va(function(){var a=this.e;return a.style[this.Fa]||a.currentStyle.getAttribute(this.wa)}), +qc:function(){var a=0;if(f.O<7){a=this.e;a=""+(a.style[f.nb+"PngFix"]||a.currentStyle.getAttribute(f.F+"png-fix"))==="true"}return a},i:f.B.va(function(){return(this.wb()||this.qc())&&!!this.j()})});f.Vb=f.B.ka({wc:["Top","Right","Bottom","Left"],Id:{thin:"1px",medium:"3px",thick:"5px"},la:function(){var a={},b={},c={},d=false,e=true,g=true,j=true;this.Cc(function(){for(var i=this.e.currentStyle,h=0,k,n,m,p,r,t,v;h<4;h++){m=this.wc[h];v=m.charAt(0).toLowerCase();k=b[v]=i["border"+m+"Style"];n=i["border"+ +m+"Color"];m=i["border"+m+"Width"];if(h>0){if(k!==p)g=false;if(n!==r)e=false;if(m!==t)j=false}p=k;r=n;t=m;c[v]=f.ha(n);m=a[v]=f.n(b[v]==="none"?"0":this.Id[m]||m);if(m.a(this.e)>0)d=true}});return d?{J:a,Zd:b,gd:c,ee:j,hd:e,$d:g}:null},ia:f.B.va(function(){var a=this.e,b=a.currentStyle,c;a.tagName in f.Ac&&a.offsetParent.currentStyle.borderCollapse==="collapse"||this.Cc(function(){c=b.borderWidth+"|"+b.borderStyle+"|"+b.borderColor});return c}),Cc:function(a){var b=this.e.runtimeStyle,c=b.borderWidth, +d=b.borderColor;if(c)b.borderWidth="";if(d)b.borderColor="";a=a.call(this);if(c)b.borderWidth=c;if(d)b.borderColor=d;return a}});(function(){f.jb=f.B.ka({wa:"border-radius",Fa:"borderRadius",la:function(b){var c=null,d,e,g,j,i=false;if(b){e=new f.v(b);var h=function(){for(var k=[],n;(g=e.next())&&g.W();){j=f.n(g.d);n=j.ic();if(n<0)return null;if(n>0)i=true;k.push(j)}return k.length>0&&k.length<5?{tl:k[0],tr:k[1]||k[0],br:k[2]||k[0],bl:k[3]||k[1]||k[0]}:null};if(b=h()){if(g){if(g.k&f.v.qa.pa&&g.d=== +"/")d=h()}else d=b;if(i&&b&&d)c={x:b,y:d}}}return c}});var a=f.n("0");a={tl:a,tr:a,br:a,bl:a};f.jb.Dc={x:a,y:a}})();f.Ub=f.B.ka({wa:"border-image",Fa:"borderImage",fb:{stretch:1,round:1,repeat:1,space:1},la:function(a){var b=null,c,d,e,g,j,i,h=0,k=f.v.qa,n=k.na,m=k.oa,p=k.Ra;if(a){c=new f.v(a);b={};for(var r=function(l){return l&&l.k&k.pa&&l.d==="/"},t=function(l){return l&&l.k&n&&l.d==="fill"},v=function(){g=c.ma(function(l){return!(l.k&(m|p))});if(t(c.next())&&!b.fill)b.fill=true;else c.D();if(r(c.next())){h++; +j=c.ma(function(l){return!l.W()&&!(l.k&n&&l.d==="auto")});if(r(c.next())){h++;i=c.ma(function(l){return!l.Ca()})}}else c.D()};a=c.next();){d=a.k;e=a.d;if(d&(m|p)&&!g){c.D();v()}else if(t(a)&&!b.fill){b.fill=true;v()}else if(d&n&&this.fb[e]&&!b.repeat){b.repeat={f:e};if(a=c.next())if(a.k&n&&this.fb[a.d])b.repeat.Ob=a.d;else c.D()}else if(d&k.URL&&!b.src)b.src=e;else return null}if(!b.src||!g||g.length<1||g.length>4||j&&j.length>4||h===1&&j.length<1||i&&i.length>4||h===2&&i.length<1)return null;if(!b.repeat)b.repeat= +{f:"stretch"};if(!b.repeat.Ob)b.repeat.Ob=b.repeat.f;a=function(l,q){return{t:q(l[0]),r:q(l[1]||l[0]),b:q(l[2]||l[0]),l:q(l[3]||l[1]||l[0])}};b.slice=a(g,function(l){return f.n(l.k&m?l.d+"px":l.d)});if(j&&j[0])b.J=a(j,function(l){return l.W()?f.n(l.d):l.d});if(i&&i[0])b.Da=a(i,function(l){return l.Ca()?f.n(l.d):l.d})}return b}});f.Ic=f.B.ka({wa:"box-shadow",Fa:"boxShadow",la:function(a){var b,c=f.n,d=f.v.qa,e;if(a){e=new f.v(a);b={Da:[],Bb:[]};for(a=function(){for(var g,j,i,h,k,n;g=e.next();){i=g.d; +j=g.k;if(j&d.pa&&i===",")break;else if(g.Ca()&&!k){e.D();k=e.ma(function(m){return!m.Ca()})}else if(j&d.z&&!h)h=i;else if(j&d.na&&i==="inset"&&!n)n=true;else return false}g=k&&k.length;if(g>1&&g<5){(n?b.Bb:b.Da).push({fe:c(k[0].d),ge:c(k[1].d),blur:c(k[2]?k[2].d:"0"),Vd:c(k[3]?k[3].d:"0"),color:f.ha(h||"currentColor")});return true}return false};a(););}return b&&(b.Bb.length||b.Da.length)?b:null}});f.Uc=f.B.ka({ia:f.B.va(function(){var a=this.e.currentStyle;return a.visibility+"|"+a.display}),la:function(){var a= +this.e,b=a.runtimeStyle;a=a.currentStyle;var c=b.visibility,d;b.visibility="";d=a.visibility;b.visibility=c;return{ce:d!=="hidden",nd:a.display!=="none"}},i:function(){return false}});f.u={R:function(a){function b(c,d,e,g){this.e=c;this.s=d;this.g=e;this.parent=g}f.p.Eb(b.prototype,f.u,a);return b},Cb:false,Q:function(){return false},Ea:f.aa,Lb:function(){this.m();this.i()&&this.V()},ib:function(){this.Cb=true},Mb:function(){this.i()?this.V():this.m()},sb:function(a,b){this.vc(a);for(var c=this.ra|| +(this.ra=[]),d=a+1,e=c.length,g;d<e;d++)if(g=c[d])break;c[a]=b;this.I().insertBefore(b,g||null)},za:function(a){var b=this.ra;return b&&b[a]||null},vc:function(a){var b=this.za(a),c=this.Ta;if(b&&c){c.removeChild(b);this.ra[a]=null}},Aa:function(a,b,c,d){var e=this.rb||(this.rb={}),g=e[a];if(!g){g=e[a]=f.p.Za("shape");if(b)g.appendChild(g[b]=f.p.Za(b));if(d){c=this.za(d);if(!c){this.sb(d,doc.createElement("group"+d));c=this.za(d)}}c.appendChild(g);a=g.style;a.position="absolute";a.left=a.top=0;a.behavior= +"url(#default#VML)"}return g},vb:function(a){var b=this.rb,c=b&&b[a];if(c){c.parentNode.removeChild(c);delete b[a]}return!!c},kc:function(a){var b=this.e,c=this.s.o(),d=c.h,e=c.f,g,j,i,h,k,n;c=a.x.tl.a(b,d);g=a.y.tl.a(b,e);j=a.x.tr.a(b,d);i=a.y.tr.a(b,e);h=a.x.br.a(b,d);k=a.y.br.a(b,e);n=a.x.bl.a(b,d);a=a.y.bl.a(b,e);d=Math.min(d/(c+j),e/(i+k),d/(n+h),e/(g+a));if(d<1){c*=d;g*=d;j*=d;i*=d;h*=d;k*=d;n*=d;a*=d}return{x:{tl:c,tr:j,br:h,bl:n},y:{tl:g,tr:i,br:k,bl:a}}},ya:function(a,b,c){b=b||1;var d,e, +g=this.s.o();e=g.h*b;g=g.f*b;var j=this.g.G,i=Math.floor,h=Math.ceil,k=a?a.Jb*b:0,n=a?a.Ib*b:0,m=a?a.tb*b:0;a=a?a.Db*b:0;var p,r,t,v,l;if(c||j.i()){d=this.kc(c||j.j());c=d.x.tl*b;j=d.y.tl*b;p=d.x.tr*b;r=d.y.tr*b;t=d.x.br*b;v=d.y.br*b;l=d.x.bl*b;b=d.y.bl*b;e="m"+i(a)+","+i(j)+"qy"+i(c)+","+i(k)+"l"+h(e-p)+","+i(k)+"qx"+h(e-n)+","+i(r)+"l"+h(e-n)+","+h(g-v)+"qy"+h(e-t)+","+h(g-m)+"l"+i(l)+","+h(g-m)+"qx"+i(a)+","+h(g-b)+" x e"}else e="m"+i(a)+","+i(k)+"l"+h(e-n)+","+i(k)+"l"+h(e-n)+","+h(g-m)+"l"+i(a)+ +","+h(g-m)+"xe";return e},I:function(){var a=this.parent.za(this.N),b;if(!a){a=doc.createElement(this.Ya);b=a.style;b.position="absolute";b.top=b.left=0;this.parent.sb(this.N,a)}return a},mc:function(){var a=this.e,b=a.currentStyle,c=a.runtimeStyle,d=a.tagName,e=f.O===6,g;if(e&&(d in f.cc||d==="FIELDSET")||d==="BUTTON"||d==="INPUT"&&a.type in f.Gd){c.borderWidth="";d=this.g.w.wc;for(g=d.length;g--;){e=d[g];c["padding"+e]="";c["padding"+e]=f.n(b["padding"+e]).a(a)+f.n(b["border"+e+"Width"]).a(a)+(f.O!== +8&&g%2?1:0)}c.borderWidth=0}else if(e){if(a.childNodes.length!==1||a.firstChild.tagName!=="ie6-mask"){b=doc.createElement("ie6-mask");d=b.style;d.visibility="visible";for(d.zoom=1;d=a.firstChild;)b.appendChild(d);a.appendChild(b);c.visibility="hidden"}}else c.borderColor="transparent"},ie:function(){},m:function(){this.parent.vc(this.N);delete this.rb;delete this.ra}};f.Rc=f.u.R({i:function(){var a=this.ed;for(var b in a)if(a.hasOwnProperty(b)&&a[b].i())return true;return false},Q:function(){return this.g.Pb.H()}, +ib:function(){if(this.i()){var a=this.jc(),b=a,c;a=a.currentStyle;var d=a.position,e=this.I().style,g=0,j=0;j=this.s.o();var i=j.Hd;if(d==="fixed"&&f.O>6){g=j.x*i;j=j.y*i;b=d}else{do b=b.offsetParent;while(b&&b.currentStyle.position==="static");if(b){c=b.getBoundingClientRect();b=b.currentStyle;g=(j.x-c.left)*i-(parseFloat(b.borderLeftWidth)||0);j=(j.y-c.top)*i-(parseFloat(b.borderTopWidth)||0)}else{b=doc.documentElement;g=(j.x+b.scrollLeft-b.clientLeft)*i;j=(j.y+b.scrollTop-b.clientTop)*i}b="absolute"}e.position= +b;e.left=g;e.top=j;e.zIndex=d==="static"?-1:a.zIndex;this.Cb=true}},Mb:f.aa,Nb:function(){var a=this.g.Pb.j();this.I().style.display=a.ce&&a.nd?"":"none"},Lb:function(){this.i()?this.Nb():this.m()},jc:function(){var a=this.e;return a.tagName in f.Ac?a.offsetParent:a},I:function(){var a=this.Ta,b;if(!a){b=this.jc();a=this.Ta=doc.createElement("css3-container");a.style.direction="ltr";this.Nb();b.parentNode.insertBefore(a,b)}return a},ab:f.aa,m:function(){var a=this.Ta,b;if(a&&(b=a.parentNode))b.removeChild(a); +delete this.Ta;delete this.ra}});f.Fc=f.u.R({N:2,Ya:"background",Q:function(){var a=this.g;return a.C.H()||a.G.H()},i:function(){var a=this.g;return a.q.i()||a.G.i()||a.C.i()||a.ga.i()&&a.ga.j().Bb},V:function(){var a=this.s.o();if(a.h&&a.f){this.od();this.pd()}},od:function(){var a=this.g.C.j(),b=this.s.o(),c=this.e,d=a&&a.color,e,g;if(d&&d.fa()>0){this.lc();a=this.Aa("bgColor","fill",this.I(),1);e=b.h;b=b.f;a.stroked=false;a.coordsize=e*2+","+b*2;a.coordorigin="1,1";a.path=this.ya(null,2);g=a.style; +g.width=e;g.height=b;a.fill.color=d.U(c);c=d.fa();if(c<1)a.fill.opacity=c}else this.vb("bgColor")},pd:function(){var a=this.g.C.j(),b=this.s.o();a=a&&a.M;var c,d,e,g,j;if(a){this.lc();d=b.h;e=b.f;for(j=a.length;j--;){b=a[j];c=this.Aa("bgImage"+j,"fill",this.I(),2);c.stroked=false;c.fill.type="tile";c.fillcolor="none";c.coordsize=d*2+","+e*2;c.coordorigin="1,1";c.path=this.ya(0,2);g=c.style;g.width=d;g.height=e;if(b.P==="linear-gradient")this.bd(c,b);else{c.fill.src=b.Ab;this.Nd(c,j)}}}for(j=a?a.length: +0;this.vb("bgImage"+j++););},Nd:function(a,b){var c=this;f.p.Rb(a.fill.src,function(d){var e=c.e,g=c.s.o(),j=g.h;g=g.f;if(j&&g){var i=a.fill,h=c.g,k=h.w.j(),n=k&&k.J;k=n?n.t.a(e):0;var m=n?n.r.a(e):0,p=n?n.b.a(e):0;n=n?n.l.a(e):0;h=h.C.j().M[b];e=h.$?h.$.coords(e,j-d.h-n-m,g-d.f-k-p):{x:0,y:0};h=h.bb;p=m=0;var r=j+1,t=g+1,v=f.O===8?0:1;n=Math.round(e.x)+n+0.5;k=Math.round(e.y)+k+0.5;i.position=n/j+","+k/g;i.size.x=1;i.size=d.h+"px,"+d.f+"px";if(h&&h!=="repeat"){if(h==="repeat-x"||h==="no-repeat"){m= +k+1;t=k+d.f+v}if(h==="repeat-y"||h==="no-repeat"){p=n+1;r=n+d.h+v}a.style.clip="rect("+m+"px,"+r+"px,"+t+"px,"+p+"px)"}}})},bd:function(a,b){var c=this.e,d=this.s.o(),e=d.h,g=d.f;a=a.fill;d=b.ca;var j=d.length,i=Math.PI,h=f.Na,k=h.tc,n=h.dc;b=h.gc(c,e,g,b);h=b.sa;var m=b.xc,p=b.yc,r=b.Wd,t=b.Xd,v=b.rd,l=b.sd,q=b.kd,s=b.ld;b=b.rc;e=h%90?Math.atan2(q*e/g,s)/i*180:h+90;e+=180;e%=360;v=k(r,t,h,v,l);g=n(r,t,v[0],v[1]);i=[];v=k(m,p,h,r,t);n=n(m,p,v[0],v[1])/g*100;k=[];for(h=0;h<j;h++)k.push(d[h].db?d[h].db.a(c, +b):h===0?0:h===j-1?b:null);for(h=1;h<j;h++){if(k[h]===null){m=k[h-1];b=h;do p=k[++b];while(p===null);k[h]=m+(p-m)/(b-h+1)}k[h]=Math.max(k[h],k[h-1])}for(h=0;h<j;h++)i.push(n+k[h]/g*100+"% "+d[h].color.U(c));a.angle=e;a.type="gradient";a.method="sigma";a.color=d[0].color.U(c);a.color2=d[j-1].color.U(c);if(a.colors)a.colors.value=i.join(",");else a.colors=i.join(",")},lc:function(){var a=this.e.runtimeStyle;a.backgroundImage="url(about:blank)";a.backgroundColor="transparent"},m:function(){f.u.m.call(this); +var a=this.e.runtimeStyle;a.backgroundImage=a.backgroundColor=""}});f.Gc=f.u.R({N:4,Ya:"border",Q:function(){var a=this.g;return a.w.H()||a.G.H()},i:function(){var a=this.g;return a.G.i()&&!a.q.i()&&a.w.i()},V:function(){var a=this.e,b=this.g.w.j(),c=this.s.o(),d=c.h;c=c.f;var e,g,j,i,h;if(b){this.mc();b=this.wd(2);i=0;for(h=b.length;i<h;i++){j=b[i];e=this.Aa("borderPiece"+i,j.stroke?"stroke":"fill",this.I());e.coordsize=d*2+","+c*2;e.coordorigin="1,1";e.path=j.path;g=e.style;g.width=d;g.height=c; +e.filled=!!j.fill;e.stroked=!!j.stroke;if(j.stroke){e=e.stroke;e.weight=j.Qb+"px";e.color=j.color.U(a);e.dashstyle=j.stroke==="dashed"?"2 2":j.stroke==="dotted"?"1 1":"solid";e.linestyle=j.stroke==="double"&&j.Qb>2?"ThinThin":"Single"}else e.fill.color=j.fill.U(a)}for(;this.vb("borderPiece"+i++););}},wd:function(a){var b=this.e,c,d,e,g=this.g.w,j=[],i,h,k,n,m=Math.round,p,r,t;if(g.i()){c=g.j();g=c.J;r=c.Zd;t=c.gd;if(c.ee&&c.$d&&c.hd){if(t.t.fa()>0){c=g.t.a(b);k=c/2;j.push({path:this.ya({Jb:k,Ib:k, +tb:k,Db:k},a),stroke:r.t,color:t.t,Qb:c})}}else{a=a||1;c=this.s.o();d=c.h;e=c.f;c=m(g.t.a(b));k=m(g.r.a(b));n=m(g.b.a(b));b=m(g.l.a(b));var v={t:c,r:k,b:n,l:b};b=this.g.G;if(b.i())p=this.kc(b.j());i=Math.floor;h=Math.ceil;var l=function(o,u){return p?p[o][u]:0},q=function(o,u,x,y,z,B){var E=l("x",o),D=l("y",o),C=o.charAt(1)==="r";o=o.charAt(0)==="b";return E>0&&D>0?(B?"al":"ae")+(C?h(d-E):i(E))*a+","+(o?h(e-D):i(D))*a+","+(i(E)-u)*a+","+(i(D)-x)*a+","+y*65535+","+2949075*(z?1:-1):(B?"m":"l")+(C?d- +u:u)*a+","+(o?e-x:x)*a},s=function(o,u,x,y){var z=o==="t"?i(l("x","tl"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+i(l("y","tr"))*a:o==="b"?h(d-l("x","br"))*a+","+i(e-u)*a:i(u)*a+","+h(e-l("y","bl"))*a;o=o==="t"?h(d-l("x","tr"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+h(e-l("y","br"))*a:o==="b"?i(l("x","bl"))*a+","+i(e-u)*a:i(u)*a+","+i(l("y","tl"))*a;return x?(y?"m"+o:"")+"l"+z:(y?"m"+z:"")+"l"+o};b=function(o,u,x,y,z,B){var E=o==="l"||o==="r",D=v[o],C,F;if(D>0&&r[o]!=="none"&&t[o].fa()>0){C=v[E?o:u];u=v[E?u: +o];F=v[E?o:x];x=v[E?x:o];if(r[o]==="dashed"||r[o]==="dotted"){j.push({path:q(y,C,u,B+45,0,1)+q(y,0,0,B,1,0),fill:t[o]});j.push({path:s(o,D/2,0,1),stroke:r[o],Qb:D,color:t[o]});j.push({path:q(z,F,x,B,0,1)+q(z,0,0,B-45,1,0),fill:t[o]})}else j.push({path:q(y,C,u,B+45,0,1)+s(o,D,0,0)+q(z,F,x,B,0,0)+(r[o]==="double"&&D>2?q(z,F-i(F/3),x-i(x/3),B-45,1,0)+s(o,h(D/3*2),1,0)+q(y,C-i(C/3),u-i(u/3),B,1,0)+"x "+q(y,i(C/3),i(u/3),B+45,0,1)+s(o,i(D/3),1,0)+q(z,i(F/3),i(x/3),B,0,0):"")+q(z,0,0,B-45,1,0)+s(o,0,1, +0)+q(y,0,0,B,1,0),fill:t[o]})}};b("t","l","r","tl","tr",90);b("r","t","b","tr","br",0);b("b","r","l","br","bl",-90);b("l","b","t","bl","tl",-180)}}return j},m:function(){if(this.ec||!this.g.q.i())this.e.runtimeStyle.borderColor="";f.u.m.call(this)}});f.Tb=f.u.R({N:5,Md:["t","tr","r","br","b","bl","l","tl","c"],Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){this.I();var a=this.g.q.j(),b=this.g.w.j(),c=this.s.o(),d=this.e,e=this.uc;f.p.Rb(a.src,function(g){function j(s, +o,u,x,y){s=e[s].style;var z=Math.max;s.width=z(o,0);s.height=z(u,0);s.left=x;s.top=y}function i(s,o,u){for(var x=0,y=s.length;x<y;x++)e[s[x]].imagedata[o]=u}var h=c.h,k=c.f,n=f.n("0"),m=a.J||(b?b.J:{t:n,r:n,b:n,l:n});n=m.t.a(d);var p=m.r.a(d),r=m.b.a(d);m=m.l.a(d);var t=a.slice,v=t.t.a(d),l=t.r.a(d),q=t.b.a(d);t=t.l.a(d);j("tl",m,n,0,0);j("t",h-m-p,n,m,0);j("tr",p,n,h-p,0);j("r",p,k-n-r,h-p,n);j("br",p,r,h-p,k-r);j("b",h-m-p,r,m,k-r);j("bl",m,r,0,k-r);j("l",m,k-n-r,0,n);j("c",h-m-p,k-n-r,m,n);i(["tl", +"t","tr"],"cropBottom",(g.f-v)/g.f);i(["tl","l","bl"],"cropRight",(g.h-t)/g.h);i(["bl","b","br"],"cropTop",(g.f-q)/g.f);i(["tr","r","br"],"cropLeft",(g.h-l)/g.h);i(["l","r","c"],"cropTop",v/g.f);i(["l","r","c"],"cropBottom",q/g.f);i(["t","b","c"],"cropLeft",t/g.h);i(["t","b","c"],"cropRight",l/g.h);e.c.style.display=a.fill?"":"none"},this)},I:function(){var a=this.parent.za(this.N),b,c,d,e=this.Md,g=e.length;if(!a){a=doc.createElement("border-image");b=a.style;b.position="absolute";this.uc={};for(d= +0;d<g;d++){c=this.uc[e[d]]=f.p.Za("rect");c.appendChild(f.p.Za("imagedata"));b=c.style;b.behavior="url(#default#VML)";b.position="absolute";b.top=b.left=0;c.imagedata.src=this.g.q.j().src;c.stroked=false;c.filled=false;a.appendChild(c)}this.parent.sb(this.N,a)}return a},Ea:function(){if(this.i()){var a=this.e,b=a.runtimeStyle,c=this.g.q.j().J;b.borderStyle="solid";if(c){b.borderTopWidth=c.t.a(a)+"px";b.borderRightWidth=c.r.a(a)+"px";b.borderBottomWidth=c.b.a(a)+"px";b.borderLeftWidth=c.l.a(a)+"px"}this.mc()}}, +m:function(){var a=this.e.runtimeStyle;a.borderStyle="";if(this.ec||!this.g.w.i())a.borderColor=a.borderWidth="";f.u.m.call(this)}});f.Hc=f.u.R({N:1,Ya:"outset-box-shadow",Q:function(){var a=this.g;return a.ga.H()||a.G.H()},i:function(){var a=this.g.ga;return a.i()&&a.j().Da[0]},V:function(){function a(C,F,O,H,M,P,I){C=b.Aa("shadow"+C+F,"fill",d,j-C);F=C.fill;C.coordsize=n*2+","+m*2;C.coordorigin="1,1";C.stroked=false;C.filled=true;F.color=M.U(c);if(P){F.type="gradienttitle";F.color2=F.color;F.opacity= +0}C.path=I;l=C.style;l.left=O;l.top=H;l.width=n;l.height=m;return C}var b=this,c=this.e,d=this.I(),e=this.g,g=e.ga.j().Da;e=e.G.j();var j=g.length,i=j,h,k=this.s.o(),n=k.h,m=k.f;k=f.O===8?1:0;for(var p=["tl","tr","br","bl"],r,t,v,l,q,s,o,u,x,y,z,B,E,D;i--;){t=g[i];q=t.fe.a(c);s=t.ge.a(c);h=t.Vd.a(c);o=t.blur.a(c);t=t.color;u=-h-o;if(!e&&o)e=f.jb.Dc;u=this.ya({Jb:u,Ib:u,tb:u,Db:u},2,e);if(o){x=(h+o)*2+n;y=(h+o)*2+m;z=x?o*2/x:0;B=y?o*2/y:0;if(o-h>n/2||o-h>m/2)for(h=4;h--;){r=p[h];E=r.charAt(0)==="b"; +D=r.charAt(1)==="r";r=a(i,r,q,s,t,o,u);v=r.fill;v.focusposition=(D?1-z:z)+","+(E?1-B:B);v.focussize="0,0";r.style.clip="rect("+((E?y/2:0)+k)+"px,"+(D?x:x/2)+"px,"+(E?y:y/2)+"px,"+((D?x/2:0)+k)+"px)"}else{r=a(i,"",q,s,t,o,u);v=r.fill;v.focusposition=z+","+B;v.focussize=1-z*2+","+(1-B*2)}}else{r=a(i,"",q,s,t,o,u);q=t.fa();if(q<1)r.fill.opacity=q}}}});f.Pc=f.u.R({N:6,Ya:"imgEl",Q:function(){var a=this.g;return this.e.src!==this.Xc||a.G.H()},i:function(){var a=this.g;return a.G.i()||a.C.qc()},V:function(){this.Xc= +j;this.Cd();var a=this.Aa("img","fill",this.I()),b=a.fill,c=this.s.o(),d=c.h;c=c.f;var e=this.g.w.j(),g=e&&e.J;e=this.e;var j=e.src,i=Math.round,h=e.currentStyle,k=f.n;if(!g||f.O<7){g=f.n("0");g={t:g,r:g,b:g,l:g}}a.stroked=false;b.type="frame";b.src=j;b.position=(d?0.5/d:0)+","+(c?0.5/c:0);a.coordsize=d*2+","+c*2;a.coordorigin="1,1";a.path=this.ya({Jb:i(g.t.a(e)+k(h.paddingTop).a(e)),Ib:i(g.r.a(e)+k(h.paddingRight).a(e)),tb:i(g.b.a(e)+k(h.paddingBottom).a(e)),Db:i(g.l.a(e)+k(h.paddingLeft).a(e))}, +2);a=a.style;a.width=d;a.height=c},Cd:function(){this.e.runtimeStyle.filter="alpha(opacity=0)"},m:function(){f.u.m.call(this);this.e.runtimeStyle.filter=""}});f.Oc=f.u.R({ib:f.aa,Mb:f.aa,Nb:f.aa,Lb:f.aa,Ld:/^,+|,+$/g,Fd:/,+/g,gb:function(a,b){(this.pb||(this.pb=[]))[a]=b||void 0},ab:function(){var a=this.pb,b;if(a&&(b=a.join(",").replace(this.Ld,"").replace(this.Fd,","))!==this.Wc)this.Wc=this.e.runtimeStyle.background=b},m:function(){this.e.runtimeStyle.background="";delete this.pb}});f.Mc=f.u.R({ua:1, +Q:function(){return this.g.C.H()},i:function(){var a=this.g;return a.C.i()||a.q.i()},V:function(){var a=this.g.C.j(),b,c,d=0,e,g;if(a){b=[];if(c=a.M)for(;e=c[d++];)if(e.P==="linear-gradient"){g=this.vd(e.Wa);g=(e.Xa||f.Ka.Kc).a(this.e,g.h,g.f,g.h,g.f);b.push("url(data:image/svg+xml,"+escape(this.xd(e,g.h,g.f))+") "+this.dd(e.$)+" / "+g.h+"px "+g.f+"px "+(e.bc||"")+" "+(e.Wa||"")+" "+(e.ub||""))}else b.push(e.Hb);a.color&&b.push(a.color.Y);this.parent.gb(this.ua,b.join(","))}},dd:function(a){return a? +a.X.map(function(b){return b.d}).join(" "):"0 0"},vd:function(a){var b=this.e,c=this.s.o(),d=c.h;c=c.f;var e;if(a!=="border-box")if((e=this.g.w.j())&&(e=e.J)){d-=e.l.a(b)+e.l.a(b);c-=e.t.a(b)+e.b.a(b)}if(a==="content-box"){a=f.n;e=b.currentStyle;d-=a(e.paddingLeft).a(b)+a(e.paddingRight).a(b);c-=a(e.paddingTop).a(b)+a(e.paddingBottom).a(b)}return{h:d,f:c}},xd:function(a,b,c){var d=this.e,e=a.ca,g=e.length,j=f.Na.gc(d,b,c,a);a=j.xc;var i=j.yc,h=j.td,k=j.ud;j=j.rc;var n,m,p,r,t;n=[];for(m=0;m<g;m++)n.push(e[m].db? +e[m].db.a(d,j):m===0?0:m===g-1?j:null);for(m=1;m<g;m++)if(n[m]===null){r=n[m-1];p=m;do t=n[++p];while(t===null);n[m]=r+(t-r)/(p-m+1)}b=['<svg width="'+b+'" height="'+c+'" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="'+a/b*100+'%" y1="'+i/c*100+'%" x2="'+h/b*100+'%" y2="'+k/c*100+'%">'];for(m=0;m<g;m++)b.push('<stop offset="'+n[m]/j+'" stop-color="'+e[m].color.U(d)+'" stop-opacity="'+e[m].color.fa()+'"/>');b.push('</linearGradient></defs><rect width="100%" height="100%" fill="url(#g)"/></svg>'); +return b.join("")},m:function(){this.parent.gb(this.ua)}});f.Nc=f.u.R({T:"repeat",Sc:"stretch",Qc:"round",ua:0,Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){var a=this,b=a.g.q.j(),c=a.g.w.j(),d=a.s.o(),e=b.repeat,g=e.f,j=e.Ob,i=a.e,h=0;f.p.Rb(b.src,function(k){function n(Q,R,U,V,W,Y,X,S,w,A){K.push('<pattern patternUnits="userSpaceOnUse" id="pattern'+G+'" x="'+(g===l?Q+U/2-w/2:Q)+'" y="'+(j===l?R+V/2-A/2:R)+'" width="'+w+'" height="'+A+'"><svg width="'+w+'" height="'+ +A+'" viewBox="'+W+" "+Y+" "+X+" "+S+'" preserveAspectRatio="none"><image xlink:href="'+v+'" x="0" y="0" width="'+r+'" height="'+t+'" /></svg></pattern>');J.push('<rect x="'+Q+'" y="'+R+'" width="'+U+'" height="'+V+'" fill="url(#pattern'+G+')" />');G++}var m=d.h,p=d.f,r=k.h,t=k.f,v=a.Dd(b.src,r,t),l=a.T,q=a.Sc;k=a.Qc;var s=Math.ceil,o=f.n("0"),u=b.J||(c?c.J:{t:o,r:o,b:o,l:o});o=u.t.a(i);var x=u.r.a(i),y=u.b.a(i);u=u.l.a(i);var z=b.slice,B=z.t.a(i),E=z.r.a(i),D=z.b.a(i);z=z.l.a(i);var C=m-u-x,F=p-o- +y,O=r-z-E,H=t-B-D,M=g===q?C:O*o/B,P=j===q?F:H*x/E,I=g===q?C:O*y/D;q=j===q?F:H*u/z;var K=[],J=[],G=0;if(g===k){M-=(M-(C%M||M))/s(C/M);I-=(I-(C%I||I))/s(C/I)}if(j===k){P-=(P-(F%P||P))/s(F/P);q-=(q-(F%q||q))/s(F/q)}k=['<svg width="'+m+'" height="'+p+'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'];n(0,0,u,o,0,0,z,B,u,o);n(u,0,C,o,z,0,O,B,M,o);n(m-x,0,x,o,r-E,0,E,B,x,o);n(0,o,u,F,0,B,z,H,u,q);if(b.fill)n(u,o,C,F,z,B,O,H,M||I||O,q||P||H);n(m-x,o,x,F,r-E,B,E,H,x,P);n(0, +p-y,u,y,0,t-D,z,D,u,y);n(u,p-y,C,y,z,t-D,O,D,I,y);n(m-x,p-y,x,y,r-E,t-D,E,D,x,y);k.push("<defs>"+K.join("\n")+"</defs>"+J.join("\n")+"</svg>");a.parent.gb(a.ua,"url(data:image/svg+xml,"+escape(k.join(""))+") no-repeat border-box border-box");h&&a.parent.ab()},a);h=1},Dd:function(){var a={};return function(b,c,d){var e=a[b],g;if(!e){e=new Image;g=doc.createElement("canvas");e.src=b;g.width=c;g.height=d;g.getContext("2d").drawImage(e,0,0);e=a[b]=g.toDataURL()}return e}}(),Ea:f.Tb.prototype.Ea,m:function(){var a= +this.e.runtimeStyle;this.parent.gb(this.ua);a.borderColor=a.borderStyle=a.borderWidth=""}});f.kb=function(){function a(l,q){l.className+=" "+q}function b(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;)a(l,q[s])},0)}function c(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;){var o=q[s];o=t[o]||(t[o]=new RegExp("\\b"+o+"\\b","g"));l.className=l.className.replace(o,"")}},0)}function d(l){function q(){if(!U){var w,A,L=f.ja,T=l.currentStyle, +N=T.getAttribute(g)==="true",da=T.getAttribute(i)!=="false",ea=T.getAttribute(h)!=="false";S=T.getAttribute(j);S=L>7?S!=="false":S==="true";if(!R){R=1;l.runtimeStyle.zoom=1;T=l;for(var fa=1;T=T.previousSibling;)if(T.nodeType===1){fa=0;break}fa&&a(l,p)}J.cb();if(N&&(A=J.o())&&(w=doc.documentElement||doc.body)&&(A.y>w.clientHeight||A.x>w.clientWidth||A.y+A.f<0||A.x+A.h<0)){if(!Y){Y=1;f.mb.ba(q)}}else{U=1;Y=R=0;f.mb.Ha(q);if(L===9){G={C:new f.Sb(l),q:new f.Ub(l),w:new f.Vb(l)};Q=[G.C,G.q];K=new f.Oc(l, +J,G);w=[new f.Mc(l,J,G,K),new f.Nc(l,J,G,K)]}else{G={C:new f.Sb(l),w:new f.Vb(l),q:new f.Ub(l),G:new f.jb(l),ga:new f.Ic(l),Pb:new f.Uc(l)};Q=[G.C,G.w,G.q,G.G,G.ga,G.Pb];K=new f.Rc(l,J,G);w=[new f.Hc(l,J,G,K),new f.Fc(l,J,G,K),new f.Gc(l,J,G,K),new f.Tb(l,J,G,K)];l.tagName==="IMG"&&w.push(new f.Pc(l,J,G,K));K.ed=w}I=[K].concat(w);if(w=l.currentStyle.getAttribute(f.F+"watch-ancestors")){w=parseInt(w,10);A=0;for(N=l.parentNode;N&&(w==="NaN"||A++<w);){H(N,"onpropertychange",C);H(N,"onmouseenter",x); +H(N,"onmouseleave",y);H(N,"onmousedown",z);if(N.tagName in f.fc){H(N,"onfocus",E);H(N,"onblur",D)}N=N.parentNode}}if(S){f.Oa.ba(o);f.Oa.Rd()}o(1)}if(!V){V=1;L<9&&H(l,"onmove",s);H(l,"onresize",s);H(l,"onpropertychange",u);ea&&H(l,"onmouseenter",x);if(ea||da)H(l,"onmouseleave",y);da&&H(l,"onmousedown",z);if(l.tagName in f.fc){H(l,"onfocus",E);H(l,"onblur",D)}f.Qa.ba(s);f.L.ba(M)}J.hb()}}function s(){J&&J.Ad()&&o()}function o(w){if(!X)if(U){var A,L=I.length;F();for(A=0;A<L;A++)I[A].Ea();if(w||J.Od())for(A= +0;A<L;A++)I[A].ib();if(w||J.Td())for(A=0;A<L;A++)I[A].Mb();K.ab();O()}else R||q()}function u(){var w,A=I.length,L;w=event;if(!X&&!(w&&w.propertyName in r))if(U){F();for(w=0;w<A;w++)I[w].Ea();for(w=0;w<A;w++){L=I[w];L.Cb||L.ib();L.Q()&&L.Lb()}K.ab();O()}else R||q()}function x(){b(l,k)}function y(){c(l,k,n)}function z(){b(l,n);f.lb.ba(B)}function B(){c(l,n);f.lb.Ha(B)}function E(){b(l,m)}function D(){c(l,m)}function C(){var w=event.propertyName;if(w==="className"||w==="id")u()}function F(){J.cb();for(var w= +Q.length;w--;)Q[w].cb()}function O(){for(var w=Q.length;w--;)Q[w].hb();J.hb()}function H(w,A,L){w.attachEvent(A,L);W.push([w,A,L])}function M(){if(V){for(var w=W.length,A;w--;){A=W[w];A[0].detachEvent(A[1],A[2])}f.L.Ha(M);V=0;W=[]}}function P(){if(!X){var w,A;M();X=1;if(I){w=0;for(A=I.length;w<A;w++){I[w].ec=1;I[w].m()}}S&&f.Oa.Ha(o);f.Qa.Ha(o);I=J=G=Q=l=null}}var I,K,J=new ha(l),G,Q,R,U,V,W=[],Y,X,S;this.Ed=q;this.update=o;this.m=P;this.qd=l}var e={},g=f.F+"lazy-init",j=f.F+"poll",i=f.F+"track-active", +h=f.F+"track-hover",k=f.La+"hover",n=f.La+"active",m=f.La+"focus",p=f.La+"first-child",r={background:1,bgColor:1,display:1},t={},v=[];d.yd=function(l){var q=f.p.Ba(l);return e[q]||(e[q]=new d(l))};d.m=function(l){l=f.p.Ba(l);var q=e[l];if(q){q.m();delete e[l]}};d.md=function(){var l=[],q;if(e){for(var s in e)if(e.hasOwnProperty(s)){q=e[s];l.push(q.qd);q.m()}e={}}return l};return d}();f.supportsVML=f.zc;f.attach=function(a){f.ja<10&&f.zc&&f.kb.yd(a).Ed()};f.detach=function(a){f.kb.m(a)}}; +var $=element;function init(){if(doc.media!=="print"){var a=window.PIE;a&&a.attach($)}}function cleanup(){if(doc.media!=="print"){var a=window.PIE;if(a){a.detach($);$=0}}}$.readyState==="complete"&&init(); +</script> +</PUBLIC:COMPONENT> diff --git a/themes/mantra/resources/js/PIE/PIE.js b/themes/mantra/resources/js/PIE/PIE.js new file mode 100644 index 00000000..d36448a9 --- /dev/null +++ b/themes/mantra/resources/js/PIE/PIE.js @@ -0,0 +1,88 @@ +/* +PIE: CSS3 rendering for IE +Version 1.0.0 +http://css3pie.com +Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. +*/ +(function(){ +var doc = document;var f=window.PIE; +if(!f){f=window.PIE={F:"-pie-",nb:"Pie",La:"pie_",Ac:{TD:1,TH:1},cc:{TABLE:1,THEAD:1,TBODY:1,TFOOT:1,TR:1,INPUT:1,TEXTAREA:1,SELECT:1,OPTION:1,IMG:1,HR:1},fc:{A:1,INPUT:1,TEXTAREA:1,SELECT:1,BUTTON:1},Gd:{submit:1,button:1,reset:1},aa:function(){}};try{doc.execCommand("BackgroundImageCache",false,true)}catch(aa){}for(var ba=4,Z=doc.createElement("div"),ca=Z.getElementsByTagName("i"),ga;Z.innerHTML="<!--[if gt IE "+ ++ba+"]><i></i><![endif]--\>",ca[0];);f.O=ba;if(ba===6)f.F=f.F.replace(/^-/,"");f.ja= +doc.documentMode||f.O;Z.innerHTML='<v:shape adj="1"/>';ga=Z.firstChild;ga.style.behavior="url(#default#VML)";f.zc=typeof ga.adj==="object";(function(){var a,b=0,c={};f.p={Za:function(d){if(!a){a=doc.createDocumentFragment();a.namespaces.add("css3vml","urn:schemas-microsoft-com:vml")}return a.createElement("css3vml:"+d)},Ba:function(d){return d&&d._pieId||(d._pieId="_"+ ++b)},Eb:function(d){var e,g,j,i,h=arguments;e=1;for(g=h.length;e<g;e++){i=h[e];for(j in i)if(i.hasOwnProperty(j))d[j]=i[j]}return d}, +Rb:function(d,e,g){var j=c[d],i,h;if(j)Object.prototype.toString.call(j)==="[object Array]"?j.push([e,g]):e.call(g,j);else{h=c[d]=[[e,g]];i=new Image;i.onload=function(){j=c[d]={h:i.width,f:i.height};for(var k=0,n=h.length;k<n;k++)h[k][0].call(h[k][1],j);i.onload=null};i.src=d}}}})();f.Na={gc:function(a,b,c,d){function e(){k=j>=90&&j<270?b:0;n=j<180?c:0;m=b-k;p=c-n}function g(){for(;j<0;)j+=360;j%=360}var j=d.sa;d=d.zb;var i,h,k,n,m,p,r,t;if(d){d=d.coords(a,b,c);i=d.x;h=d.y}if(j){j=j.jd();g();e(); +if(!d){i=k;h=n}d=f.Na.tc(i,h,j,m,p);a=d[0];d=d[1]}else if(d){a=b-i;d=c-h}else{i=h=a=0;d=c}r=a-i;t=d-h;if(j===void 0){j=!r?t<0?90:270:!t?r<0?180:0:-Math.atan2(t,r)/Math.PI*180;g();e()}return{sa:j,xc:i,yc:h,td:a,ud:d,Wd:k,Xd:n,rd:m,sd:p,kd:r,ld:t,rc:f.Na.dc(i,h,a,d)}},tc:function(a,b,c,d,e){if(c===0||c===180)return[d,b];else if(c===90||c===270)return[a,e];else{c=Math.tan(-c*Math.PI/180);a=c*a-b;b=-1/c;d=b*d-e;e=b-c;return[(d-a)/e,(c*d-b*a)/e]}},dc:function(a,b,c,d){a=c-a;b=d-b;return Math.abs(a===0? +b:b===0?a:Math.sqrt(a*a+b*b))}};f.ea=function(){this.Gb=[];this.oc={}};f.ea.prototype={ba:function(a){var b=f.p.Ba(a),c=this.oc,d=this.Gb;if(!(b in c)){c[b]=d.length;d.push(a)}},Ha:function(a){a=f.p.Ba(a);var b=this.oc;if(a&&a in b){delete this.Gb[b[a]];delete b[a]}},xa:function(){for(var a=this.Gb,b=a.length;b--;)a[b]&&a[b]()}};f.Oa=new f.ea;f.Oa.Rd=function(){var a=this,b;if(!a.Sd){b=doc.documentElement.currentStyle.getAttribute(f.F+"poll-interval")||250;(function c(){a.xa();setTimeout(c,b)})(); +a.Sd=1}};(function(){function a(){f.L.xa();window.detachEvent("onunload",a);window.PIE=null}f.L=new f.ea;window.attachEvent("onunload",a);f.L.ta=function(b,c,d){b.attachEvent(c,d);this.ba(function(){b.detachEvent(c,d)})}})();f.Qa=new f.ea;f.L.ta(window,"onresize",function(){f.Qa.xa()});(function(){function a(){f.mb.xa()}f.mb=new f.ea;f.L.ta(window,"onscroll",a);f.Qa.ba(a)})();(function(){function a(){c=f.kb.md()}function b(){if(c){for(var d=0,e=c.length;d<e;d++)f.attach(c[d]);c=0}}var c;if(f.ja<9){f.L.ta(window, +"onbeforeprint",a);f.L.ta(window,"onafterprint",b)}})();f.lb=new f.ea;f.L.ta(doc,"onmouseup",function(){f.lb.xa()});f.he=function(){function a(h){this.Y=h}var b=doc.createElement("length-calc"),c=doc.body||doc.documentElement,d=b.style,e={},g=["mm","cm","in","pt","pc"],j=g.length,i={};d.position="absolute";d.top=d.left="-9999px";for(c.appendChild(b);j--;){d.width="100"+g[j];e[g[j]]=b.offsetWidth/100}c.removeChild(b);d.width="1em";a.prototype={Kb:/(px|em|ex|mm|cm|in|pt|pc|%)$/,ic:function(){var h= +this.Jd;if(h===void 0)h=this.Jd=parseFloat(this.Y);return h},yb:function(){var h=this.ae;if(!h)h=this.ae=(h=this.Y.match(this.Kb))&&h[0]||"px";return h},a:function(h,k){var n=this.ic(),m=this.yb();switch(m){case "px":return n;case "%":return n*(typeof k==="function"?k():k)/100;case "em":return n*this.xb(h);case "ex":return n*this.xb(h)/2;default:return n*e[m]}},xb:function(h){var k=h.currentStyle.fontSize,n,m;if(k.indexOf("px")>0)return parseFloat(k);else if(h.tagName in f.cc){m=this;n=h.parentNode; +return f.n(k).a(n,function(){return m.xb(n)})}else{h.appendChild(b);k=b.offsetWidth;b.parentNode===h&&h.removeChild(b);return k}}};f.n=function(h){return i[h]||(i[h]=new a(h))};return a}();f.Ja=function(){function a(e){this.X=e}var b=f.n("50%"),c={top:1,center:1,bottom:1},d={left:1,center:1,right:1};a.prototype={zd:function(){if(!this.ac){var e=this.X,g=e.length,j=f.v,i=j.qa,h=f.n("0");i=i.na;h=["left",h,"top",h];if(g===1){e.push(new j.ob(i,"center"));g++}if(g===2){i&(e[0].k|e[1].k)&&e[0].d in c&& +e[1].d in d&&e.push(e.shift());if(e[0].k&i)if(e[0].d==="center")h[1]=b;else h[0]=e[0].d;else if(e[0].W())h[1]=f.n(e[0].d);if(e[1].k&i)if(e[1].d==="center")h[3]=b;else h[2]=e[1].d;else if(e[1].W())h[3]=f.n(e[1].d)}this.ac=h}return this.ac},coords:function(e,g,j){var i=this.zd(),h=i[1].a(e,g);e=i[3].a(e,j);return{x:i[0]==="right"?g-h:h,y:i[2]==="bottom"?j-e:e}}};return a}();f.Ka=function(){function a(b,c){this.h=b;this.f=c}a.prototype={a:function(b,c,d,e,g){var j=this.h,i=this.f,h=c/d;e=e/g;if(j=== +"contain"){j=e>h?c:d*e;i=e>h?c/e:d}else if(j==="cover"){j=e<h?c:d*e;i=e<h?c/e:d}else if(j==="auto"){i=i==="auto"?g:i.a(b,d);j=i*e}else{j=j.a(b,c);i=i==="auto"?j/e:i.a(b,d)}return{h:j,f:i}}};a.Kc=new a("auto","auto");return a}();f.Ec=function(){function a(b){this.Y=b}a.prototype={Kb:/[a-z]+$/i,yb:function(){return this.ad||(this.ad=this.Y.match(this.Kb)[0].toLowerCase())},jd:function(){var b=this.Vc,c;if(b===undefined){b=this.yb();c=parseFloat(this.Y,10);b=this.Vc=b==="deg"?c:b==="rad"?c/Math.PI*180: +b==="grad"?c/400*360:b==="turn"?c*360:0}return b}};return a}();f.Jc=function(){function a(c){this.Y=c}var b={};a.Qd=/\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/;a.Fb={aliceblue:"F0F8FF",antiquewhite:"FAEBD7",aqua:"0FF",aquamarine:"7FFFD4",azure:"F0FFFF",beige:"F5F5DC",bisque:"FFE4C4",black:"000",blanchedalmond:"FFEBCD",blue:"00F",blueviolet:"8A2BE2",brown:"A52A2A",burlywood:"DEB887",cadetblue:"5F9EA0",chartreuse:"7FFF00",chocolate:"D2691E",coral:"FF7F50",cornflowerblue:"6495ED", +cornsilk:"FFF8DC",crimson:"DC143C",cyan:"0FF",darkblue:"00008B",darkcyan:"008B8B",darkgoldenrod:"B8860B",darkgray:"A9A9A9",darkgreen:"006400",darkkhaki:"BDB76B",darkmagenta:"8B008B",darkolivegreen:"556B2F",darkorange:"FF8C00",darkorchid:"9932CC",darkred:"8B0000",darksalmon:"E9967A",darkseagreen:"8FBC8F",darkslateblue:"483D8B",darkslategray:"2F4F4F",darkturquoise:"00CED1",darkviolet:"9400D3",deeppink:"FF1493",deepskyblue:"00BFFF",dimgray:"696969",dodgerblue:"1E90FF",firebrick:"B22222",floralwhite:"FFFAF0", +forestgreen:"228B22",fuchsia:"F0F",gainsboro:"DCDCDC",ghostwhite:"F8F8FF",gold:"FFD700",goldenrod:"DAA520",gray:"808080",green:"008000",greenyellow:"ADFF2F",honeydew:"F0FFF0",hotpink:"FF69B4",indianred:"CD5C5C",indigo:"4B0082",ivory:"FFFFF0",khaki:"F0E68C",lavender:"E6E6FA",lavenderblush:"FFF0F5",lawngreen:"7CFC00",lemonchiffon:"FFFACD",lightblue:"ADD8E6",lightcoral:"F08080",lightcyan:"E0FFFF",lightgoldenrodyellow:"FAFAD2",lightgreen:"90EE90",lightgrey:"D3D3D3",lightpink:"FFB6C1",lightsalmon:"FFA07A", +lightseagreen:"20B2AA",lightskyblue:"87CEFA",lightslategray:"789",lightsteelblue:"B0C4DE",lightyellow:"FFFFE0",lime:"0F0",limegreen:"32CD32",linen:"FAF0E6",magenta:"F0F",maroon:"800000",mediumauqamarine:"66CDAA",mediumblue:"0000CD",mediumorchid:"BA55D3",mediumpurple:"9370D8",mediumseagreen:"3CB371",mediumslateblue:"7B68EE",mediumspringgreen:"00FA9A",mediumturquoise:"48D1CC",mediumvioletred:"C71585",midnightblue:"191970",mintcream:"F5FFFA",mistyrose:"FFE4E1",moccasin:"FFE4B5",navajowhite:"FFDEAD", +navy:"000080",oldlace:"FDF5E6",olive:"808000",olivedrab:"688E23",orange:"FFA500",orangered:"FF4500",orchid:"DA70D6",palegoldenrod:"EEE8AA",palegreen:"98FB98",paleturquoise:"AFEEEE",palevioletred:"D87093",papayawhip:"FFEFD5",peachpuff:"FFDAB9",peru:"CD853F",pink:"FFC0CB",plum:"DDA0DD",powderblue:"B0E0E6",purple:"800080",red:"F00",rosybrown:"BC8F8F",royalblue:"4169E1",saddlebrown:"8B4513",salmon:"FA8072",sandybrown:"F4A460",seagreen:"2E8B57",seashell:"FFF5EE",sienna:"A0522D",silver:"C0C0C0",skyblue:"87CEEB", +slateblue:"6A5ACD",slategray:"708090",snow:"FFFAFA",springgreen:"00FF7F",steelblue:"4682B4",tan:"D2B48C",teal:"008080",thistle:"D8BFD8",tomato:"FF6347",turquoise:"40E0D0",violet:"EE82EE",wheat:"F5DEB3",white:"FFF",whitesmoke:"F5F5F5",yellow:"FF0",yellowgreen:"9ACD32"};a.prototype={parse:function(){if(!this.Ua){var c=this.Y,d;if(d=c.match(a.Qd)){this.Ua="rgb("+d[1]+","+d[2]+","+d[3]+")";this.Yb=parseFloat(d[4])}else{if((d=c.toLowerCase())in a.Fb)c="#"+a.Fb[d];this.Ua=c;this.Yb=c==="transparent"?0: +1}}},U:function(c){this.parse();return this.Ua==="currentColor"?c.currentStyle.color:this.Ua},fa:function(){this.parse();return this.Yb}};f.ha=function(c){return b[c]||(b[c]=new a(c))};return a}();f.v=function(){function a(c){this.$a=c;this.ch=0;this.X=[];this.Ga=0}var b=a.qa={Ia:1,Wb:2,z:4,Lc:8,Xb:16,na:32,K:64,oa:128,pa:256,Ra:512,Tc:1024,URL:2048};a.ob=function(c,d){this.k=c;this.d=d};a.ob.prototype={Ca:function(){return this.k&b.K||this.k&b.oa&&this.d==="0"},W:function(){return this.Ca()||this.k& +b.Ra}};a.prototype={de:/\s/,Kd:/^[\+\-]?(\d*\.)?\d+/,url:/^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i,nc:/^\-?[_a-z][\w-]*/i,Yd:/^("([^"]*)"|'([^']*)')/,Bd:/^#([\da-f]{6}|[\da-f]{3})/i,be:{px:b.K,em:b.K,ex:b.K,mm:b.K,cm:b.K,"in":b.K,pt:b.K,pc:b.K,deg:b.Ia,rad:b.Ia,grad:b.Ia},fd:{rgb:1,rgba:1,hsl:1,hsla:1},next:function(c){function d(p,r){p=new a.ob(p,r);if(!c){k.X.push(p);k.Ga++}return p}function e(){k.Ga++;return null}var g,j,i,h,k=this;if(this.Ga<this.X.length)return this.X[this.Ga++];for(;this.de.test(this.$a.charAt(this.ch));)this.ch++; +if(this.ch>=this.$a.length)return e();j=this.ch;g=this.$a.substring(this.ch);i=g.charAt(0);switch(i){case "#":if(h=g.match(this.Bd)){this.ch+=h[0].length;return d(b.z,h[0])}break;case '"':case "'":if(h=g.match(this.Yd)){this.ch+=h[0].length;return d(b.Tc,h[2]||h[3]||"")}break;case "/":case ",":this.ch++;return d(b.pa,i);case "u":if(h=g.match(this.url)){this.ch+=h[0].length;return d(b.URL,h[2]||h[3]||h[4]||"")}}if(h=g.match(this.Kd)){i=h[0];this.ch+=i.length;if(g.charAt(i.length)==="%"){this.ch++; +return d(b.Ra,i+"%")}if(h=g.substring(i.length).match(this.nc)){i+=h[0];this.ch+=h[0].length;return d(this.be[h[0].toLowerCase()]||b.Lc,i)}return d(b.oa,i)}if(h=g.match(this.nc)){i=h[0];this.ch+=i.length;if(i.toLowerCase()in f.Jc.Fb||i==="currentColor"||i==="transparent")return d(b.z,i);if(g.charAt(i.length)==="("){this.ch++;if(i.toLowerCase()in this.fd){g=function(p){return p&&p.k&b.oa};h=function(p){return p&&p.k&(b.oa|b.Ra)};var n=function(p,r){return p&&p.d===r},m=function(){return k.next(1)}; +if((i.charAt(0)==="r"?h(m()):g(m()))&&n(m(),",")&&h(m())&&n(m(),",")&&h(m())&&(i==="rgb"||i==="hsa"||n(m(),",")&&g(m()))&&n(m(),")"))return d(b.z,this.$a.substring(j,this.ch));return e()}return d(b.Xb,i)}return d(b.na,i)}this.ch++;return d(b.Wb,i)},D:function(){return this.X[this.Ga-- -2]},all:function(){for(;this.next(););return this.X},ma:function(c,d){for(var e=[],g,j;g=this.next();){if(c(g)){j=true;this.D();break}e.push(g)}return d&&!j?null:e}};return a}();var ha=function(a){this.e=a};ha.prototype= +{Z:0,Od:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.x!==b.x||a.y!==b.y)},Td:function(){var a=this.qb,b;return!a||(b=this.o())&&(a.h!==b.h||a.f!==b.f)},hc:function(){var a=this.e,b=a.getBoundingClientRect(),c=f.ja===9,d=f.O===7,e=b.right-b.left;return{x:b.left,y:b.top,h:c||d?a.offsetWidth:e,f:c||d?a.offsetHeight:b.bottom-b.top,Hd:d&&e?a.offsetWidth/e:1}},o:function(){return this.Z?this.Va||(this.Va=this.hc()):this.hc()},Ad:function(){return!!this.qb},cb:function(){++this.Z},hb:function(){if(!--this.Z){if(this.Va)this.qb= +this.Va;this.Va=null}}};(function(){function a(b){var c=f.p.Ba(b);return function(){if(this.Z){var d=this.$b||(this.$b={});return c in d?d[c]:(d[c]=b.call(this))}else return b.call(this)}}f.B={Z:0,ka:function(b){function c(d){this.e=d;this.Zb=this.ia()}f.p.Eb(c.prototype,f.B,b);c.$c={};return c},j:function(){var b=this.ia(),c=this.constructor.$c;return b?b in c?c[b]:(c[b]=this.la(b)):null},ia:a(function(){var b=this.e,c=this.constructor,d=b.style;b=b.currentStyle;var e=this.wa,g=this.Fa,j=c.Yc||(c.Yc= +f.F+e);c=c.Zc||(c.Zc=f.nb+g.charAt(0).toUpperCase()+g.substring(1));return d[c]||b.getAttribute(j)||d[g]||b.getAttribute(e)}),i:a(function(){return!!this.j()}),H:a(function(){var b=this.ia(),c=b!==this.Zb;this.Zb=b;return c}),va:a,cb:function(){++this.Z},hb:function(){--this.Z||delete this.$b}}})();f.Sb=f.B.ka({wa:f.F+"background",Fa:f.nb+"Background",cd:{scroll:1,fixed:1,local:1},fb:{"repeat-x":1,"repeat-y":1,repeat:1,"no-repeat":1},sc:{"padding-box":1,"border-box":1,"content-box":1},Pd:{top:1,right:1, +bottom:1,left:1,center:1},Ud:{contain:1,cover:1},eb:{Ma:"backgroundClip",z:"backgroundColor",da:"backgroundImage",Pa:"backgroundOrigin",S:"backgroundPosition",T:"backgroundRepeat",Sa:"backgroundSize"},la:function(a){function b(s){return s&&s.W()||s.k&k&&s.d in t}function c(s){return s&&(s.W()&&f.n(s.d)||s.d==="auto"&&"auto")}var d=this.e.currentStyle,e,g,j,i=f.v.qa,h=i.pa,k=i.na,n=i.z,m,p,r=0,t=this.Pd,v,l,q={M:[]};if(this.wb()){e=new f.v(a);for(j={};g=e.next();){m=g.k;p=g.d;if(!j.P&&m&i.Xb&&p=== +"linear-gradient"){v={ca:[],P:p};for(l={};g=e.next();){m=g.k;p=g.d;if(m&i.Wb&&p===")"){l.color&&v.ca.push(l);v.ca.length>1&&f.p.Eb(j,v);break}if(m&n){if(v.sa||v.zb){g=e.D();if(g.k!==h)break;e.next()}l={color:f.ha(p)};g=e.next();if(g.W())l.db=f.n(g.d);else e.D()}else if(m&i.Ia&&!v.sa&&!l.color&&!v.ca.length)v.sa=new f.Ec(g.d);else if(b(g)&&!v.zb&&!l.color&&!v.ca.length){e.D();v.zb=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&h&&p===","){if(l.color){v.ca.push(l);l={}}}else break}}else if(!j.P&& +m&i.URL){j.Ab=p;j.P="image"}else if(b(g)&&!j.$){e.D();j.$=new f.Ja(e.ma(function(s){return!b(s)},false))}else if(m&k)if(p in this.fb&&!j.bb)j.bb=p;else if(p in this.sc&&!j.Wa){j.Wa=p;if((g=e.next())&&g.k&k&&g.d in this.sc)j.ub=g.d;else{j.ub=p;e.D()}}else if(p in this.cd&&!j.bc)j.bc=p;else return null;else if(m&n&&!q.color)q.color=f.ha(p);else if(m&h&&p==="/"&&!j.Xa&&j.$){g=e.next();if(g.k&k&&g.d in this.Ud)j.Xa=new f.Ka(g.d);else if(g=c(g)){m=c(e.next());if(!m){m=g;e.D()}j.Xa=new f.Ka(g,m)}else return null}else if(m& +h&&p===","&&j.P){j.Hb=a.substring(r,e.ch-1);r=e.ch;q.M.push(j);j={}}else return null}if(j.P){j.Hb=a.substring(r);q.M.push(j)}}else this.Bc(f.ja<9?function(){var s=this.eb,o=d[s.S+"X"],u=d[s.S+"Y"],x=d[s.da],y=d[s.z];if(y!=="transparent")q.color=f.ha(y);if(x!=="none")q.M=[{P:"image",Ab:(new f.v(x)).next().d,bb:d[s.T],$:new f.Ja((new f.v(o+" "+u)).all())}]}:function(){var s=this.eb,o=/\s*,\s*/,u=d[s.da].split(o),x=d[s.z],y,z,B,E,D,C;if(x!=="transparent")q.color=f.ha(x);if((E=u.length)&&u[0]!=="none"){x= +d[s.T].split(o);y=d[s.S].split(o);z=d[s.Pa].split(o);B=d[s.Ma].split(o);s=d[s.Sa].split(o);q.M=[];for(o=0;o<E;o++)if((D=u[o])&&D!=="none"){C=s[o].split(" ");q.M.push({Hb:D+" "+x[o]+" "+y[o]+" / "+s[o]+" "+z[o]+" "+B[o],P:"image",Ab:(new f.v(D)).next().d,bb:x[o],$:new f.Ja((new f.v(y[o])).all()),Wa:z[o],ub:B[o],Xa:new f.Ka(C[0],C[1])})}}});return q.color||q.M[0]?q:null},Bc:function(a){var b=f.ja>8,c=this.eb,d=this.e.runtimeStyle,e=d[c.da],g=d[c.z],j=d[c.T],i,h,k,n;if(e)d[c.da]="";if(g)d[c.z]="";if(j)d[c.T]= +"";if(b){i=d[c.Ma];h=d[c.Pa];n=d[c.S];k=d[c.Sa];if(i)d[c.Ma]="";if(h)d[c.Pa]="";if(n)d[c.S]="";if(k)d[c.Sa]=""}a=a.call(this);if(e)d[c.da]=e;if(g)d[c.z]=g;if(j)d[c.T]=j;if(b){if(i)d[c.Ma]=i;if(h)d[c.Pa]=h;if(n)d[c.S]=n;if(k)d[c.Sa]=k}return a},ia:f.B.va(function(){return this.wb()||this.Bc(function(){var a=this.e.currentStyle,b=this.eb;return a[b.z]+" "+a[b.da]+" "+a[b.T]+" "+a[b.S+"X"]+" "+a[b.S+"Y"]})}),wb:f.B.va(function(){var a=this.e;return a.style[this.Fa]||a.currentStyle.getAttribute(this.wa)}), +qc:function(){var a=0;if(f.O<7){a=this.e;a=""+(a.style[f.nb+"PngFix"]||a.currentStyle.getAttribute(f.F+"png-fix"))==="true"}return a},i:f.B.va(function(){return(this.wb()||this.qc())&&!!this.j()})});f.Vb=f.B.ka({wc:["Top","Right","Bottom","Left"],Id:{thin:"1px",medium:"3px",thick:"5px"},la:function(){var a={},b={},c={},d=false,e=true,g=true,j=true;this.Cc(function(){for(var i=this.e.currentStyle,h=0,k,n,m,p,r,t,v;h<4;h++){m=this.wc[h];v=m.charAt(0).toLowerCase();k=b[v]=i["border"+m+"Style"];n=i["border"+ +m+"Color"];m=i["border"+m+"Width"];if(h>0){if(k!==p)g=false;if(n!==r)e=false;if(m!==t)j=false}p=k;r=n;t=m;c[v]=f.ha(n);m=a[v]=f.n(b[v]==="none"?"0":this.Id[m]||m);if(m.a(this.e)>0)d=true}});return d?{J:a,Zd:b,gd:c,ee:j,hd:e,$d:g}:null},ia:f.B.va(function(){var a=this.e,b=a.currentStyle,c;a.tagName in f.Ac&&a.offsetParent.currentStyle.borderCollapse==="collapse"||this.Cc(function(){c=b.borderWidth+"|"+b.borderStyle+"|"+b.borderColor});return c}),Cc:function(a){var b=this.e.runtimeStyle,c=b.borderWidth, +d=b.borderColor;if(c)b.borderWidth="";if(d)b.borderColor="";a=a.call(this);if(c)b.borderWidth=c;if(d)b.borderColor=d;return a}});(function(){f.jb=f.B.ka({wa:"border-radius",Fa:"borderRadius",la:function(b){var c=null,d,e,g,j,i=false;if(b){e=new f.v(b);var h=function(){for(var k=[],n;(g=e.next())&&g.W();){j=f.n(g.d);n=j.ic();if(n<0)return null;if(n>0)i=true;k.push(j)}return k.length>0&&k.length<5?{tl:k[0],tr:k[1]||k[0],br:k[2]||k[0],bl:k[3]||k[1]||k[0]}:null};if(b=h()){if(g){if(g.k&f.v.qa.pa&&g.d=== +"/")d=h()}else d=b;if(i&&b&&d)c={x:b,y:d}}}return c}});var a=f.n("0");a={tl:a,tr:a,br:a,bl:a};f.jb.Dc={x:a,y:a}})();f.Ub=f.B.ka({wa:"border-image",Fa:"borderImage",fb:{stretch:1,round:1,repeat:1,space:1},la:function(a){var b=null,c,d,e,g,j,i,h=0,k=f.v.qa,n=k.na,m=k.oa,p=k.Ra;if(a){c=new f.v(a);b={};for(var r=function(l){return l&&l.k&k.pa&&l.d==="/"},t=function(l){return l&&l.k&n&&l.d==="fill"},v=function(){g=c.ma(function(l){return!(l.k&(m|p))});if(t(c.next())&&!b.fill)b.fill=true;else c.D();if(r(c.next())){h++; +j=c.ma(function(l){return!l.W()&&!(l.k&n&&l.d==="auto")});if(r(c.next())){h++;i=c.ma(function(l){return!l.Ca()})}}else c.D()};a=c.next();){d=a.k;e=a.d;if(d&(m|p)&&!g){c.D();v()}else if(t(a)&&!b.fill){b.fill=true;v()}else if(d&n&&this.fb[e]&&!b.repeat){b.repeat={f:e};if(a=c.next())if(a.k&n&&this.fb[a.d])b.repeat.Ob=a.d;else c.D()}else if(d&k.URL&&!b.src)b.src=e;else return null}if(!b.src||!g||g.length<1||g.length>4||j&&j.length>4||h===1&&j.length<1||i&&i.length>4||h===2&&i.length<1)return null;if(!b.repeat)b.repeat= +{f:"stretch"};if(!b.repeat.Ob)b.repeat.Ob=b.repeat.f;a=function(l,q){return{t:q(l[0]),r:q(l[1]||l[0]),b:q(l[2]||l[0]),l:q(l[3]||l[1]||l[0])}};b.slice=a(g,function(l){return f.n(l.k&m?l.d+"px":l.d)});if(j&&j[0])b.J=a(j,function(l){return l.W()?f.n(l.d):l.d});if(i&&i[0])b.Da=a(i,function(l){return l.Ca()?f.n(l.d):l.d})}return b}});f.Ic=f.B.ka({wa:"box-shadow",Fa:"boxShadow",la:function(a){var b,c=f.n,d=f.v.qa,e;if(a){e=new f.v(a);b={Da:[],Bb:[]};for(a=function(){for(var g,j,i,h,k,n;g=e.next();){i=g.d; +j=g.k;if(j&d.pa&&i===",")break;else if(g.Ca()&&!k){e.D();k=e.ma(function(m){return!m.Ca()})}else if(j&d.z&&!h)h=i;else if(j&d.na&&i==="inset"&&!n)n=true;else return false}g=k&&k.length;if(g>1&&g<5){(n?b.Bb:b.Da).push({fe:c(k[0].d),ge:c(k[1].d),blur:c(k[2]?k[2].d:"0"),Vd:c(k[3]?k[3].d:"0"),color:f.ha(h||"currentColor")});return true}return false};a(););}return b&&(b.Bb.length||b.Da.length)?b:null}});f.Uc=f.B.ka({ia:f.B.va(function(){var a=this.e.currentStyle;return a.visibility+"|"+a.display}),la:function(){var a= +this.e,b=a.runtimeStyle;a=a.currentStyle;var c=b.visibility,d;b.visibility="";d=a.visibility;b.visibility=c;return{ce:d!=="hidden",nd:a.display!=="none"}},i:function(){return false}});f.u={R:function(a){function b(c,d,e,g){this.e=c;this.s=d;this.g=e;this.parent=g}f.p.Eb(b.prototype,f.u,a);return b},Cb:false,Q:function(){return false},Ea:f.aa,Lb:function(){this.m();this.i()&&this.V()},ib:function(){this.Cb=true},Mb:function(){this.i()?this.V():this.m()},sb:function(a,b){this.vc(a);for(var c=this.ra|| +(this.ra=[]),d=a+1,e=c.length,g;d<e;d++)if(g=c[d])break;c[a]=b;this.I().insertBefore(b,g||null)},za:function(a){var b=this.ra;return b&&b[a]||null},vc:function(a){var b=this.za(a),c=this.Ta;if(b&&c){c.removeChild(b);this.ra[a]=null}},Aa:function(a,b,c,d){var e=this.rb||(this.rb={}),g=e[a];if(!g){g=e[a]=f.p.Za("shape");if(b)g.appendChild(g[b]=f.p.Za(b));if(d){c=this.za(d);if(!c){this.sb(d,doc.createElement("group"+d));c=this.za(d)}}c.appendChild(g);a=g.style;a.position="absolute";a.left=a.top=0;a.behavior= +"url(#default#VML)"}return g},vb:function(a){var b=this.rb,c=b&&b[a];if(c){c.parentNode.removeChild(c);delete b[a]}return!!c},kc:function(a){var b=this.e,c=this.s.o(),d=c.h,e=c.f,g,j,i,h,k,n;c=a.x.tl.a(b,d);g=a.y.tl.a(b,e);j=a.x.tr.a(b,d);i=a.y.tr.a(b,e);h=a.x.br.a(b,d);k=a.y.br.a(b,e);n=a.x.bl.a(b,d);a=a.y.bl.a(b,e);d=Math.min(d/(c+j),e/(i+k),d/(n+h),e/(g+a));if(d<1){c*=d;g*=d;j*=d;i*=d;h*=d;k*=d;n*=d;a*=d}return{x:{tl:c,tr:j,br:h,bl:n},y:{tl:g,tr:i,br:k,bl:a}}},ya:function(a,b,c){b=b||1;var d,e, +g=this.s.o();e=g.h*b;g=g.f*b;var j=this.g.G,i=Math.floor,h=Math.ceil,k=a?a.Jb*b:0,n=a?a.Ib*b:0,m=a?a.tb*b:0;a=a?a.Db*b:0;var p,r,t,v,l;if(c||j.i()){d=this.kc(c||j.j());c=d.x.tl*b;j=d.y.tl*b;p=d.x.tr*b;r=d.y.tr*b;t=d.x.br*b;v=d.y.br*b;l=d.x.bl*b;b=d.y.bl*b;e="m"+i(a)+","+i(j)+"qy"+i(c)+","+i(k)+"l"+h(e-p)+","+i(k)+"qx"+h(e-n)+","+i(r)+"l"+h(e-n)+","+h(g-v)+"qy"+h(e-t)+","+h(g-m)+"l"+i(l)+","+h(g-m)+"qx"+i(a)+","+h(g-b)+" x e"}else e="m"+i(a)+","+i(k)+"l"+h(e-n)+","+i(k)+"l"+h(e-n)+","+h(g-m)+"l"+i(a)+ +","+h(g-m)+"xe";return e},I:function(){var a=this.parent.za(this.N),b;if(!a){a=doc.createElement(this.Ya);b=a.style;b.position="absolute";b.top=b.left=0;this.parent.sb(this.N,a)}return a},mc:function(){var a=this.e,b=a.currentStyle,c=a.runtimeStyle,d=a.tagName,e=f.O===6,g;if(e&&(d in f.cc||d==="FIELDSET")||d==="BUTTON"||d==="INPUT"&&a.type in f.Gd){c.borderWidth="";d=this.g.w.wc;for(g=d.length;g--;){e=d[g];c["padding"+e]="";c["padding"+e]=f.n(b["padding"+e]).a(a)+f.n(b["border"+e+"Width"]).a(a)+(f.O!== +8&&g%2?1:0)}c.borderWidth=0}else if(e){if(a.childNodes.length!==1||a.firstChild.tagName!=="ie6-mask"){b=doc.createElement("ie6-mask");d=b.style;d.visibility="visible";for(d.zoom=1;d=a.firstChild;)b.appendChild(d);a.appendChild(b);c.visibility="hidden"}}else c.borderColor="transparent"},ie:function(){},m:function(){this.parent.vc(this.N);delete this.rb;delete this.ra}};f.Rc=f.u.R({i:function(){var a=this.ed;for(var b in a)if(a.hasOwnProperty(b)&&a[b].i())return true;return false},Q:function(){return this.g.Pb.H()}, +ib:function(){if(this.i()){var a=this.jc(),b=a,c;a=a.currentStyle;var d=a.position,e=this.I().style,g=0,j=0;j=this.s.o();var i=j.Hd;if(d==="fixed"&&f.O>6){g=j.x*i;j=j.y*i;b=d}else{do b=b.offsetParent;while(b&&b.currentStyle.position==="static");if(b){c=b.getBoundingClientRect();b=b.currentStyle;g=(j.x-c.left)*i-(parseFloat(b.borderLeftWidth)||0);j=(j.y-c.top)*i-(parseFloat(b.borderTopWidth)||0)}else{b=doc.documentElement;g=(j.x+b.scrollLeft-b.clientLeft)*i;j=(j.y+b.scrollTop-b.clientTop)*i}b="absolute"}e.position= +b;e.left=g;e.top=j;e.zIndex=d==="static"?-1:a.zIndex;this.Cb=true}},Mb:f.aa,Nb:function(){var a=this.g.Pb.j();this.I().style.display=a.ce&&a.nd?"":"none"},Lb:function(){this.i()?this.Nb():this.m()},jc:function(){var a=this.e;return a.tagName in f.Ac?a.offsetParent:a},I:function(){var a=this.Ta,b;if(!a){b=this.jc();a=this.Ta=doc.createElement("css3-container");a.style.direction="ltr";this.Nb();b.parentNode.insertBefore(a,b)}return a},ab:f.aa,m:function(){var a=this.Ta,b;if(a&&(b=a.parentNode))b.removeChild(a); +delete this.Ta;delete this.ra}});f.Fc=f.u.R({N:2,Ya:"background",Q:function(){var a=this.g;return a.C.H()||a.G.H()},i:function(){var a=this.g;return a.q.i()||a.G.i()||a.C.i()||a.ga.i()&&a.ga.j().Bb},V:function(){var a=this.s.o();if(a.h&&a.f){this.od();this.pd()}},od:function(){var a=this.g.C.j(),b=this.s.o(),c=this.e,d=a&&a.color,e,g;if(d&&d.fa()>0){this.lc();a=this.Aa("bgColor","fill",this.I(),1);e=b.h;b=b.f;a.stroked=false;a.coordsize=e*2+","+b*2;a.coordorigin="1,1";a.path=this.ya(null,2);g=a.style; +g.width=e;g.height=b;a.fill.color=d.U(c);c=d.fa();if(c<1)a.fill.opacity=c}else this.vb("bgColor")},pd:function(){var a=this.g.C.j(),b=this.s.o();a=a&&a.M;var c,d,e,g,j;if(a){this.lc();d=b.h;e=b.f;for(j=a.length;j--;){b=a[j];c=this.Aa("bgImage"+j,"fill",this.I(),2);c.stroked=false;c.fill.type="tile";c.fillcolor="none";c.coordsize=d*2+","+e*2;c.coordorigin="1,1";c.path=this.ya(0,2);g=c.style;g.width=d;g.height=e;if(b.P==="linear-gradient")this.bd(c,b);else{c.fill.src=b.Ab;this.Nd(c,j)}}}for(j=a?a.length: +0;this.vb("bgImage"+j++););},Nd:function(a,b){var c=this;f.p.Rb(a.fill.src,function(d){var e=c.e,g=c.s.o(),j=g.h;g=g.f;if(j&&g){var i=a.fill,h=c.g,k=h.w.j(),n=k&&k.J;k=n?n.t.a(e):0;var m=n?n.r.a(e):0,p=n?n.b.a(e):0;n=n?n.l.a(e):0;h=h.C.j().M[b];e=h.$?h.$.coords(e,j-d.h-n-m,g-d.f-k-p):{x:0,y:0};h=h.bb;p=m=0;var r=j+1,t=g+1,v=f.O===8?0:1;n=Math.round(e.x)+n+0.5;k=Math.round(e.y)+k+0.5;i.position=n/j+","+k/g;i.size.x=1;i.size=d.h+"px,"+d.f+"px";if(h&&h!=="repeat"){if(h==="repeat-x"||h==="no-repeat"){m= +k+1;t=k+d.f+v}if(h==="repeat-y"||h==="no-repeat"){p=n+1;r=n+d.h+v}a.style.clip="rect("+m+"px,"+r+"px,"+t+"px,"+p+"px)"}}})},bd:function(a,b){var c=this.e,d=this.s.o(),e=d.h,g=d.f;a=a.fill;d=b.ca;var j=d.length,i=Math.PI,h=f.Na,k=h.tc,n=h.dc;b=h.gc(c,e,g,b);h=b.sa;var m=b.xc,p=b.yc,r=b.Wd,t=b.Xd,v=b.rd,l=b.sd,q=b.kd,s=b.ld;b=b.rc;e=h%90?Math.atan2(q*e/g,s)/i*180:h+90;e+=180;e%=360;v=k(r,t,h,v,l);g=n(r,t,v[0],v[1]);i=[];v=k(m,p,h,r,t);n=n(m,p,v[0],v[1])/g*100;k=[];for(h=0;h<j;h++)k.push(d[h].db?d[h].db.a(c, +b):h===0?0:h===j-1?b:null);for(h=1;h<j;h++){if(k[h]===null){m=k[h-1];b=h;do p=k[++b];while(p===null);k[h]=m+(p-m)/(b-h+1)}k[h]=Math.max(k[h],k[h-1])}for(h=0;h<j;h++)i.push(n+k[h]/g*100+"% "+d[h].color.U(c));a.angle=e;a.type="gradient";a.method="sigma";a.color=d[0].color.U(c);a.color2=d[j-1].color.U(c);if(a.colors)a.colors.value=i.join(",");else a.colors=i.join(",")},lc:function(){var a=this.e.runtimeStyle;a.backgroundImage="url(about:blank)";a.backgroundColor="transparent"},m:function(){f.u.m.call(this); +var a=this.e.runtimeStyle;a.backgroundImage=a.backgroundColor=""}});f.Gc=f.u.R({N:4,Ya:"border",Q:function(){var a=this.g;return a.w.H()||a.G.H()},i:function(){var a=this.g;return a.G.i()&&!a.q.i()&&a.w.i()},V:function(){var a=this.e,b=this.g.w.j(),c=this.s.o(),d=c.h;c=c.f;var e,g,j,i,h;if(b){this.mc();b=this.wd(2);i=0;for(h=b.length;i<h;i++){j=b[i];e=this.Aa("borderPiece"+i,j.stroke?"stroke":"fill",this.I());e.coordsize=d*2+","+c*2;e.coordorigin="1,1";e.path=j.path;g=e.style;g.width=d;g.height=c; +e.filled=!!j.fill;e.stroked=!!j.stroke;if(j.stroke){e=e.stroke;e.weight=j.Qb+"px";e.color=j.color.U(a);e.dashstyle=j.stroke==="dashed"?"2 2":j.stroke==="dotted"?"1 1":"solid";e.linestyle=j.stroke==="double"&&j.Qb>2?"ThinThin":"Single"}else e.fill.color=j.fill.U(a)}for(;this.vb("borderPiece"+i++););}},wd:function(a){var b=this.e,c,d,e,g=this.g.w,j=[],i,h,k,n,m=Math.round,p,r,t;if(g.i()){c=g.j();g=c.J;r=c.Zd;t=c.gd;if(c.ee&&c.$d&&c.hd){if(t.t.fa()>0){c=g.t.a(b);k=c/2;j.push({path:this.ya({Jb:k,Ib:k, +tb:k,Db:k},a),stroke:r.t,color:t.t,Qb:c})}}else{a=a||1;c=this.s.o();d=c.h;e=c.f;c=m(g.t.a(b));k=m(g.r.a(b));n=m(g.b.a(b));b=m(g.l.a(b));var v={t:c,r:k,b:n,l:b};b=this.g.G;if(b.i())p=this.kc(b.j());i=Math.floor;h=Math.ceil;var l=function(o,u){return p?p[o][u]:0},q=function(o,u,x,y,z,B){var E=l("x",o),D=l("y",o),C=o.charAt(1)==="r";o=o.charAt(0)==="b";return E>0&&D>0?(B?"al":"ae")+(C?h(d-E):i(E))*a+","+(o?h(e-D):i(D))*a+","+(i(E)-u)*a+","+(i(D)-x)*a+","+y*65535+","+2949075*(z?1:-1):(B?"m":"l")+(C?d- +u:u)*a+","+(o?e-x:x)*a},s=function(o,u,x,y){var z=o==="t"?i(l("x","tl"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+i(l("y","tr"))*a:o==="b"?h(d-l("x","br"))*a+","+i(e-u)*a:i(u)*a+","+h(e-l("y","bl"))*a;o=o==="t"?h(d-l("x","tr"))*a+","+h(u)*a:o==="r"?h(d-u)*a+","+h(e-l("y","br"))*a:o==="b"?i(l("x","bl"))*a+","+i(e-u)*a:i(u)*a+","+i(l("y","tl"))*a;return x?(y?"m"+o:"")+"l"+z:(y?"m"+z:"")+"l"+o};b=function(o,u,x,y,z,B){var E=o==="l"||o==="r",D=v[o],C,F;if(D>0&&r[o]!=="none"&&t[o].fa()>0){C=v[E?o:u];u=v[E?u: +o];F=v[E?o:x];x=v[E?x:o];if(r[o]==="dashed"||r[o]==="dotted"){j.push({path:q(y,C,u,B+45,0,1)+q(y,0,0,B,1,0),fill:t[o]});j.push({path:s(o,D/2,0,1),stroke:r[o],Qb:D,color:t[o]});j.push({path:q(z,F,x,B,0,1)+q(z,0,0,B-45,1,0),fill:t[o]})}else j.push({path:q(y,C,u,B+45,0,1)+s(o,D,0,0)+q(z,F,x,B,0,0)+(r[o]==="double"&&D>2?q(z,F-i(F/3),x-i(x/3),B-45,1,0)+s(o,h(D/3*2),1,0)+q(y,C-i(C/3),u-i(u/3),B,1,0)+"x "+q(y,i(C/3),i(u/3),B+45,0,1)+s(o,i(D/3),1,0)+q(z,i(F/3),i(x/3),B,0,0):"")+q(z,0,0,B-45,1,0)+s(o,0,1, +0)+q(y,0,0,B,1,0),fill:t[o]})}};b("t","l","r","tl","tr",90);b("r","t","b","tr","br",0);b("b","r","l","br","bl",-90);b("l","b","t","bl","tl",-180)}}return j},m:function(){if(this.ec||!this.g.q.i())this.e.runtimeStyle.borderColor="";f.u.m.call(this)}});f.Tb=f.u.R({N:5,Md:["t","tr","r","br","b","bl","l","tl","c"],Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){this.I();var a=this.g.q.j(),b=this.g.w.j(),c=this.s.o(),d=this.e,e=this.uc;f.p.Rb(a.src,function(g){function j(s, +o,u,x,y){s=e[s].style;var z=Math.max;s.width=z(o,0);s.height=z(u,0);s.left=x;s.top=y}function i(s,o,u){for(var x=0,y=s.length;x<y;x++)e[s[x]].imagedata[o]=u}var h=c.h,k=c.f,n=f.n("0"),m=a.J||(b?b.J:{t:n,r:n,b:n,l:n});n=m.t.a(d);var p=m.r.a(d),r=m.b.a(d);m=m.l.a(d);var t=a.slice,v=t.t.a(d),l=t.r.a(d),q=t.b.a(d);t=t.l.a(d);j("tl",m,n,0,0);j("t",h-m-p,n,m,0);j("tr",p,n,h-p,0);j("r",p,k-n-r,h-p,n);j("br",p,r,h-p,k-r);j("b",h-m-p,r,m,k-r);j("bl",m,r,0,k-r);j("l",m,k-n-r,0,n);j("c",h-m-p,k-n-r,m,n);i(["tl", +"t","tr"],"cropBottom",(g.f-v)/g.f);i(["tl","l","bl"],"cropRight",(g.h-t)/g.h);i(["bl","b","br"],"cropTop",(g.f-q)/g.f);i(["tr","r","br"],"cropLeft",(g.h-l)/g.h);i(["l","r","c"],"cropTop",v/g.f);i(["l","r","c"],"cropBottom",q/g.f);i(["t","b","c"],"cropLeft",t/g.h);i(["t","b","c"],"cropRight",l/g.h);e.c.style.display=a.fill?"":"none"},this)},I:function(){var a=this.parent.za(this.N),b,c,d,e=this.Md,g=e.length;if(!a){a=doc.createElement("border-image");b=a.style;b.position="absolute";this.uc={};for(d= +0;d<g;d++){c=this.uc[e[d]]=f.p.Za("rect");c.appendChild(f.p.Za("imagedata"));b=c.style;b.behavior="url(#default#VML)";b.position="absolute";b.top=b.left=0;c.imagedata.src=this.g.q.j().src;c.stroked=false;c.filled=false;a.appendChild(c)}this.parent.sb(this.N,a)}return a},Ea:function(){if(this.i()){var a=this.e,b=a.runtimeStyle,c=this.g.q.j().J;b.borderStyle="solid";if(c){b.borderTopWidth=c.t.a(a)+"px";b.borderRightWidth=c.r.a(a)+"px";b.borderBottomWidth=c.b.a(a)+"px";b.borderLeftWidth=c.l.a(a)+"px"}this.mc()}}, +m:function(){var a=this.e.runtimeStyle;a.borderStyle="";if(this.ec||!this.g.w.i())a.borderColor=a.borderWidth="";f.u.m.call(this)}});f.Hc=f.u.R({N:1,Ya:"outset-box-shadow",Q:function(){var a=this.g;return a.ga.H()||a.G.H()},i:function(){var a=this.g.ga;return a.i()&&a.j().Da[0]},V:function(){function a(C,F,O,H,M,P,I){C=b.Aa("shadow"+C+F,"fill",d,j-C);F=C.fill;C.coordsize=n*2+","+m*2;C.coordorigin="1,1";C.stroked=false;C.filled=true;F.color=M.U(c);if(P){F.type="gradienttitle";F.color2=F.color;F.opacity= +0}C.path=I;l=C.style;l.left=O;l.top=H;l.width=n;l.height=m;return C}var b=this,c=this.e,d=this.I(),e=this.g,g=e.ga.j().Da;e=e.G.j();var j=g.length,i=j,h,k=this.s.o(),n=k.h,m=k.f;k=f.O===8?1:0;for(var p=["tl","tr","br","bl"],r,t,v,l,q,s,o,u,x,y,z,B,E,D;i--;){t=g[i];q=t.fe.a(c);s=t.ge.a(c);h=t.Vd.a(c);o=t.blur.a(c);t=t.color;u=-h-o;if(!e&&o)e=f.jb.Dc;u=this.ya({Jb:u,Ib:u,tb:u,Db:u},2,e);if(o){x=(h+o)*2+n;y=(h+o)*2+m;z=x?o*2/x:0;B=y?o*2/y:0;if(o-h>n/2||o-h>m/2)for(h=4;h--;){r=p[h];E=r.charAt(0)==="b"; +D=r.charAt(1)==="r";r=a(i,r,q,s,t,o,u);v=r.fill;v.focusposition=(D?1-z:z)+","+(E?1-B:B);v.focussize="0,0";r.style.clip="rect("+((E?y/2:0)+k)+"px,"+(D?x:x/2)+"px,"+(E?y:y/2)+"px,"+((D?x/2:0)+k)+"px)"}else{r=a(i,"",q,s,t,o,u);v=r.fill;v.focusposition=z+","+B;v.focussize=1-z*2+","+(1-B*2)}}else{r=a(i,"",q,s,t,o,u);q=t.fa();if(q<1)r.fill.opacity=q}}}});f.Pc=f.u.R({N:6,Ya:"imgEl",Q:function(){var a=this.g;return this.e.src!==this.Xc||a.G.H()},i:function(){var a=this.g;return a.G.i()||a.C.qc()},V:function(){this.Xc= +j;this.Cd();var a=this.Aa("img","fill",this.I()),b=a.fill,c=this.s.o(),d=c.h;c=c.f;var e=this.g.w.j(),g=e&&e.J;e=this.e;var j=e.src,i=Math.round,h=e.currentStyle,k=f.n;if(!g||f.O<7){g=f.n("0");g={t:g,r:g,b:g,l:g}}a.stroked=false;b.type="frame";b.src=j;b.position=(d?0.5/d:0)+","+(c?0.5/c:0);a.coordsize=d*2+","+c*2;a.coordorigin="1,1";a.path=this.ya({Jb:i(g.t.a(e)+k(h.paddingTop).a(e)),Ib:i(g.r.a(e)+k(h.paddingRight).a(e)),tb:i(g.b.a(e)+k(h.paddingBottom).a(e)),Db:i(g.l.a(e)+k(h.paddingLeft).a(e))}, +2);a=a.style;a.width=d;a.height=c},Cd:function(){this.e.runtimeStyle.filter="alpha(opacity=0)"},m:function(){f.u.m.call(this);this.e.runtimeStyle.filter=""}});f.Oc=f.u.R({ib:f.aa,Mb:f.aa,Nb:f.aa,Lb:f.aa,Ld:/^,+|,+$/g,Fd:/,+/g,gb:function(a,b){(this.pb||(this.pb=[]))[a]=b||void 0},ab:function(){var a=this.pb,b;if(a&&(b=a.join(",").replace(this.Ld,"").replace(this.Fd,","))!==this.Wc)this.Wc=this.e.runtimeStyle.background=b},m:function(){this.e.runtimeStyle.background="";delete this.pb}});f.Mc=f.u.R({ua:1, +Q:function(){return this.g.C.H()},i:function(){var a=this.g;return a.C.i()||a.q.i()},V:function(){var a=this.g.C.j(),b,c,d=0,e,g;if(a){b=[];if(c=a.M)for(;e=c[d++];)if(e.P==="linear-gradient"){g=this.vd(e.Wa);g=(e.Xa||f.Ka.Kc).a(this.e,g.h,g.f,g.h,g.f);b.push("url(data:image/svg+xml,"+escape(this.xd(e,g.h,g.f))+") "+this.dd(e.$)+" / "+g.h+"px "+g.f+"px "+(e.bc||"")+" "+(e.Wa||"")+" "+(e.ub||""))}else b.push(e.Hb);a.color&&b.push(a.color.Y);this.parent.gb(this.ua,b.join(","))}},dd:function(a){return a? +a.X.map(function(b){return b.d}).join(" "):"0 0"},vd:function(a){var b=this.e,c=this.s.o(),d=c.h;c=c.f;var e;if(a!=="border-box")if((e=this.g.w.j())&&(e=e.J)){d-=e.l.a(b)+e.l.a(b);c-=e.t.a(b)+e.b.a(b)}if(a==="content-box"){a=f.n;e=b.currentStyle;d-=a(e.paddingLeft).a(b)+a(e.paddingRight).a(b);c-=a(e.paddingTop).a(b)+a(e.paddingBottom).a(b)}return{h:d,f:c}},xd:function(a,b,c){var d=this.e,e=a.ca,g=e.length,j=f.Na.gc(d,b,c,a);a=j.xc;var i=j.yc,h=j.td,k=j.ud;j=j.rc;var n,m,p,r,t;n=[];for(m=0;m<g;m++)n.push(e[m].db? +e[m].db.a(d,j):m===0?0:m===g-1?j:null);for(m=1;m<g;m++)if(n[m]===null){r=n[m-1];p=m;do t=n[++p];while(t===null);n[m]=r+(t-r)/(p-m+1)}b=['<svg width="'+b+'" height="'+c+'" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="g" gradientUnits="userSpaceOnUse" x1="'+a/b*100+'%" y1="'+i/c*100+'%" x2="'+h/b*100+'%" y2="'+k/c*100+'%">'];for(m=0;m<g;m++)b.push('<stop offset="'+n[m]/j+'" stop-color="'+e[m].color.U(d)+'" stop-opacity="'+e[m].color.fa()+'"/>');b.push('</linearGradient></defs><rect width="100%" height="100%" fill="url(#g)"/></svg>'); +return b.join("")},m:function(){this.parent.gb(this.ua)}});f.Nc=f.u.R({T:"repeat",Sc:"stretch",Qc:"round",ua:0,Q:function(){return this.g.q.H()},i:function(){return this.g.q.i()},V:function(){var a=this,b=a.g.q.j(),c=a.g.w.j(),d=a.s.o(),e=b.repeat,g=e.f,j=e.Ob,i=a.e,h=0;f.p.Rb(b.src,function(k){function n(Q,R,U,V,W,Y,X,S,w,A){K.push('<pattern patternUnits="userSpaceOnUse" id="pattern'+G+'" x="'+(g===l?Q+U/2-w/2:Q)+'" y="'+(j===l?R+V/2-A/2:R)+'" width="'+w+'" height="'+A+'"><svg width="'+w+'" height="'+ +A+'" viewBox="'+W+" "+Y+" "+X+" "+S+'" preserveAspectRatio="none"><image xlink:href="'+v+'" x="0" y="0" width="'+r+'" height="'+t+'" /></svg></pattern>');J.push('<rect x="'+Q+'" y="'+R+'" width="'+U+'" height="'+V+'" fill="url(#pattern'+G+')" />');G++}var m=d.h,p=d.f,r=k.h,t=k.f,v=a.Dd(b.src,r,t),l=a.T,q=a.Sc;k=a.Qc;var s=Math.ceil,o=f.n("0"),u=b.J||(c?c.J:{t:o,r:o,b:o,l:o});o=u.t.a(i);var x=u.r.a(i),y=u.b.a(i);u=u.l.a(i);var z=b.slice,B=z.t.a(i),E=z.r.a(i),D=z.b.a(i);z=z.l.a(i);var C=m-u-x,F=p-o- +y,O=r-z-E,H=t-B-D,M=g===q?C:O*o/B,P=j===q?F:H*x/E,I=g===q?C:O*y/D;q=j===q?F:H*u/z;var K=[],J=[],G=0;if(g===k){M-=(M-(C%M||M))/s(C/M);I-=(I-(C%I||I))/s(C/I)}if(j===k){P-=(P-(F%P||P))/s(F/P);q-=(q-(F%q||q))/s(F/q)}k=['<svg width="'+m+'" height="'+p+'" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'];n(0,0,u,o,0,0,z,B,u,o);n(u,0,C,o,z,0,O,B,M,o);n(m-x,0,x,o,r-E,0,E,B,x,o);n(0,o,u,F,0,B,z,H,u,q);if(b.fill)n(u,o,C,F,z,B,O,H,M||I||O,q||P||H);n(m-x,o,x,F,r-E,B,E,H,x,P);n(0, +p-y,u,y,0,t-D,z,D,u,y);n(u,p-y,C,y,z,t-D,O,D,I,y);n(m-x,p-y,x,y,r-E,t-D,E,D,x,y);k.push("<defs>"+K.join("\n")+"</defs>"+J.join("\n")+"</svg>");a.parent.gb(a.ua,"url(data:image/svg+xml,"+escape(k.join(""))+") no-repeat border-box border-box");h&&a.parent.ab()},a);h=1},Dd:function(){var a={};return function(b,c,d){var e=a[b],g;if(!e){e=new Image;g=doc.createElement("canvas");e.src=b;g.width=c;g.height=d;g.getContext("2d").drawImage(e,0,0);e=a[b]=g.toDataURL()}return e}}(),Ea:f.Tb.prototype.Ea,m:function(){var a= +this.e.runtimeStyle;this.parent.gb(this.ua);a.borderColor=a.borderStyle=a.borderWidth=""}});f.kb=function(){function a(l,q){l.className+=" "+q}function b(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;)a(l,q[s])},0)}function c(l){var q=v.slice.call(arguments,1),s=q.length;setTimeout(function(){if(l)for(;s--;){var o=q[s];o=t[o]||(t[o]=new RegExp("\\b"+o+"\\b","g"));l.className=l.className.replace(o,"")}},0)}function d(l){function q(){if(!U){var w,A,L=f.ja,T=l.currentStyle, +N=T.getAttribute(g)==="true",da=T.getAttribute(i)!=="false",ea=T.getAttribute(h)!=="false";S=T.getAttribute(j);S=L>7?S!=="false":S==="true";if(!R){R=1;l.runtimeStyle.zoom=1;T=l;for(var fa=1;T=T.previousSibling;)if(T.nodeType===1){fa=0;break}fa&&a(l,p)}J.cb();if(N&&(A=J.o())&&(w=doc.documentElement||doc.body)&&(A.y>w.clientHeight||A.x>w.clientWidth||A.y+A.f<0||A.x+A.h<0)){if(!Y){Y=1;f.mb.ba(q)}}else{U=1;Y=R=0;f.mb.Ha(q);if(L===9){G={C:new f.Sb(l),q:new f.Ub(l),w:new f.Vb(l)};Q=[G.C,G.q];K=new f.Oc(l, +J,G);w=[new f.Mc(l,J,G,K),new f.Nc(l,J,G,K)]}else{G={C:new f.Sb(l),w:new f.Vb(l),q:new f.Ub(l),G:new f.jb(l),ga:new f.Ic(l),Pb:new f.Uc(l)};Q=[G.C,G.w,G.q,G.G,G.ga,G.Pb];K=new f.Rc(l,J,G);w=[new f.Hc(l,J,G,K),new f.Fc(l,J,G,K),new f.Gc(l,J,G,K),new f.Tb(l,J,G,K)];l.tagName==="IMG"&&w.push(new f.Pc(l,J,G,K));K.ed=w}I=[K].concat(w);if(w=l.currentStyle.getAttribute(f.F+"watch-ancestors")){w=parseInt(w,10);A=0;for(N=l.parentNode;N&&(w==="NaN"||A++<w);){H(N,"onpropertychange",C);H(N,"onmouseenter",x); +H(N,"onmouseleave",y);H(N,"onmousedown",z);if(N.tagName in f.fc){H(N,"onfocus",E);H(N,"onblur",D)}N=N.parentNode}}if(S){f.Oa.ba(o);f.Oa.Rd()}o(1)}if(!V){V=1;L<9&&H(l,"onmove",s);H(l,"onresize",s);H(l,"onpropertychange",u);ea&&H(l,"onmouseenter",x);if(ea||da)H(l,"onmouseleave",y);da&&H(l,"onmousedown",z);if(l.tagName in f.fc){H(l,"onfocus",E);H(l,"onblur",D)}f.Qa.ba(s);f.L.ba(M)}J.hb()}}function s(){J&&J.Ad()&&o()}function o(w){if(!X)if(U){var A,L=I.length;F();for(A=0;A<L;A++)I[A].Ea();if(w||J.Od())for(A= +0;A<L;A++)I[A].ib();if(w||J.Td())for(A=0;A<L;A++)I[A].Mb();K.ab();O()}else R||q()}function u(){var w,A=I.length,L;w=event;if(!X&&!(w&&w.propertyName in r))if(U){F();for(w=0;w<A;w++)I[w].Ea();for(w=0;w<A;w++){L=I[w];L.Cb||L.ib();L.Q()&&L.Lb()}K.ab();O()}else R||q()}function x(){b(l,k)}function y(){c(l,k,n)}function z(){b(l,n);f.lb.ba(B)}function B(){c(l,n);f.lb.Ha(B)}function E(){b(l,m)}function D(){c(l,m)}function C(){var w=event.propertyName;if(w==="className"||w==="id")u()}function F(){J.cb();for(var w= +Q.length;w--;)Q[w].cb()}function O(){for(var w=Q.length;w--;)Q[w].hb();J.hb()}function H(w,A,L){w.attachEvent(A,L);W.push([w,A,L])}function M(){if(V){for(var w=W.length,A;w--;){A=W[w];A[0].detachEvent(A[1],A[2])}f.L.Ha(M);V=0;W=[]}}function P(){if(!X){var w,A;M();X=1;if(I){w=0;for(A=I.length;w<A;w++){I[w].ec=1;I[w].m()}}S&&f.Oa.Ha(o);f.Qa.Ha(o);I=J=G=Q=l=null}}var I,K,J=new ha(l),G,Q,R,U,V,W=[],Y,X,S;this.Ed=q;this.update=o;this.m=P;this.qd=l}var e={},g=f.F+"lazy-init",j=f.F+"poll",i=f.F+"track-active", +h=f.F+"track-hover",k=f.La+"hover",n=f.La+"active",m=f.La+"focus",p=f.La+"first-child",r={background:1,bgColor:1,display:1},t={},v=[];d.yd=function(l){var q=f.p.Ba(l);return e[q]||(e[q]=new d(l))};d.m=function(l){l=f.p.Ba(l);var q=e[l];if(q){q.m();delete e[l]}};d.md=function(){var l=[],q;if(e){for(var s in e)if(e.hasOwnProperty(s)){q=e[s];l.push(q.qd);q.m()}e={}}return l};return d}();f.supportsVML=f.zc;f.attach=function(a){f.ja<10&&f.zc&&f.kb.yd(a).Ed()};f.detach=function(a){f.kb.m(a)}}; +})();
\ No newline at end of file diff --git a/themes/mantra/resources/js/PIE/PIE.php b/themes/mantra/resources/js/PIE/PIE.php new file mode 100644 index 00000000..58a6f0a6 --- /dev/null +++ b/themes/mantra/resources/js/PIE/PIE.php @@ -0,0 +1,19 @@ +<?php +/* +This file is a wrapper, for use in PHP environments, which serves PIE.htc using the +correct content-type, so that IE will recognize it as a behavior. Simply specify the +behavior property to fetch this .php file instead of the .htc directly: + +.myElement { + [ ...css3 properties... ] + behavior: url(PIE.php); +} + +This is only necessary when the web server is not configured to serve .htc files with +the text/x-component content-type, and cannot easily be configured to do so (as is the +case with some shared hosting providers). +*/ + +header( 'Content-type: text/x-component' ); +include( 'PIE.htc' ); +?>
\ No newline at end of file diff --git a/themes/mantra/resources/js/PIE/PIE_uncompressed.htc b/themes/mantra/resources/js/PIE/PIE_uncompressed.htc new file mode 100644 index 00000000..bf1a010b --- /dev/null +++ b/themes/mantra/resources/js/PIE/PIE_uncompressed.htc @@ -0,0 +1,4505 @@ +<!-- +PIE: CSS3 rendering for IE +Version 1.0.0 +http://css3pie.com +Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. +--> +<PUBLIC:COMPONENT lightWeight="true"> +<!-- saved from url=(0014)about:internet --> +<PUBLIC:ATTACH EVENT="oncontentready" FOR="element" ONEVENT="init()" /> +<PUBLIC:ATTACH EVENT="ondocumentready" FOR="element" ONEVENT="init()" /> +<PUBLIC:ATTACH EVENT="ondetach" FOR="element" ONEVENT="cleanup()" /> + +<script type="text/javascript"> +var doc = element.document;var PIE = window['PIE']; + +if( !PIE ) { + PIE = window['PIE'] = { + CSS_PREFIX: '-pie-', + STYLE_PREFIX: 'Pie', + CLASS_PREFIX: 'pie_', + tableCellTags: { + 'TD': 1, + 'TH': 1 + }, + + /** + * Lookup table of elements which cannot take custom children. + */ + childlessElements: { + 'TABLE':1, + 'THEAD':1, + 'TBODY':1, + 'TFOOT':1, + 'TR':1, + 'INPUT':1, + 'TEXTAREA':1, + 'SELECT':1, + 'OPTION':1, + 'IMG':1, + 'HR':1 + }, + + /** + * Elements that can receive user focus + */ + focusableElements: { + 'A':1, + 'INPUT':1, + 'TEXTAREA':1, + 'SELECT':1, + 'BUTTON':1 + }, + + /** + * Values of the type attribute for input elements displayed as buttons + */ + inputButtonTypes: { + 'submit':1, + 'button':1, + 'reset':1 + }, + + emptyFn: function() {} + }; + + // Force the background cache to be used. No reason it shouldn't be. + try { + doc.execCommand( 'BackgroundImageCache', false, true ); + } catch(e) {} + + (function() { + /* + * IE version detection approach by James Padolsey, with modifications -- from + * http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/ + */ + var ieVersion = 4, + div = doc.createElement('div'), + all = div.getElementsByTagName('i'), + shape; + while ( + div.innerHTML = '<!--[if gt IE ' + (++ieVersion) + ']><i></i><![endif]-->', + all[0] + ) {} + PIE.ieVersion = ieVersion; + + // Detect IE6 + if( ieVersion === 6 ) { + // IE6 can't access properties with leading dash, but can without it. + PIE.CSS_PREFIX = PIE.CSS_PREFIX.replace( /^-/, '' ); + } + + PIE.ieDocMode = doc.documentMode || PIE.ieVersion; + + // Detect VML support (a small number of IE installs don't have a working VML engine) + div.innerHTML = '<v:shape adj="1"/>'; + shape = div.firstChild; + shape.style['behavior'] = 'url(#default#VML)'; + PIE.supportsVML = (typeof shape['adj'] === "object"); + }()); +/** + * Utility functions + */ +(function() { + var vmlCreatorDoc, + idNum = 0, + imageSizes = {}; + + + PIE.Util = { + + /** + * To create a VML element, it must be created by a Document which has the VML + * namespace set. Unfortunately, if you try to add the namespace programatically + * into the main document, you will get an "Unspecified error" when trying to + * access document.namespaces before the document is finished loading. To get + * around this, we create a DocumentFragment, which in IE land is apparently a + * full-fledged Document. It allows adding namespaces immediately, so we add the + * namespace there and then have it create the VML element. + * @param {string} tag The tag name for the VML element + * @return {Element} The new VML element + */ + createVmlElement: function( tag ) { + var vmlPrefix = 'css3vml'; + if( !vmlCreatorDoc ) { + vmlCreatorDoc = doc.createDocumentFragment(); + vmlCreatorDoc.namespaces.add( vmlPrefix, 'urn:schemas-microsoft-com:vml' ); + } + return vmlCreatorDoc.createElement( vmlPrefix + ':' + tag ); + }, + + + /** + * Generate and return a unique ID for a given object. The generated ID is stored + * as a property of the object for future reuse. + * @param {Object} obj + */ + getUID: function( obj ) { + return obj && obj[ '_pieId' ] || ( obj[ '_pieId' ] = '_' + ++idNum ); + }, + + + /** + * Simple utility for merging objects + * @param {Object} obj1 The main object into which all others will be merged + * @param {...Object} var_args Other objects which will be merged into the first, in order + */ + merge: function( obj1 ) { + var i, len, p, objN, args = arguments; + for( i = 1, len = args.length; i < len; i++ ) { + objN = args[i]; + for( p in objN ) { + if( objN.hasOwnProperty( p ) ) { + obj1[ p ] = objN[ p ]; + } + } + } + return obj1; + }, + + + /** + * Execute a callback function, passing it the dimensions of a given image once + * they are known. + * @param {string} src The source URL of the image + * @param {function({w:number, h:number})} func The callback function to be called once the image dimensions are known + * @param {Object} ctx A context object which will be used as the 'this' value within the executed callback function + */ + withImageSize: function( src, func, ctx ) { + var size = imageSizes[ src ], img, queue; + if( size ) { + // If we have a queue, add to it + if( Object.prototype.toString.call( size ) === '[object Array]' ) { + size.push( [ func, ctx ] ); + } + // Already have the size cached, call func right away + else { + func.call( ctx, size ); + } + } else { + queue = imageSizes[ src ] = [ [ func, ctx ] ]; //create queue + img = new Image(); + img.onload = function() { + size = imageSizes[ src ] = { w: img.width, h: img.height }; + for( var i = 0, len = queue.length; i < len; i++ ) { + queue[ i ][ 0 ].call( queue[ i ][ 1 ], size ); + } + img.onload = null; + }; + img.src = src; + } + } + }; +})();/** + * Utility functions for handling gradients + */ +PIE.GradientUtil = { + + getGradientMetrics: function( el, width, height, gradientInfo ) { + var angle = gradientInfo.angle, + startPos = gradientInfo.gradientStart, + startX, startY, + endX, endY, + startCornerX, startCornerY, + endCornerX, endCornerY, + deltaX, deltaY, + p, UNDEF; + + // Find the "start" and "end" corners; these are the corners furthest along the gradient line. + // This is used below to find the start/end positions of the CSS3 gradient-line, and also in finding + // the total length of the VML rendered gradient-line corner to corner. + function findCorners() { + startCornerX = ( angle >= 90 && angle < 270 ) ? width : 0; + startCornerY = angle < 180 ? height : 0; + endCornerX = width - startCornerX; + endCornerY = height - startCornerY; + } + + // Normalize the angle to a value between [0, 360) + function normalizeAngle() { + while( angle < 0 ) { + angle += 360; + } + angle = angle % 360; + } + + // Find the start and end points of the gradient + if( startPos ) { + startPos = startPos.coords( el, width, height ); + startX = startPos.x; + startY = startPos.y; + } + if( angle ) { + angle = angle.degrees(); + + normalizeAngle(); + findCorners(); + + // If no start position was specified, then choose a corner as the starting point. + if( !startPos ) { + startX = startCornerX; + startY = startCornerY; + } + + // Find the end position by extending a perpendicular line from the gradient-line which + // intersects the corner opposite from the starting corner. + p = PIE.GradientUtil.perpendicularIntersect( startX, startY, angle, endCornerX, endCornerY ); + endX = p[0]; + endY = p[1]; + } + else if( startPos ) { + // Start position but no angle specified: find the end point by rotating 180deg around the center + endX = width - startX; + endY = height - startY; + } + else { + // Neither position nor angle specified; create vertical gradient from top to bottom + startX = startY = endX = 0; + endY = height; + } + deltaX = endX - startX; + deltaY = endY - startY; + + if( angle === UNDEF ) { + // Get the angle based on the change in x/y from start to end point. Checks first for horizontal + // or vertical angles so they get exact whole numbers rather than what atan2 gives. + angle = ( !deltaX ? ( deltaY < 0 ? 90 : 270 ) : + ( !deltaY ? ( deltaX < 0 ? 180 : 0 ) : + -Math.atan2( deltaY, deltaX ) / Math.PI * 180 + ) + ); + normalizeAngle(); + findCorners(); + } + + return { + angle: angle, + startX: startX, + startY: startY, + endX: endX, + endY: endY, + startCornerX: startCornerX, + startCornerY: startCornerY, + endCornerX: endCornerX, + endCornerY: endCornerY, + deltaX: deltaX, + deltaY: deltaY, + lineLength: PIE.GradientUtil.distance( startX, startY, endX, endY ) + } + }, + + /** + * Find the point along a given line (defined by a starting point and an angle), at which + * that line is intersected by a perpendicular line extending through another point. + * @param x1 - x coord of the starting point + * @param y1 - y coord of the starting point + * @param angle - angle of the line extending from the starting point (in degrees) + * @param x2 - x coord of point along the perpendicular line + * @param y2 - y coord of point along the perpendicular line + * @return [ x, y ] + */ + perpendicularIntersect: function( x1, y1, angle, x2, y2 ) { + // Handle straight vertical and horizontal angles, for performance and to avoid + // divide-by-zero errors. + if( angle === 0 || angle === 180 ) { + return [ x2, y1 ]; + } + else if( angle === 90 || angle === 270 ) { + return [ x1, y2 ]; + } + else { + // General approach: determine the Ax+By=C formula for each line (the slope of the second + // line is the negative inverse of the first) and then solve for where both formulas have + // the same x/y values. + var a1 = Math.tan( -angle * Math.PI / 180 ), + c1 = a1 * x1 - y1, + a2 = -1 / a1, + c2 = a2 * x2 - y2, + d = a2 - a1, + endX = ( c2 - c1 ) / d, + endY = ( a1 * c2 - a2 * c1 ) / d; + return [ endX, endY ]; + } + }, + + /** + * Find the distance between two points + * @param {Number} p1x + * @param {Number} p1y + * @param {Number} p2x + * @param {Number} p2y + * @return {Number} the distance + */ + distance: function( p1x, p1y, p2x, p2y ) { + var dx = p2x - p1x, + dy = p2y - p1y; + return Math.abs( + dx === 0 ? dy : + dy === 0 ? dx : + Math.sqrt( dx * dx + dy * dy ) + ); + } + +};/** + * + */ +PIE.Observable = function() { + /** + * List of registered observer functions + */ + this.observers = []; + + /** + * Hash of function ids to their position in the observers list, for fast lookup + */ + this.indexes = {}; +}; +PIE.Observable.prototype = { + + observe: function( fn ) { + var id = PIE.Util.getUID( fn ), + indexes = this.indexes, + observers = this.observers; + if( !( id in indexes ) ) { + indexes[ id ] = observers.length; + observers.push( fn ); + } + }, + + unobserve: function( fn ) { + var id = PIE.Util.getUID( fn ), + indexes = this.indexes; + if( id && id in indexes ) { + delete this.observers[ indexes[ id ] ]; + delete indexes[ id ]; + } + }, + + fire: function() { + var o = this.observers, + i = o.length; + while( i-- ) { + o[ i ] && o[ i ](); + } + } + +};/* + * Simple heartbeat timer - this is a brute-force workaround for syncing issues caused by IE not + * always firing the onmove and onresize events when elements are moved or resized. We check a few + * times every second to make sure the elements have the correct position and size. See Element.js + * which adds heartbeat listeners based on the custom -pie-poll flag, which defaults to true in IE8-9 + * and false elsewhere. + */ + +PIE.Heartbeat = new PIE.Observable(); +PIE.Heartbeat.run = function() { + var me = this, + interval; + if( !me.running ) { + interval = doc.documentElement.currentStyle.getAttribute( PIE.CSS_PREFIX + 'poll-interval' ) || 250; + (function beat() { + me.fire(); + setTimeout(beat, interval); + })(); + me.running = 1; + } +}; +/** + * Create an observable listener for the onunload event + */ +(function() { + PIE.OnUnload = new PIE.Observable(); + + function handleUnload() { + PIE.OnUnload.fire(); + window.detachEvent( 'onunload', handleUnload ); + window[ 'PIE' ] = null; + } + + window.attachEvent( 'onunload', handleUnload ); + + /** + * Attach an event which automatically gets detached onunload + */ + PIE.OnUnload.attachManagedEvent = function( target, name, handler ) { + target.attachEvent( name, handler ); + this.observe( function() { + target.detachEvent( name, handler ); + } ); + }; +})()/** + * Create a single observable listener for window resize events. + */ +PIE.OnResize = new PIE.Observable(); + +PIE.OnUnload.attachManagedEvent( window, 'onresize', function() { PIE.OnResize.fire(); } ); +/** + * Create a single observable listener for scroll events. Used for lazy loading based + * on the viewport, and for fixed position backgrounds. + */ +(function() { + PIE.OnScroll = new PIE.Observable(); + + function scrolled() { + PIE.OnScroll.fire(); + } + + PIE.OnUnload.attachManagedEvent( window, 'onscroll', scrolled ); + + PIE.OnResize.observe( scrolled ); +})(); +/** + * Listen for printing events, destroy all active PIE instances when printing, and + * restore them afterward. + */ +(function() { + + var elements; + + function beforePrint() { + elements = PIE.Element.destroyAll(); + } + + function afterPrint() { + if( elements ) { + for( var i = 0, len = elements.length; i < len; i++ ) { + PIE[ 'attach' ]( elements[i] ); + } + elements = 0; + } + } + + if( PIE.ieDocMode < 9 ) { + PIE.OnUnload.attachManagedEvent( window, 'onbeforeprint', beforePrint ); + PIE.OnUnload.attachManagedEvent( window, 'onafterprint', afterPrint ); + } + +})();/** + * Create a single observable listener for document mouseup events. + */ +PIE.OnMouseup = new PIE.Observable(); + +PIE.OnUnload.attachManagedEvent( doc, 'onmouseup', function() { PIE.OnMouseup.fire(); } ); +/** + * Wrapper for length and percentage style values. The value is immutable. A singleton instance per unique + * value is returned from PIE.getLength() - always use that instead of instantiating directly. + * @constructor + * @param {string} val The CSS string representing the length. It is assumed that this will already have + * been validated as a valid length or percentage syntax. + */ +PIE.Length = (function() { + var lengthCalcEl = doc.createElement( 'length-calc' ), + parent = doc.body || doc.documentElement, + s = lengthCalcEl.style, + conversions = {}, + units = [ 'mm', 'cm', 'in', 'pt', 'pc' ], + i = units.length, + instances = {}; + + s.position = 'absolute'; + s.top = s.left = '-9999px'; + + parent.appendChild( lengthCalcEl ); + while( i-- ) { + s.width = '100' + units[i]; + conversions[ units[i] ] = lengthCalcEl.offsetWidth / 100; + } + parent.removeChild( lengthCalcEl ); + + // All calcs from here on will use 1em + s.width = '1em'; + + + function Length( val ) { + this.val = val; + } + Length.prototype = { + /** + * Regular expression for matching the length unit + * @private + */ + unitRE: /(px|em|ex|mm|cm|in|pt|pc|%)$/, + + /** + * Get the numeric value of the length + * @return {number} The value + */ + getNumber: function() { + var num = this.num, + UNDEF; + if( num === UNDEF ) { + num = this.num = parseFloat( this.val ); + } + return num; + }, + + /** + * Get the unit of the length + * @return {string} The unit + */ + getUnit: function() { + var unit = this.unit, + m; + if( !unit ) { + m = this.val.match( this.unitRE ); + unit = this.unit = ( m && m[0] ) || 'px'; + } + return unit; + }, + + /** + * Determine whether this is a percentage length value + * @return {boolean} + */ + isPercentage: function() { + return this.getUnit() === '%'; + }, + + /** + * Resolve this length into a number of pixels. + * @param {Element} el - the context element, used to resolve font-relative values + * @param {(function():number|number)=} pct100 - the number of pixels that equal a 100% percentage. This can be either a number or a + * function which will be called to return the number. + */ + pixels: function( el, pct100 ) { + var num = this.getNumber(), + unit = this.getUnit(); + switch( unit ) { + case "px": + return num; + case "%": + return num * ( typeof pct100 === 'function' ? pct100() : pct100 ) / 100; + case "em": + return num * this.getEmPixels( el ); + case "ex": + return num * this.getEmPixels( el ) / 2; + default: + return num * conversions[ unit ]; + } + }, + + /** + * The em and ex units are relative to the font-size of the current element, + * however if the font-size is set using non-pixel units then we get that value + * rather than a pixel conversion. To get around this, we keep a floating element + * with width:1em which we insert into the target element and then read its offsetWidth. + * For elements that won't accept a child we insert into the parent node and perform + * additional calculation. If the font-size *is* specified in pixels, then we use that + * directly to avoid the expensive DOM manipulation. + * @param {Element} el + * @return {number} + */ + getEmPixels: function( el ) { + var fs = el.currentStyle.fontSize, + px, parent, me; + + if( fs.indexOf( 'px' ) > 0 ) { + return parseFloat( fs ); + } + else if( el.tagName in PIE.childlessElements ) { + me = this; + parent = el.parentNode; + return PIE.getLength( fs ).pixels( parent, function() { + return me.getEmPixels( parent ); + } ); + } + else { + el.appendChild( lengthCalcEl ); + px = lengthCalcEl.offsetWidth; + if( lengthCalcEl.parentNode === el ) { //not sure how this could be false but it sometimes is + el.removeChild( lengthCalcEl ); + } + return px; + } + } + }; + + + /** + * Retrieve a PIE.Length instance for the given value. A shared singleton instance is returned for each unique value. + * @param {string} val The CSS string representing the length. It is assumed that this will already have + * been validated as a valid length or percentage syntax. + */ + PIE.getLength = function( val ) { + return instances[ val ] || ( instances[ val ] = new Length( val ) ); + }; + + return Length; +})(); +/** + * Wrapper for a CSS3 bg-position value. Takes up to 2 position keywords and 2 lengths/percentages. + * @constructor + * @param {Array.<PIE.Tokenizer.Token>} tokens The tokens making up the background position value. + */ +PIE.BgPosition = (function() { + + var length_fifty = PIE.getLength( '50%' ), + vert_idents = { 'top': 1, 'center': 1, 'bottom': 1 }, + horiz_idents = { 'left': 1, 'center': 1, 'right': 1 }; + + + function BgPosition( tokens ) { + this.tokens = tokens; + } + BgPosition.prototype = { + /** + * Normalize the values into the form: + * [ xOffsetSide, xOffsetLength, yOffsetSide, yOffsetLength ] + * where: xOffsetSide is either 'left' or 'right', + * yOffsetSide is either 'top' or 'bottom', + * and x/yOffsetLength are both PIE.Length objects. + * @return {Array} + */ + getValues: function() { + if( !this._values ) { + var tokens = this.tokens, + len = tokens.length, + Tokenizer = PIE.Tokenizer, + identType = Tokenizer.Type, + length_zero = PIE.getLength( '0' ), + type_ident = identType.IDENT, + type_length = identType.LENGTH, + type_percent = identType.PERCENT, + type, value, + vals = [ 'left', length_zero, 'top', length_zero ]; + + // If only one value, the second is assumed to be 'center' + if( len === 1 ) { + tokens.push( new Tokenizer.Token( type_ident, 'center' ) ); + len++; + } + + // Two values - CSS2 + if( len === 2 ) { + // If both idents, they can appear in either order, so switch them if needed + if( type_ident & ( tokens[0].tokenType | tokens[1].tokenType ) && + tokens[0].tokenValue in vert_idents && tokens[1].tokenValue in horiz_idents ) { + tokens.push( tokens.shift() ); + } + if( tokens[0].tokenType & type_ident ) { + if( tokens[0].tokenValue === 'center' ) { + vals[1] = length_fifty; + } else { + vals[0] = tokens[0].tokenValue; + } + } + else if( tokens[0].isLengthOrPercent() ) { + vals[1] = PIE.getLength( tokens[0].tokenValue ); + } + if( tokens[1].tokenType & type_ident ) { + if( tokens[1].tokenValue === 'center' ) { + vals[3] = length_fifty; + } else { + vals[2] = tokens[1].tokenValue; + } + } + else if( tokens[1].isLengthOrPercent() ) { + vals[3] = PIE.getLength( tokens[1].tokenValue ); + } + } + + // Three or four values - CSS3 + else { + // TODO + } + + this._values = vals; + } + return this._values; + }, + + /** + * Find the coordinates of the background image from the upper-left corner of the background area. + * Note that these coordinate values are not rounded. + * @param {Element} el + * @param {number} width - the width for percentages (background area width minus image width) + * @param {number} height - the height for percentages (background area height minus image height) + * @return {Object} { x: Number, y: Number } + */ + coords: function( el, width, height ) { + var vals = this.getValues(), + pxX = vals[1].pixels( el, width ), + pxY = vals[3].pixels( el, height ); + + return { + x: vals[0] === 'right' ? width - pxX : pxX, + y: vals[2] === 'bottom' ? height - pxY : pxY + }; + } + }; + + return BgPosition; +})(); +/** + * Wrapper for a CSS3 background-size value. + * @constructor + * @param {String|PIE.Length} w The width parameter + * @param {String|PIE.Length} h The height parameter, if any + */ +PIE.BgSize = (function() { + + var CONTAIN = 'contain', + COVER = 'cover', + AUTO = 'auto'; + + + function BgSize( w, h ) { + this.w = w; + this.h = h; + } + BgSize.prototype = { + + pixels: function( el, areaW, areaH, imgW, imgH ) { + var me = this, + w = me.w, + h = me.h, + areaRatio = areaW / areaH, + imgRatio = imgW / imgH; + + if ( w === CONTAIN ) { + w = imgRatio > areaRatio ? areaW : areaH * imgRatio; + h = imgRatio > areaRatio ? areaW / imgRatio : areaH; + } + else if ( w === COVER ) { + w = imgRatio < areaRatio ? areaW : areaH * imgRatio; + h = imgRatio < areaRatio ? areaW / imgRatio : areaH; + } + else if ( w === AUTO ) { + h = ( h === AUTO ? imgH : h.pixels( el, areaH ) ); + w = h * imgRatio; + } + else { + w = w.pixels( el, areaW ); + h = ( h === AUTO ? w / imgRatio : h.pixels( el, areaH ) ); + } + + return { w: w, h: h }; + } + + }; + + BgSize.DEFAULT = new BgSize( AUTO, AUTO ); + + return BgSize; +})(); +/** + * Wrapper for angle values; handles conversion to degrees from all allowed angle units + * @constructor + * @param {string} val The raw CSS value for the angle. It is assumed it has been pre-validated. + */ +PIE.Angle = (function() { + function Angle( val ) { + this.val = val; + } + Angle.prototype = { + unitRE: /[a-z]+$/i, + + /** + * @return {string} The unit of the angle value + */ + getUnit: function() { + return this._unit || ( this._unit = this.val.match( this.unitRE )[0].toLowerCase() ); + }, + + /** + * Get the numeric value of the angle in degrees. + * @return {number} The degrees value + */ + degrees: function() { + var deg = this._deg, u, n; + if( deg === undefined ) { + u = this.getUnit(); + n = parseFloat( this.val, 10 ); + deg = this._deg = ( u === 'deg' ? n : u === 'rad' ? n / Math.PI * 180 : u === 'grad' ? n / 400 * 360 : u === 'turn' ? n * 360 : 0 ); + } + return deg; + } + }; + + return Angle; +})();/** + * Abstraction for colors values. Allows detection of rgba values. A singleton instance per unique + * value is returned from PIE.getColor() - always use that instead of instantiating directly. + * @constructor + * @param {string} val The raw CSS string value for the color + */ +PIE.Color = (function() { + var instances = {}; + + function Color( val ) { + this.val = val; + } + + /** + * Regular expression for matching rgba colors and extracting their components + * @type {RegExp} + */ + Color.rgbaRE = /\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/; + + Color.names = { + "aliceblue":"F0F8FF", "antiquewhite":"FAEBD7", "aqua":"0FF", + "aquamarine":"7FFFD4", "azure":"F0FFFF", "beige":"F5F5DC", + "bisque":"FFE4C4", "black":"000", "blanchedalmond":"FFEBCD", + "blue":"00F", "blueviolet":"8A2BE2", "brown":"A52A2A", + "burlywood":"DEB887", "cadetblue":"5F9EA0", "chartreuse":"7FFF00", + "chocolate":"D2691E", "coral":"FF7F50", "cornflowerblue":"6495ED", + "cornsilk":"FFF8DC", "crimson":"DC143C", "cyan":"0FF", + "darkblue":"00008B", "darkcyan":"008B8B", "darkgoldenrod":"B8860B", + "darkgray":"A9A9A9", "darkgreen":"006400", "darkkhaki":"BDB76B", + "darkmagenta":"8B008B", "darkolivegreen":"556B2F", "darkorange":"FF8C00", + "darkorchid":"9932CC", "darkred":"8B0000", "darksalmon":"E9967A", + "darkseagreen":"8FBC8F", "darkslateblue":"483D8B", "darkslategray":"2F4F4F", + "darkturquoise":"00CED1", "darkviolet":"9400D3", "deeppink":"FF1493", + "deepskyblue":"00BFFF", "dimgray":"696969", "dodgerblue":"1E90FF", + "firebrick":"B22222", "floralwhite":"FFFAF0", "forestgreen":"228B22", + "fuchsia":"F0F", "gainsboro":"DCDCDC", "ghostwhite":"F8F8FF", + "gold":"FFD700", "goldenrod":"DAA520", "gray":"808080", + "green":"008000", "greenyellow":"ADFF2F", "honeydew":"F0FFF0", + "hotpink":"FF69B4", "indianred":"CD5C5C", "indigo":"4B0082", + "ivory":"FFFFF0", "khaki":"F0E68C", "lavender":"E6E6FA", + "lavenderblush":"FFF0F5", "lawngreen":"7CFC00", "lemonchiffon":"FFFACD", + "lightblue":"ADD8E6", "lightcoral":"F08080", "lightcyan":"E0FFFF", + "lightgoldenrodyellow":"FAFAD2", "lightgreen":"90EE90", "lightgrey":"D3D3D3", + "lightpink":"FFB6C1", "lightsalmon":"FFA07A", "lightseagreen":"20B2AA", + "lightskyblue":"87CEFA", "lightslategray":"789", "lightsteelblue":"B0C4DE", + "lightyellow":"FFFFE0", "lime":"0F0", "limegreen":"32CD32", + "linen":"FAF0E6", "magenta":"F0F", "maroon":"800000", + "mediumauqamarine":"66CDAA", "mediumblue":"0000CD", "mediumorchid":"BA55D3", + "mediumpurple":"9370D8", "mediumseagreen":"3CB371", "mediumslateblue":"7B68EE", + "mediumspringgreen":"00FA9A", "mediumturquoise":"48D1CC", "mediumvioletred":"C71585", + "midnightblue":"191970", "mintcream":"F5FFFA", "mistyrose":"FFE4E1", + "moccasin":"FFE4B5", "navajowhite":"FFDEAD", "navy":"000080", + "oldlace":"FDF5E6", "olive":"808000", "olivedrab":"688E23", + "orange":"FFA500", "orangered":"FF4500", "orchid":"DA70D6", + "palegoldenrod":"EEE8AA", "palegreen":"98FB98", "paleturquoise":"AFEEEE", + "palevioletred":"D87093", "papayawhip":"FFEFD5", "peachpuff":"FFDAB9", + "peru":"CD853F", "pink":"FFC0CB", "plum":"DDA0DD", + "powderblue":"B0E0E6", "purple":"800080", "red":"F00", + "rosybrown":"BC8F8F", "royalblue":"4169E1", "saddlebrown":"8B4513", + "salmon":"FA8072", "sandybrown":"F4A460", "seagreen":"2E8B57", + "seashell":"FFF5EE", "sienna":"A0522D", "silver":"C0C0C0", + "skyblue":"87CEEB", "slateblue":"6A5ACD", "slategray":"708090", + "snow":"FFFAFA", "springgreen":"00FF7F", "steelblue":"4682B4", + "tan":"D2B48C", "teal":"008080", "thistle":"D8BFD8", + "tomato":"FF6347", "turquoise":"40E0D0", "violet":"EE82EE", + "wheat":"F5DEB3", "white":"FFF", "whitesmoke":"F5F5F5", + "yellow":"FF0", "yellowgreen":"9ACD32" + }; + + Color.prototype = { + /** + * @private + */ + parse: function() { + if( !this._color ) { + var me = this, + v = me.val, + vLower, + m = v.match( Color.rgbaRE ); + if( m ) { + me._color = 'rgb(' + m[1] + ',' + m[2] + ',' + m[3] + ')'; + me._alpha = parseFloat( m[4] ); + } + else { + if( ( vLower = v.toLowerCase() ) in Color.names ) { + v = '#' + Color.names[vLower]; + } + me._color = v; + me._alpha = ( v === 'transparent' ? 0 : 1 ); + } + } + }, + + /** + * Retrieve the value of the color in a format usable by IE natively. This will be the same as + * the raw input value, except for rgba values which will be converted to an rgb value. + * @param {Element} el The context element, used to get 'currentColor' keyword value. + * @return {string} Color value + */ + colorValue: function( el ) { + this.parse(); + return this._color === 'currentColor' ? el.currentStyle.color : this._color; + }, + + /** + * Retrieve the alpha value of the color. Will be 1 for all values except for rgba values + * with an alpha component. + * @return {number} The alpha value, from 0 to 1. + */ + alpha: function() { + this.parse(); + return this._alpha; + } + }; + + + /** + * Retrieve a PIE.Color instance for the given value. A shared singleton instance is returned for each unique value. + * @param {string} val The CSS string representing the color. It is assumed that this will already have + * been validated as a valid color syntax. + */ + PIE.getColor = function(val) { + return instances[ val ] || ( instances[ val ] = new Color( val ) ); + }; + + return Color; +})();/** + * A tokenizer for CSS value strings. + * @constructor + * @param {string} css The CSS value string + */ +PIE.Tokenizer = (function() { + function Tokenizer( css ) { + this.css = css; + this.ch = 0; + this.tokens = []; + this.tokenIndex = 0; + } + + /** + * Enumeration of token type constants. + * @enum {number} + */ + var Type = Tokenizer.Type = { + ANGLE: 1, + CHARACTER: 2, + COLOR: 4, + DIMEN: 8, + FUNCTION: 16, + IDENT: 32, + LENGTH: 64, + NUMBER: 128, + OPERATOR: 256, + PERCENT: 512, + STRING: 1024, + URL: 2048 + }; + + /** + * A single token + * @constructor + * @param {number} type The type of the token - see PIE.Tokenizer.Type + * @param {string} value The value of the token + */ + Tokenizer.Token = function( type, value ) { + this.tokenType = type; + this.tokenValue = value; + }; + Tokenizer.Token.prototype = { + isLength: function() { + return this.tokenType & Type.LENGTH || ( this.tokenType & Type.NUMBER && this.tokenValue === '0' ); + }, + isLengthOrPercent: function() { + return this.isLength() || this.tokenType & Type.PERCENT; + } + }; + + Tokenizer.prototype = { + whitespace: /\s/, + number: /^[\+\-]?(\d*\.)?\d+/, + url: /^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i, + ident: /^\-?[_a-z][\w-]*/i, + string: /^("([^"]*)"|'([^']*)')/, + operator: /^[\/,]/, + hash: /^#[\w]+/, + hashColor: /^#([\da-f]{6}|[\da-f]{3})/i, + + unitTypes: { + 'px': Type.LENGTH, 'em': Type.LENGTH, 'ex': Type.LENGTH, + 'mm': Type.LENGTH, 'cm': Type.LENGTH, 'in': Type.LENGTH, + 'pt': Type.LENGTH, 'pc': Type.LENGTH, + 'deg': Type.ANGLE, 'rad': Type.ANGLE, 'grad': Type.ANGLE + }, + + colorFunctions: { + 'rgb': 1, 'rgba': 1, 'hsl': 1, 'hsla': 1 + }, + + + /** + * Advance to and return the next token in the CSS string. If the end of the CSS string has + * been reached, null will be returned. + * @param {boolean} forget - if true, the token will not be stored for the purposes of backtracking with prev(). + * @return {PIE.Tokenizer.Token} + */ + next: function( forget ) { + var css, ch, firstChar, match, val, + me = this; + + function newToken( type, value ) { + var tok = new Tokenizer.Token( type, value ); + if( !forget ) { + me.tokens.push( tok ); + me.tokenIndex++; + } + return tok; + } + function failure() { + me.tokenIndex++; + return null; + } + + // In case we previously backed up, return the stored token in the next slot + if( this.tokenIndex < this.tokens.length ) { + return this.tokens[ this.tokenIndex++ ]; + } + + // Move past leading whitespace characters + while( this.whitespace.test( this.css.charAt( this.ch ) ) ) { + this.ch++; + } + if( this.ch >= this.css.length ) { + return failure(); + } + + ch = this.ch; + css = this.css.substring( this.ch ); + firstChar = css.charAt( 0 ); + switch( firstChar ) { + case '#': + if( match = css.match( this.hashColor ) ) { + this.ch += match[0].length; + return newToken( Type.COLOR, match[0] ); + } + break; + + case '"': + case "'": + if( match = css.match( this.string ) ) { + this.ch += match[0].length; + return newToken( Type.STRING, match[2] || match[3] || '' ); + } + break; + + case "/": + case ",": + this.ch++; + return newToken( Type.OPERATOR, firstChar ); + + case 'u': + if( match = css.match( this.url ) ) { + this.ch += match[0].length; + return newToken( Type.URL, match[2] || match[3] || match[4] || '' ); + } + } + + // Numbers and values starting with numbers + if( match = css.match( this.number ) ) { + val = match[0]; + this.ch += val.length; + + // Check if it is followed by a unit + if( css.charAt( val.length ) === '%' ) { + this.ch++; + return newToken( Type.PERCENT, val + '%' ); + } + if( match = css.substring( val.length ).match( this.ident ) ) { + val += match[0]; + this.ch += match[0].length; + return newToken( this.unitTypes[ match[0].toLowerCase() ] || Type.DIMEN, val ); + } + + // Plain ol' number + return newToken( Type.NUMBER, val ); + } + + // Identifiers + if( match = css.match( this.ident ) ) { + val = match[0]; + this.ch += val.length; + + // Named colors + if( val.toLowerCase() in PIE.Color.names || val === 'currentColor' || val === 'transparent' ) { + return newToken( Type.COLOR, val ); + } + + // Functions + if( css.charAt( val.length ) === '(' ) { + this.ch++; + + // Color values in function format: rgb, rgba, hsl, hsla + if( val.toLowerCase() in this.colorFunctions ) { + function isNum( tok ) { + return tok && tok.tokenType & Type.NUMBER; + } + function isNumOrPct( tok ) { + return tok && ( tok.tokenType & ( Type.NUMBER | Type.PERCENT ) ); + } + function isValue( tok, val ) { + return tok && tok.tokenValue === val; + } + function next() { + return me.next( 1 ); + } + + if( ( val.charAt(0) === 'r' ? isNumOrPct( next() ) : isNum( next() ) ) && + isValue( next(), ',' ) && + isNumOrPct( next() ) && + isValue( next(), ',' ) && + isNumOrPct( next() ) && + ( val === 'rgb' || val === 'hsa' || ( + isValue( next(), ',' ) && + isNum( next() ) + ) ) && + isValue( next(), ')' ) ) { + return newToken( Type.COLOR, this.css.substring( ch, this.ch ) ); + } + return failure(); + } + + return newToken( Type.FUNCTION, val ); + } + + // Other identifier + return newToken( Type.IDENT, val ); + } + + // Standalone character + this.ch++; + return newToken( Type.CHARACTER, firstChar ); + }, + + /** + * Determine whether there is another token + * @return {boolean} + */ + hasNext: function() { + var next = this.next(); + this.prev(); + return !!next; + }, + + /** + * Back up and return the previous token + * @return {PIE.Tokenizer.Token} + */ + prev: function() { + return this.tokens[ this.tokenIndex-- - 2 ]; + }, + + /** + * Retrieve all the tokens in the CSS string + * @return {Array.<PIE.Tokenizer.Token>} + */ + all: function() { + while( this.next() ) {} + return this.tokens; + }, + + /** + * Return a list of tokens from the current position until the given function returns + * true. The final token will not be included in the list. + * @param {function():boolean} func - test function + * @param {boolean} require - if true, then if the end of the CSS string is reached + * before the test function returns true, null will be returned instead of the + * tokens that have been found so far. + * @return {Array.<PIE.Tokenizer.Token>} + */ + until: function( func, require ) { + var list = [], t, hit; + while( t = this.next() ) { + if( func( t ) ) { + hit = true; + this.prev(); + break; + } + list.push( t ); + } + return require && !hit ? null : list; + } + }; + + return Tokenizer; +})();/** + * Handles calculating, caching, and detecting changes to size and position of the element. + * @constructor + * @param {Element} el the target element + */ +PIE.BoundsInfo = function( el ) { + this.targetElement = el; +}; +PIE.BoundsInfo.prototype = { + + _locked: 0, + + positionChanged: function() { + var last = this._lastBounds, + bounds; + return !last || ( ( bounds = this.getBounds() ) && ( last.x !== bounds.x || last.y !== bounds.y ) ); + }, + + sizeChanged: function() { + var last = this._lastBounds, + bounds; + return !last || ( ( bounds = this.getBounds() ) && ( last.w !== bounds.w || last.h !== bounds.h ) ); + }, + + getLiveBounds: function() { + var el = this.targetElement, + rect = el.getBoundingClientRect(), + isIE9 = PIE.ieDocMode === 9, + isIE7 = PIE.ieVersion === 7, + width = rect.right - rect.left; + return { + x: rect.left, + y: rect.top, + // In some cases scrolling the page will cause IE9 to report incorrect dimensions + // in the rect returned by getBoundingClientRect, so we must query offsetWidth/Height + // instead. Also IE7 is inconsistent in using logical vs. device pixels in measurements + // so we must calculate the ratio and use it in certain places as a position adjustment. + w: isIE9 || isIE7 ? el.offsetWidth : width, + h: isIE9 || isIE7 ? el.offsetHeight : rect.bottom - rect.top, + logicalZoomRatio: ( isIE7 && width ) ? el.offsetWidth / width : 1 + }; + }, + + getBounds: function() { + return this._locked ? + ( this._lockedBounds || ( this._lockedBounds = this.getLiveBounds() ) ) : + this.getLiveBounds(); + }, + + hasBeenQueried: function() { + return !!this._lastBounds; + }, + + lock: function() { + ++this._locked; + }, + + unlock: function() { + if( !--this._locked ) { + if( this._lockedBounds ) this._lastBounds = this._lockedBounds; + this._lockedBounds = null; + } + } + +}; +(function() { + +function cacheWhenLocked( fn ) { + var uid = PIE.Util.getUID( fn ); + return function() { + if( this._locked ) { + var cache = this._lockedValues || ( this._lockedValues = {} ); + return ( uid in cache ) ? cache[ uid ] : ( cache[ uid ] = fn.call( this ) ); + } else { + return fn.call( this ); + } + } +} + + +PIE.StyleInfoBase = { + + _locked: 0, + + /** + * Create a new StyleInfo class, with the standard constructor, and augmented by + * the StyleInfoBase's members. + * @param proto + */ + newStyleInfo: function( proto ) { + function StyleInfo( el ) { + this.targetElement = el; + this._lastCss = this.getCss(); + } + PIE.Util.merge( StyleInfo.prototype, PIE.StyleInfoBase, proto ); + StyleInfo._propsCache = {}; + return StyleInfo; + }, + + /** + * Get an object representation of the target CSS style, caching it for each unique + * CSS value string. + * @return {Object} + */ + getProps: function() { + var css = this.getCss(), + cache = this.constructor._propsCache; + return css ? ( css in cache ? cache[ css ] : ( cache[ css ] = this.parseCss( css ) ) ) : null; + }, + + /** + * Get the raw CSS value for the target style + * @return {string} + */ + getCss: cacheWhenLocked( function() { + var el = this.targetElement, + ctor = this.constructor, + s = el.style, + cs = el.currentStyle, + cssProp = this.cssProperty, + styleProp = this.styleProperty, + prefixedCssProp = ctor._prefixedCssProp || ( ctor._prefixedCssProp = PIE.CSS_PREFIX + cssProp ), + prefixedStyleProp = ctor._prefixedStyleProp || ( ctor._prefixedStyleProp = PIE.STYLE_PREFIX + styleProp.charAt(0).toUpperCase() + styleProp.substring(1) ); + return s[ prefixedStyleProp ] || cs.getAttribute( prefixedCssProp ) || s[ styleProp ] || cs.getAttribute( cssProp ); + } ), + + /** + * Determine whether the target CSS style is active. + * @return {boolean} + */ + isActive: cacheWhenLocked( function() { + return !!this.getProps(); + } ), + + /** + * Determine whether the target CSS style has changed since the last time it was used. + * @return {boolean} + */ + changed: cacheWhenLocked( function() { + var currentCss = this.getCss(), + changed = currentCss !== this._lastCss; + this._lastCss = currentCss; + return changed; + } ), + + cacheWhenLocked: cacheWhenLocked, + + lock: function() { + ++this._locked; + }, + + unlock: function() { + if( !--this._locked ) { + delete this._lockedValues; + } + } +}; + +})();/** + * Handles parsing, caching, and detecting changes to background (and -pie-background) CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: PIE.CSS_PREFIX + 'background', + styleProperty: PIE.STYLE_PREFIX + 'Background', + + attachIdents: { 'scroll':1, 'fixed':1, 'local':1 }, + repeatIdents: { 'repeat-x':1, 'repeat-y':1, 'repeat':1, 'no-repeat':1 }, + originAndClipIdents: { 'padding-box':1, 'border-box':1, 'content-box':1 }, + positionIdents: { 'top':1, 'right':1, 'bottom':1, 'left':1, 'center':1 }, + sizeIdents: { 'contain':1, 'cover':1 }, + propertyNames: { + CLIP: 'backgroundClip', + COLOR: 'backgroundColor', + IMAGE: 'backgroundImage', + ORIGIN: 'backgroundOrigin', + POSITION: 'backgroundPosition', + REPEAT: 'backgroundRepeat', + SIZE: 'backgroundSize' + }, + + /** + * For background styles, we support the -pie-background property but fall back to the standard + * backround* properties. The reason we have to use the prefixed version is that IE natively + * parses the standard properties and if it sees something it doesn't know how to parse, for example + * multiple values or gradient definitions, it will throw that away and not make it available through + * currentStyle. + * + * Format of return object: + * { + * color: <PIE.Color>, + * bgImages: [ + * { + * imgType: 'image', + * imgUrl: 'image.png', + * imgRepeat: <'no-repeat' | 'repeat-x' | 'repeat-y' | 'repeat'>, + * bgPosition: <PIE.BgPosition>, + * bgAttachment: <'scroll' | 'fixed' | 'local'>, + * bgOrigin: <'border-box' | 'padding-box' | 'content-box'>, + * bgClip: <'border-box' | 'padding-box'>, + * bgSize: <PIE.BgSize>, + * origString: 'url(img.png) no-repeat top left' + * }, + * { + * imgType: 'linear-gradient', + * gradientStart: <PIE.BgPosition>, + * angle: <PIE.Angle>, + * stops: [ + * { color: <PIE.Color>, offset: <PIE.Length> }, + * { color: <PIE.Color>, offset: <PIE.Length> }, ... + * ] + * } + * ] + * } + * @param {String} css + * @override + */ + parseCss: function( css ) { + var el = this.targetElement, + cs = el.currentStyle, + tokenizer, token, image, + tok_type = PIE.Tokenizer.Type, + type_operator = tok_type.OPERATOR, + type_ident = tok_type.IDENT, + type_color = tok_type.COLOR, + tokType, tokVal, + beginCharIndex = 0, + positionIdents = this.positionIdents, + gradient, stop, width, height, + props = { bgImages: [] }; + + function isBgPosToken( token ) { + return token && token.isLengthOrPercent() || ( token.tokenType & type_ident && token.tokenValue in positionIdents ); + } + + function sizeToken( token ) { + return token && ( ( token.isLengthOrPercent() && PIE.getLength( token.tokenValue ) ) || ( token.tokenValue === 'auto' && 'auto' ) ); + } + + // If the CSS3-specific -pie-background property is present, parse it + if( this.getCss3() ) { + tokenizer = new PIE.Tokenizer( css ); + image = {}; + + while( token = tokenizer.next() ) { + tokType = token.tokenType; + tokVal = token.tokenValue; + + if( !image.imgType && tokType & tok_type.FUNCTION && tokVal === 'linear-gradient' ) { + gradient = { stops: [], imgType: tokVal }; + stop = {}; + while( token = tokenizer.next() ) { + tokType = token.tokenType; + tokVal = token.tokenValue; + + // If we reached the end of the function and had at least 2 stops, flush the info + if( tokType & tok_type.CHARACTER && tokVal === ')' ) { + if( stop.color ) { + gradient.stops.push( stop ); + } + if( gradient.stops.length > 1 ) { + PIE.Util.merge( image, gradient ); + } + break; + } + + // Color stop - must start with color + if( tokType & type_color ) { + // if we already have an angle/position, make sure that the previous token was a comma + if( gradient.angle || gradient.gradientStart ) { + token = tokenizer.prev(); + if( token.tokenType !== type_operator ) { + break; //fail + } + tokenizer.next(); + } + + stop = { + color: PIE.getColor( tokVal ) + }; + // check for offset following color + token = tokenizer.next(); + if( token.isLengthOrPercent() ) { + stop.offset = PIE.getLength( token.tokenValue ); + } else { + tokenizer.prev(); + } + } + // Angle - can only appear in first spot + else if( tokType & tok_type.ANGLE && !gradient.angle && !stop.color && !gradient.stops.length ) { + gradient.angle = new PIE.Angle( token.tokenValue ); + } + else if( isBgPosToken( token ) && !gradient.gradientStart && !stop.color && !gradient.stops.length ) { + tokenizer.prev(); + gradient.gradientStart = new PIE.BgPosition( + tokenizer.until( function( t ) { + return !isBgPosToken( t ); + }, false ) + ); + } + else if( tokType & type_operator && tokVal === ',' ) { + if( stop.color ) { + gradient.stops.push( stop ); + stop = {}; + } + } + else { + // Found something we didn't recognize; fail without adding image + break; + } + } + } + else if( !image.imgType && tokType & tok_type.URL ) { + image.imgUrl = tokVal; + image.imgType = 'image'; + } + else if( isBgPosToken( token ) && !image.bgPosition ) { + tokenizer.prev(); + image.bgPosition = new PIE.BgPosition( + tokenizer.until( function( t ) { + return !isBgPosToken( t ); + }, false ) + ); + } + else if( tokType & type_ident ) { + if( tokVal in this.repeatIdents && !image.imgRepeat ) { + image.imgRepeat = tokVal; + } + else if( tokVal in this.originAndClipIdents && !image.bgOrigin ) { + image.bgOrigin = tokVal; + if( ( token = tokenizer.next() ) && ( token.tokenType & type_ident ) && + token.tokenValue in this.originAndClipIdents ) { + image.bgClip = token.tokenValue; + } else { + image.bgClip = tokVal; + tokenizer.prev(); + } + } + else if( tokVal in this.attachIdents && !image.bgAttachment ) { + image.bgAttachment = tokVal; + } + else { + return null; + } + } + else if( tokType & type_color && !props.color ) { + props.color = PIE.getColor( tokVal ); + } + else if( tokType & type_operator && tokVal === '/' && !image.bgSize && image.bgPosition ) { + // background size + token = tokenizer.next(); + if( token.tokenType & type_ident && token.tokenValue in this.sizeIdents ) { + image.bgSize = new PIE.BgSize( token.tokenValue ); + } + else if( width = sizeToken( token ) ) { + height = sizeToken( tokenizer.next() ); + if ( !height ) { + height = width; + tokenizer.prev(); + } + image.bgSize = new PIE.BgSize( width, height ); + } + else { + return null; + } + } + // new layer + else if( tokType & type_operator && tokVal === ',' && image.imgType ) { + image.origString = css.substring( beginCharIndex, tokenizer.ch - 1 ); + beginCharIndex = tokenizer.ch; + props.bgImages.push( image ); + image = {}; + } + else { + // Found something unrecognized; chuck everything + return null; + } + } + + // leftovers + if( image.imgType ) { + image.origString = css.substring( beginCharIndex ); + props.bgImages.push( image ); + } + } + + // Otherwise, use the standard background properties; let IE give us the values rather than parsing them + else { + this.withActualBg( PIE.ieDocMode < 9 ? + function() { + var propNames = this.propertyNames, + posX = cs[propNames.POSITION + 'X'], + posY = cs[propNames.POSITION + 'Y'], + img = cs[propNames.IMAGE], + color = cs[propNames.COLOR]; + + if( color !== 'transparent' ) { + props.color = PIE.getColor( color ) + } + if( img !== 'none' ) { + props.bgImages = [ { + imgType: 'image', + imgUrl: new PIE.Tokenizer( img ).next().tokenValue, + imgRepeat: cs[propNames.REPEAT], + bgPosition: new PIE.BgPosition( new PIE.Tokenizer( posX + ' ' + posY ).all() ) + } ]; + } + } : + function() { + var propNames = this.propertyNames, + splitter = /\s*,\s*/, + images = cs[propNames.IMAGE].split( splitter ), + color = cs[propNames.COLOR], + repeats, positions, origins, clips, sizes, i, len, image, sizeParts; + + if( color !== 'transparent' ) { + props.color = PIE.getColor( color ) + } + + len = images.length; + if( len && images[0] !== 'none' ) { + repeats = cs[propNames.REPEAT].split( splitter ); + positions = cs[propNames.POSITION].split( splitter ); + origins = cs[propNames.ORIGIN].split( splitter ); + clips = cs[propNames.CLIP].split( splitter ); + sizes = cs[propNames.SIZE].split( splitter ); + + props.bgImages = []; + for( i = 0; i < len; i++ ) { + image = images[ i ]; + if( image && image !== 'none' ) { + sizeParts = sizes[i].split( ' ' ); + props.bgImages.push( { + origString: image + ' ' + repeats[ i ] + ' ' + positions[ i ] + ' / ' + sizes[ i ] + ' ' + + origins[ i ] + ' ' + clips[ i ], + imgType: 'image', + imgUrl: new PIE.Tokenizer( image ).next().tokenValue, + imgRepeat: repeats[ i ], + bgPosition: new PIE.BgPosition( new PIE.Tokenizer( positions[ i ] ).all() ), + bgOrigin: origins[ i ], + bgClip: clips[ i ], + bgSize: new PIE.BgSize( sizeParts[ 0 ], sizeParts[ 1 ] ) + } ); + } + } + } + } + ); + } + + return ( props.color || props.bgImages[0] ) ? props : null; + }, + + /** + * Execute a function with the actual background styles (not overridden with runtimeStyle + * properties set by the renderers) available via currentStyle. + * @param fn + */ + withActualBg: function( fn ) { + var isIE9 = PIE.ieDocMode > 8, + propNames = this.propertyNames, + rs = this.targetElement.runtimeStyle, + rsImage = rs[propNames.IMAGE], + rsColor = rs[propNames.COLOR], + rsRepeat = rs[propNames.REPEAT], + rsClip, rsOrigin, rsSize, rsPosition, ret; + + if( rsImage ) rs[propNames.IMAGE] = ''; + if( rsColor ) rs[propNames.COLOR] = ''; + if( rsRepeat ) rs[propNames.REPEAT] = ''; + if( isIE9 ) { + rsClip = rs[propNames.CLIP]; + rsOrigin = rs[propNames.ORIGIN]; + rsPosition = rs[propNames.POSITION]; + rsSize = rs[propNames.SIZE]; + if( rsClip ) rs[propNames.CLIP] = ''; + if( rsOrigin ) rs[propNames.ORIGIN] = ''; + if( rsPosition ) rs[propNames.POSITION] = ''; + if( rsSize ) rs[propNames.SIZE] = ''; + } + + ret = fn.call( this ); + + if( rsImage ) rs[propNames.IMAGE] = rsImage; + if( rsColor ) rs[propNames.COLOR] = rsColor; + if( rsRepeat ) rs[propNames.REPEAT] = rsRepeat; + if( isIE9 ) { + if( rsClip ) rs[propNames.CLIP] = rsClip; + if( rsOrigin ) rs[propNames.ORIGIN] = rsOrigin; + if( rsPosition ) rs[propNames.POSITION] = rsPosition; + if( rsSize ) rs[propNames.SIZE] = rsSize; + } + + return ret; + }, + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + return this.getCss3() || + this.withActualBg( function() { + var cs = this.targetElement.currentStyle, + propNames = this.propertyNames; + return cs[propNames.COLOR] + ' ' + cs[propNames.IMAGE] + ' ' + cs[propNames.REPEAT] + ' ' + + cs[propNames.POSITION + 'X'] + ' ' + cs[propNames.POSITION + 'Y']; + } ); + } ), + + getCss3: PIE.StyleInfoBase.cacheWhenLocked( function() { + var el = this.targetElement; + return el.style[ this.styleProperty ] || el.currentStyle.getAttribute( this.cssProperty ); + } ), + + /** + * Tests if style.PiePngFix or the -pie-png-fix property is set to true in IE6. + */ + isPngFix: function() { + var val = 0, el; + if( PIE.ieVersion < 7 ) { + el = this.targetElement; + val = ( '' + ( el.style[ PIE.STYLE_PREFIX + 'PngFix' ] || el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'png-fix' ) ) === 'true' ); + } + return val; + }, + + /** + * The isActive logic is slightly different, because getProps() always returns an object + * even if it is just falling back to the native background properties. But we only want + * to report is as being "active" if either the -pie-background override property is present + * and parses successfully or '-pie-png-fix' is set to true in IE6. + */ + isActive: PIE.StyleInfoBase.cacheWhenLocked( function() { + return (this.getCss3() || this.isPngFix()) && !!this.getProps(); + } ) + +} );/** + * Handles parsing, caching, and detecting changes to border CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BorderStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + sides: [ 'Top', 'Right', 'Bottom', 'Left' ], + namedWidths: { + 'thin': '1px', + 'medium': '3px', + 'thick': '5px' + }, + + parseCss: function( css ) { + var w = {}, + s = {}, + c = {}, + active = false, + colorsSame = true, + stylesSame = true, + widthsSame = true; + + this.withActualBorder( function() { + var el = this.targetElement, + cs = el.currentStyle, + i = 0, + style, color, width, lastStyle, lastColor, lastWidth, side, ltr; + for( ; i < 4; i++ ) { + side = this.sides[ i ]; + + ltr = side.charAt(0).toLowerCase(); + style = s[ ltr ] = cs[ 'border' + side + 'Style' ]; + color = cs[ 'border' + side + 'Color' ]; + width = cs[ 'border' + side + 'Width' ]; + + if( i > 0 ) { + if( style !== lastStyle ) { stylesSame = false; } + if( color !== lastColor ) { colorsSame = false; } + if( width !== lastWidth ) { widthsSame = false; } + } + lastStyle = style; + lastColor = color; + lastWidth = width; + + c[ ltr ] = PIE.getColor( color ); + + width = w[ ltr ] = PIE.getLength( s[ ltr ] === 'none' ? '0' : ( this.namedWidths[ width ] || width ) ); + if( width.pixels( this.targetElement ) > 0 ) { + active = true; + } + } + } ); + + return active ? { + widths: w, + styles: s, + colors: c, + widthsSame: widthsSame, + colorsSame: colorsSame, + stylesSame: stylesSame + } : null; + }, + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + var el = this.targetElement, + cs = el.currentStyle, + css; + + // Don't redraw or hide borders for cells in border-collapse:collapse tables + if( !( el.tagName in PIE.tableCellTags && el.offsetParent.currentStyle.borderCollapse === 'collapse' ) ) { + this.withActualBorder( function() { + css = cs.borderWidth + '|' + cs.borderStyle + '|' + cs.borderColor; + } ); + } + return css; + } ), + + /** + * Execute a function with the actual border styles (not overridden with runtimeStyle + * properties set by the renderers) available via currentStyle. + * @param fn + */ + withActualBorder: function( fn ) { + var rs = this.targetElement.runtimeStyle, + rsWidth = rs.borderWidth, + rsColor = rs.borderColor, + ret; + + if( rsWidth ) rs.borderWidth = ''; + if( rsColor ) rs.borderColor = ''; + + ret = fn.call( this ); + + if( rsWidth ) rs.borderWidth = rsWidth; + if( rsColor ) rs.borderColor = rsColor; + + return ret; + } + +} ); +/** + * Handles parsing, caching, and detecting changes to border-radius CSS + * @constructor + * @param {Element} el the target element + */ +(function() { + +PIE.BorderRadiusStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'border-radius', + styleProperty: 'borderRadius', + + parseCss: function( css ) { + var p = null, x, y, + tokenizer, token, length, + hasNonZero = false; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + + function collectLengths() { + var arr = [], num; + while( ( token = tokenizer.next() ) && token.isLengthOrPercent() ) { + length = PIE.getLength( token.tokenValue ); + num = length.getNumber(); + if( num < 0 ) { + return null; + } + if( num > 0 ) { + hasNonZero = true; + } + arr.push( length ); + } + return arr.length > 0 && arr.length < 5 ? { + 'tl': arr[0], + 'tr': arr[1] || arr[0], + 'br': arr[2] || arr[0], + 'bl': arr[3] || arr[1] || arr[0] + } : null; + } + + // Grab the initial sequence of lengths + if( x = collectLengths() ) { + // See if there is a slash followed by more lengths, for the y-axis radii + if( token ) { + if( token.tokenType & PIE.Tokenizer.Type.OPERATOR && token.tokenValue === '/' ) { + y = collectLengths(); + } + } else { + y = x; + } + + // Treat all-zero values the same as no value + if( hasNonZero && x && y ) { + p = { x: x, y : y }; + } + } + } + + return p; + } +} ); + +var zero = PIE.getLength( '0' ), + zeros = { 'tl': zero, 'tr': zero, 'br': zero, 'bl': zero }; +PIE.BorderRadiusStyleInfo.ALL_ZERO = { x: zeros, y: zeros }; + +})();/** + * Handles parsing, caching, and detecting changes to border-image CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'border-image', + styleProperty: 'borderImage', + + repeatIdents: { 'stretch':1, 'round':1, 'repeat':1, 'space':1 }, + + parseCss: function( css ) { + var p = null, tokenizer, token, type, value, + slices, widths, outsets, + slashCount = 0, + Type = PIE.Tokenizer.Type, + IDENT = Type.IDENT, + NUMBER = Type.NUMBER, + PERCENT = Type.PERCENT; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + p = {}; + + function isSlash( token ) { + return token && ( token.tokenType & Type.OPERATOR ) && ( token.tokenValue === '/' ); + } + + function isFillIdent( token ) { + return token && ( token.tokenType & IDENT ) && ( token.tokenValue === 'fill' ); + } + + function collectSlicesEtc() { + slices = tokenizer.until( function( tok ) { + return !( tok.tokenType & ( NUMBER | PERCENT ) ); + } ); + + if( isFillIdent( tokenizer.next() ) && !p.fill ) { + p.fill = true; + } else { + tokenizer.prev(); + } + + if( isSlash( tokenizer.next() ) ) { + slashCount++; + widths = tokenizer.until( function( token ) { + return !token.isLengthOrPercent() && !( ( token.tokenType & IDENT ) && token.tokenValue === 'auto' ); + } ); + + if( isSlash( tokenizer.next() ) ) { + slashCount++; + outsets = tokenizer.until( function( token ) { + return !token.isLength(); + } ); + } + } else { + tokenizer.prev(); + } + } + + while( token = tokenizer.next() ) { + type = token.tokenType; + value = token.tokenValue; + + // Numbers and/or 'fill' keyword: slice values. May be followed optionally by width values, followed optionally by outset values + if( type & ( NUMBER | PERCENT ) && !slices ) { + tokenizer.prev(); + collectSlicesEtc(); + } + else if( isFillIdent( token ) && !p.fill ) { + p.fill = true; + collectSlicesEtc(); + } + + // Idents: one or values for 'repeat' + else if( ( type & IDENT ) && this.repeatIdents[value] && !p.repeat ) { + p.repeat = { h: value }; + if( token = tokenizer.next() ) { + if( ( token.tokenType & IDENT ) && this.repeatIdents[token.tokenValue] ) { + p.repeat.v = token.tokenValue; + } else { + tokenizer.prev(); + } + } + } + + // URL of the image + else if( ( type & Type.URL ) && !p.src ) { + p.src = value; + } + + // Found something unrecognized; exit. + else { + return null; + } + } + + // Validate what we collected + if( !p.src || !slices || slices.length < 1 || slices.length > 4 || + ( widths && widths.length > 4 ) || ( slashCount === 1 && widths.length < 1 ) || + ( outsets && outsets.length > 4 ) || ( slashCount === 2 && outsets.length < 1 ) ) { + return null; + } + + // Fill in missing values + if( !p.repeat ) { + p.repeat = { h: 'stretch' }; + } + if( !p.repeat.v ) { + p.repeat.v = p.repeat.h; + } + + function distributeSides( tokens, convertFn ) { + return { + 't': convertFn( tokens[0] ), + 'r': convertFn( tokens[1] || tokens[0] ), + 'b': convertFn( tokens[2] || tokens[0] ), + 'l': convertFn( tokens[3] || tokens[1] || tokens[0] ) + }; + } + + p.slice = distributeSides( slices, function( tok ) { + return PIE.getLength( ( tok.tokenType & NUMBER ) ? tok.tokenValue + 'px' : tok.tokenValue ); + } ); + + if( widths && widths[0] ) { + p.widths = distributeSides( widths, function( tok ) { + return tok.isLengthOrPercent() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; + } ); + } + + if( outsets && outsets[0] ) { + p.outset = distributeSides( outsets, function( tok ) { + return tok.isLength() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; + } ); + } + } + + return p; + } + +} );/** + * Handles parsing, caching, and detecting changes to box-shadow CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'box-shadow', + styleProperty: 'boxShadow', + + parseCss: function( css ) { + var props, + getLength = PIE.getLength, + Type = PIE.Tokenizer.Type, + tokenizer; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + props = { outset: [], inset: [] }; + + function parseItem() { + var token, type, value, color, lengths, inset, len; + + while( token = tokenizer.next() ) { + value = token.tokenValue; + type = token.tokenType; + + if( type & Type.OPERATOR && value === ',' ) { + break; + } + else if( token.isLength() && !lengths ) { + tokenizer.prev(); + lengths = tokenizer.until( function( token ) { + return !token.isLength(); + } ); + } + else if( type & Type.COLOR && !color ) { + color = value; + } + else if( type & Type.IDENT && value === 'inset' && !inset ) { + inset = true; + } + else { //encountered an unrecognized token; fail. + return false; + } + } + + len = lengths && lengths.length; + if( len > 1 && len < 5 ) { + ( inset ? props.inset : props.outset ).push( { + xOffset: getLength( lengths[0].tokenValue ), + yOffset: getLength( lengths[1].tokenValue ), + blur: getLength( lengths[2] ? lengths[2].tokenValue : '0' ), + spread: getLength( lengths[3] ? lengths[3].tokenValue : '0' ), + color: PIE.getColor( color || 'currentColor' ) + } ); + return true; + } + return false; + } + + while( parseItem() ) {} + } + + return props && ( props.inset.length || props.outset.length ) ? props : null; + } +} ); +/** + * Retrieves the state of the element's visibility and display + * @constructor + * @param {Element} el the target element + */ +PIE.VisibilityStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + var cs = this.targetElement.currentStyle; + return cs.visibility + '|' + cs.display; + } ), + + parseCss: function() { + var el = this.targetElement, + rs = el.runtimeStyle, + cs = el.currentStyle, + rsVis = rs.visibility, + csVis; + + rs.visibility = ''; + csVis = cs.visibility; + rs.visibility = rsVis; + + return { + visible: csVis !== 'hidden', + displayed: cs.display !== 'none' + } + }, + + /** + * Always return false for isActive, since this property alone will not trigger + * a renderer to do anything. + */ + isActive: function() { + return false; + } + +} ); +PIE.RendererBase = { + + /** + * Create a new Renderer class, with the standard constructor, and augmented by + * the RendererBase's members. + * @param proto + */ + newRenderer: function( proto ) { + function Renderer( el, boundsInfo, styleInfos, parent ) { + this.targetElement = el; + this.boundsInfo = boundsInfo; + this.styleInfos = styleInfos; + this.parent = parent; + } + PIE.Util.merge( Renderer.prototype, PIE.RendererBase, proto ); + return Renderer; + }, + + /** + * Flag indicating the element has already been positioned at least once. + * @type {boolean} + */ + isPositioned: false, + + /** + * Determine if the renderer needs to be updated + * @return {boolean} + */ + needsUpdate: function() { + return false; + }, + + /** + * Run any preparation logic that would affect the main update logic of this + * renderer or any of the other renderers, e.g. things that might affect the + * element's size or style properties. + */ + prepareUpdate: PIE.emptyFn, + + /** + * Tell the renderer to update based on modified properties + */ + updateProps: function() { + this.destroy(); + if( this.isActive() ) { + this.draw(); + } + }, + + /** + * Tell the renderer to update based on modified element position + */ + updatePos: function() { + this.isPositioned = true; + }, + + /** + * Tell the renderer to update based on modified element dimensions + */ + updateSize: function() { + if( this.isActive() ) { + this.draw(); + } else { + this.destroy(); + } + }, + + + /** + * Add a layer element, with the given z-order index, to the renderer's main box element. We can't use + * z-index because that breaks when the root rendering box's z-index is 'auto' in IE8+ standards mode. + * So instead we make sure they are inserted into the DOM in the correct order. + * @param {number} index + * @param {Element} el + */ + addLayer: function( index, el ) { + this.removeLayer( index ); + for( var layers = this._layers || ( this._layers = [] ), i = index + 1, len = layers.length, layer; i < len; i++ ) { + layer = layers[i]; + if( layer ) { + break; + } + } + layers[index] = el; + this.getBox().insertBefore( el, layer || null ); + }, + + /** + * Retrieve a layer element by its index, or null if not present + * @param {number} index + * @return {Element} + */ + getLayer: function( index ) { + var layers = this._layers; + return layers && layers[index] || null; + }, + + /** + * Remove a layer element by its index + * @param {number} index + */ + removeLayer: function( index ) { + var layer = this.getLayer( index ), + box = this._box; + if( layer && box ) { + box.removeChild( layer ); + this._layers[index] = null; + } + }, + + + /** + * Get a VML shape by name, creating it if necessary. + * @param {string} name A name identifying the element + * @param {string=} subElName If specified a subelement of the shape will be created with this tag name + * @param {Element} parent The parent element for the shape; will be ignored if 'group' is specified + * @param {number=} group If specified, an ordinal group for the shape. 1 or greater. Groups are rendered + * using container elements in the correct order, to get correct z stacking without z-index. + */ + getShape: function( name, subElName, parent, group ) { + var shapes = this._shapes || ( this._shapes = {} ), + shape = shapes[ name ], + s; + + if( !shape ) { + shape = shapes[ name ] = PIE.Util.createVmlElement( 'shape' ); + if( subElName ) { + shape.appendChild( shape[ subElName ] = PIE.Util.createVmlElement( subElName ) ); + } + + if( group ) { + parent = this.getLayer( group ); + if( !parent ) { + this.addLayer( group, doc.createElement( 'group' + group ) ); + parent = this.getLayer( group ); + } + } + + parent.appendChild( shape ); + + s = shape.style; + s.position = 'absolute'; + s.left = s.top = 0; + s['behavior'] = 'url(#default#VML)'; + } + return shape; + }, + + /** + * Delete a named shape which was created by getShape(). Returns true if a shape with the + * given name was found and deleted, or false if there was no shape of that name. + * @param {string} name + * @return {boolean} + */ + deleteShape: function( name ) { + var shapes = this._shapes, + shape = shapes && shapes[ name ]; + if( shape ) { + shape.parentNode.removeChild( shape ); + delete shapes[ name ]; + } + return !!shape; + }, + + + /** + * For a given set of border radius length/percentage values, convert them to concrete pixel + * values based on the current size of the target element. + * @param {Object} radii + * @return {Object} + */ + getRadiiPixels: function( radii ) { + var el = this.targetElement, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + tlX, tlY, trX, trY, brX, brY, blX, blY, f; + + tlX = radii.x['tl'].pixels( el, w ); + tlY = radii.y['tl'].pixels( el, h ); + trX = radii.x['tr'].pixels( el, w ); + trY = radii.y['tr'].pixels( el, h ); + brX = radii.x['br'].pixels( el, w ); + brY = radii.y['br'].pixels( el, h ); + blX = radii.x['bl'].pixels( el, w ); + blY = radii.y['bl'].pixels( el, h ); + + // If any corner ellipses overlap, reduce them all by the appropriate factor. This formula + // is taken straight from the CSS3 Backgrounds and Borders spec. + f = Math.min( + w / ( tlX + trX ), + h / ( trY + brY ), + w / ( blX + brX ), + h / ( tlY + blY ) + ); + if( f < 1 ) { + tlX *= f; + tlY *= f; + trX *= f; + trY *= f; + brX *= f; + brY *= f; + blX *= f; + blY *= f; + } + + return { + x: { + 'tl': tlX, + 'tr': trX, + 'br': brX, + 'bl': blX + }, + y: { + 'tl': tlY, + 'tr': trY, + 'br': brY, + 'bl': blY + } + } + }, + + /** + * Return the VML path string for the element's background box, with corners rounded. + * @param {Object.<{t:number, r:number, b:number, l:number}>} shrink - if present, specifies number of + * pixels to shrink the box path inward from the element's four sides. + * @param {number=} mult If specified, all coordinates will be multiplied by this number + * @param {Object=} radii If specified, this will be used for the corner radii instead of the properties + * from this renderer's borderRadiusInfo object. + * @return {string} the VML path + */ + getBoxPath: function( shrink, mult, radii ) { + mult = mult || 1; + + var r, str, + bounds = this.boundsInfo.getBounds(), + w = bounds.w * mult, + h = bounds.h * mult, + radInfo = this.styleInfos.borderRadiusInfo, + floor = Math.floor, ceil = Math.ceil, + shrinkT = shrink ? shrink.t * mult : 0, + shrinkR = shrink ? shrink.r * mult : 0, + shrinkB = shrink ? shrink.b * mult : 0, + shrinkL = shrink ? shrink.l * mult : 0, + tlX, tlY, trX, trY, brX, brY, blX, blY; + + if( radii || radInfo.isActive() ) { + r = this.getRadiiPixels( radii || radInfo.getProps() ); + + tlX = r.x['tl'] * mult; + tlY = r.y['tl'] * mult; + trX = r.x['tr'] * mult; + trY = r.y['tr'] * mult; + brX = r.x['br'] * mult; + brY = r.y['br'] * mult; + blX = r.x['bl'] * mult; + blY = r.y['bl'] * mult; + + str = 'm' + floor( shrinkL ) + ',' + floor( tlY ) + + 'qy' + floor( tlX ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - trX ) + ',' + floor( shrinkT ) + + 'qx' + ceil( w - shrinkR ) + ',' + floor( trY ) + + 'l' + ceil( w - shrinkR ) + ',' + ceil( h - brY ) + + 'qy' + ceil( w - brX ) + ',' + ceil( h - shrinkB ) + + 'l' + floor( blX ) + ',' + ceil( h - shrinkB ) + + 'qx' + floor( shrinkL ) + ',' + ceil( h - blY ) + ' x e'; + } else { + // simplified path for non-rounded box + str = 'm' + floor( shrinkL ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - shrinkR ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - shrinkR ) + ',' + ceil( h - shrinkB ) + + 'l' + floor( shrinkL ) + ',' + ceil( h - shrinkB ) + + 'xe'; + } + return str; + }, + + + /** + * Get the container element for the shapes, creating it if necessary. + */ + getBox: function() { + var box = this.parent.getLayer( this.boxZIndex ), s; + + if( !box ) { + box = doc.createElement( this.boxName ); + s = box.style; + s.position = 'absolute'; + s.top = s.left = 0; + this.parent.addLayer( this.boxZIndex, box ); + } + + return box; + }, + + + /** + * Hide the actual border of the element. In IE7 and up we can just set its color to transparent; + * however IE6 does not support transparent borders so we have to get tricky with it. Also, some elements + * like form buttons require removing the border width altogether, so for those we increase the padding + * by the border size. + */ + hideBorder: function() { + var el = this.targetElement, + cs = el.currentStyle, + rs = el.runtimeStyle, + tag = el.tagName, + isIE6 = PIE.ieVersion === 6, + sides, side, i; + + if( ( isIE6 && ( tag in PIE.childlessElements || tag === 'FIELDSET' ) ) || + tag === 'BUTTON' || ( tag === 'INPUT' && el.type in PIE.inputButtonTypes ) ) { + rs.borderWidth = ''; + sides = this.styleInfos.borderInfo.sides; + for( i = sides.length; i--; ) { + side = sides[ i ]; + rs[ 'padding' + side ] = ''; + rs[ 'padding' + side ] = ( PIE.getLength( cs[ 'padding' + side ] ) ).pixels( el ) + + ( PIE.getLength( cs[ 'border' + side + 'Width' ] ) ).pixels( el ) + + ( PIE.ieVersion !== 8 && i % 2 ? 1 : 0 ); //needs an extra horizontal pixel to counteract the extra "inner border" going away + } + rs.borderWidth = 0; + } + else if( isIE6 ) { + // Wrap all the element's children in a custom element, set the element to visiblity:hidden, + // and set the wrapper element to visiblity:visible. This hides the outer element's decorations + // (background and border) but displays all the contents. + // TODO find a better way to do this that doesn't mess up the DOM parent-child relationship, + // as this can interfere with other author scripts which add/modify/delete children. Also, this + // won't work for elements which cannot take children, e.g. input/button/textarea/img/etc. Look into + // using a compositor filter or some other filter which masks the border. + if( el.childNodes.length !== 1 || el.firstChild.tagName !== 'ie6-mask' ) { + var cont = doc.createElement( 'ie6-mask' ), + s = cont.style, child; + s.visibility = 'visible'; + s.zoom = 1; + while( child = el.firstChild ) { + cont.appendChild( child ); + } + el.appendChild( cont ); + rs.visibility = 'hidden'; + } + } + else { + rs.borderColor = 'transparent'; + } + }, + + unhideBorder: function() { + + }, + + + /** + * Destroy the rendered objects. This is a base implementation which handles common renderer + * structures, but individual renderers may override as necessary. + */ + destroy: function() { + this.parent.removeLayer( this.boxZIndex ); + delete this._shapes; + delete this._layers; + } +}; +/** + * Root renderer; creates the outermost container element and handles keeping it aligned + * with the target element's size and position. + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.RootRenderer = PIE.RendererBase.newRenderer( { + + isActive: function() { + var children = this.childRenderers; + for( var i in children ) { + if( children.hasOwnProperty( i ) && children[ i ].isActive() ) { + return true; + } + } + return false; + }, + + needsUpdate: function() { + return this.styleInfos.visibilityInfo.changed(); + }, + + updatePos: function() { + if( this.isActive() ) { + var el = this.getPositioningElement(), + par = el, + docEl, + parRect, + tgtCS = el.currentStyle, + tgtPos = tgtCS.position, + boxPos, + s = this.getBox().style, cs, + x = 0, y = 0, + elBounds = this.boundsInfo.getBounds(), + logicalZoomRatio = elBounds.logicalZoomRatio; + + if( tgtPos === 'fixed' && PIE.ieVersion > 6 ) { + x = elBounds.x * logicalZoomRatio; + y = elBounds.y * logicalZoomRatio; + boxPos = tgtPos; + } else { + // Get the element's offsets from its nearest positioned ancestor. Uses + // getBoundingClientRect for accuracy and speed. + do { + par = par.offsetParent; + } while( par && ( par.currentStyle.position === 'static' ) ); + if( par ) { + parRect = par.getBoundingClientRect(); + cs = par.currentStyle; + x = ( elBounds.x - parRect.left ) * logicalZoomRatio - ( parseFloat(cs.borderLeftWidth) || 0 ); + y = ( elBounds.y - parRect.top ) * logicalZoomRatio - ( parseFloat(cs.borderTopWidth) || 0 ); + } else { + docEl = doc.documentElement; + x = ( elBounds.x + docEl.scrollLeft - docEl.clientLeft ) * logicalZoomRatio; + y = ( elBounds.y + docEl.scrollTop - docEl.clientTop ) * logicalZoomRatio; + } + boxPos = 'absolute'; + } + + s.position = boxPos; + s.left = x; + s.top = y; + s.zIndex = tgtPos === 'static' ? -1 : tgtCS.zIndex; + this.isPositioned = true; + } + }, + + updateSize: PIE.emptyFn, + + updateVisibility: function() { + var vis = this.styleInfos.visibilityInfo.getProps(); + this.getBox().style.display = ( vis.visible && vis.displayed ) ? '' : 'none'; + }, + + updateProps: function() { + if( this.isActive() ) { + this.updateVisibility(); + } else { + this.destroy(); + } + }, + + getPositioningElement: function() { + var el = this.targetElement; + return el.tagName in PIE.tableCellTags ? el.offsetParent : el; + }, + + getBox: function() { + var box = this._box, el; + if( !box ) { + el = this.getPositioningElement(); + box = this._box = doc.createElement( 'css3-container' ); + box.style['direction'] = 'ltr'; //fix positioning bug in rtl environments + + this.updateVisibility(); + + el.parentNode.insertBefore( box, el ); + } + return box; + }, + + finishUpdate: PIE.emptyFn, + + destroy: function() { + var box = this._box, par; + if( box && ( par = box.parentNode ) ) { + par.removeChild( box ); + } + delete this._box; + delete this._layers; + } + +} ); +/** + * Renderer for element backgrounds. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 2, + boxName: 'background', + + needsUpdate: function() { + var si = this.styleInfos; + return si.backgroundInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderImageInfo.isActive() || + si.borderRadiusInfo.isActive() || + si.backgroundInfo.isActive() || + ( si.boxShadowInfo.isActive() && si.boxShadowInfo.getProps().inset ); + }, + + /** + * Draw the shapes + */ + draw: function() { + var bounds = this.boundsInfo.getBounds(); + if( bounds.w && bounds.h ) { + this.drawBgColor(); + this.drawBgImages(); + } + }, + + /** + * Draw the background color shape + */ + drawBgColor: function() { + var props = this.styleInfos.backgroundInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + el = this.targetElement, + color = props && props.color, + shape, w, h, s, alpha; + + if( color && color.alpha() > 0 ) { + this.hideBackground(); + + shape = this.getShape( 'bgColor', 'fill', this.getBox(), 1 ); + w = bounds.w; + h = bounds.h; + shape.stroked = false; + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( null, 2 ); + s = shape.style; + s.width = w; + s.height = h; + shape.fill.color = color.colorValue( el ); + + alpha = color.alpha(); + if( alpha < 1 ) { + shape.fill.opacity = alpha; + } + } else { + this.deleteShape( 'bgColor' ); + } + }, + + /** + * Draw all the background image layers + */ + drawBgImages: function() { + var props = this.styleInfos.backgroundInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + images = props && props.bgImages, + img, shape, w, h, s, i; + + if( images ) { + this.hideBackground(); + + w = bounds.w; + h = bounds.h; + + i = images.length; + while( i-- ) { + img = images[i]; + shape = this.getShape( 'bgImage' + i, 'fill', this.getBox(), 2 ); + + shape.stroked = false; + shape.fill.type = 'tile'; + shape.fillcolor = 'none'; + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( 0, 2 ); + s = shape.style; + s.width = w; + s.height = h; + + if( img.imgType === 'linear-gradient' ) { + this.addLinearGradient( shape, img ); + } + else { + shape.fill.src = img.imgUrl; + this.positionBgImage( shape, i ); + } + } + } + + // Delete any bgImage shapes previously created which weren't used above + i = images ? images.length : 0; + while( this.deleteShape( 'bgImage' + i++ ) ) {} + }, + + + /** + * Set the position and clipping of the background image for a layer + * @param {Element} shape + * @param {number} index + */ + positionBgImage: function( shape, index ) { + var me = this; + PIE.Util.withImageSize( shape.fill.src, function( size ) { + var el = me.targetElement, + bounds = me.boundsInfo.getBounds(), + elW = bounds.w, + elH = bounds.h; + + // It's possible that the element dimensions are zero now but weren't when the original + // update executed, make sure that's not the case to avoid divide-by-zero error + if( elW && elH ) { + var fill = shape.fill, + si = me.styleInfos, + border = si.borderInfo.getProps(), + bw = border && border.widths, + bwT = bw ? bw['t'].pixels( el ) : 0, + bwR = bw ? bw['r'].pixels( el ) : 0, + bwB = bw ? bw['b'].pixels( el ) : 0, + bwL = bw ? bw['l'].pixels( el ) : 0, + bg = si.backgroundInfo.getProps().bgImages[ index ], + bgPos = bg.bgPosition ? bg.bgPosition.coords( el, elW - size.w - bwL - bwR, elH - size.h - bwT - bwB ) : { x:0, y:0 }, + repeat = bg.imgRepeat, + pxX, pxY, + clipT = 0, clipL = 0, + clipR = elW + 1, clipB = elH + 1, //make sure the default clip region is not inside the box (by a subpixel) + clipAdjust = PIE.ieVersion === 8 ? 0 : 1; //prior to IE8 requires 1 extra pixel in the image clip region + + // Positioning - find the pixel offset from the top/left and convert to a ratio + // The position is shifted by half a pixel, to adjust for the half-pixel coordorigin shift which is + // needed to fix antialiasing but makes the bg image fuzzy. + pxX = Math.round( bgPos.x ) + bwL + 0.5; + pxY = Math.round( bgPos.y ) + bwT + 0.5; + fill.position = ( pxX / elW ) + ',' + ( pxY / elH ); + + // Set the size of the image. We have to actually set it to px values otherwise it will not honor + // the user's browser zoom level and always display at its natural screen size. + fill['size']['x'] = 1; //Can be any value, just has to be set to "prime" it so the next line works. Weird! + fill['size'] = size.w + 'px,' + size.h + 'px'; + + // Repeating - clip the image shape + if( repeat && repeat !== 'repeat' ) { + if( repeat === 'repeat-x' || repeat === 'no-repeat' ) { + clipT = pxY + 1; + clipB = pxY + size.h + clipAdjust; + } + if( repeat === 'repeat-y' || repeat === 'no-repeat' ) { + clipL = pxX + 1; + clipR = pxX + size.w + clipAdjust; + } + shape.style.clip = 'rect(' + clipT + 'px,' + clipR + 'px,' + clipB + 'px,' + clipL + 'px)'; + } + } + } ); + }, + + + /** + * Draw the linear gradient for a gradient layer + * @param {Element} shape + * @param {Object} info The object holding the information about the gradient + */ + addLinearGradient: function( shape, info ) { + var el = this.targetElement, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + fill = shape.fill, + stops = info.stops, + stopCount = stops.length, + PI = Math.PI, + GradientUtil = PIE.GradientUtil, + perpendicularIntersect = GradientUtil.perpendicularIntersect, + distance = GradientUtil.distance, + metrics = GradientUtil.getGradientMetrics( el, w, h, info ), + angle = metrics.angle, + startX = metrics.startX, + startY = metrics.startY, + startCornerX = metrics.startCornerX, + startCornerY = metrics.startCornerY, + endCornerX = metrics.endCornerX, + endCornerY = metrics.endCornerY, + deltaX = metrics.deltaX, + deltaY = metrics.deltaY, + lineLength = metrics.lineLength, + vmlAngle, vmlGradientLength, vmlColors, + stopPx, vmlOffsetPct, + p, i, j, before, after; + + // In VML land, the angle of the rendered gradient depends on the aspect ratio of the shape's + // bounding box; for example specifying a 45 deg angle actually results in a gradient + // drawn diagonally from one corner to its opposite corner, which will only appear to the + // viewer as 45 degrees if the shape is equilateral. We adjust for this by taking the x/y deltas + // between the start and end points, multiply one of them by the shape's aspect ratio, + // and get their arctangent, resulting in an appropriate VML angle. If the angle is perfectly + // horizontal or vertical then we don't need to do this conversion. + vmlAngle = ( angle % 90 ) ? Math.atan2( deltaX * w / h, deltaY ) / PI * 180 : ( angle + 90 ); + + // VML angles are 180 degrees offset from CSS angles + vmlAngle += 180; + vmlAngle = vmlAngle % 360; + + // Add all the stops to the VML 'colors' list, including the first and last stops. + // For each, we find its pixel offset along the gradient-line; if the offset of a stop is less + // than that of its predecessor we increase it to be equal. We then map that pixel offset to a + // percentage along the VML gradient-line, which runs from shape corner to corner. + p = perpendicularIntersect( startCornerX, startCornerY, angle, endCornerX, endCornerY ); + vmlGradientLength = distance( startCornerX, startCornerY, p[0], p[1] ); + vmlColors = []; + p = perpendicularIntersect( startX, startY, angle, startCornerX, startCornerY ); + vmlOffsetPct = distance( startX, startY, p[0], p[1] ) / vmlGradientLength * 100; + + // Find the pixel offsets along the CSS3 gradient-line for each stop. + stopPx = []; + for( i = 0; i < stopCount; i++ ) { + stopPx.push( stops[i].offset ? stops[i].offset.pixels( el, lineLength ) : + i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); + } + // Fill in gaps with evenly-spaced offsets + for( i = 1; i < stopCount; i++ ) { + if( stopPx[ i ] === null ) { + before = stopPx[ i - 1 ]; + j = i; + do { + after = stopPx[ ++j ]; + } while( after === null ); + stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); + } + // Make sure each stop's offset is no less than the one before it + stopPx[ i ] = Math.max( stopPx[ i ], stopPx[ i - 1 ] ); + } + + // Convert to percentage along the VML gradient line and add to the VML 'colors' value + for( i = 0; i < stopCount; i++ ) { + vmlColors.push( + ( vmlOffsetPct + ( stopPx[ i ] / vmlGradientLength * 100 ) ) + '% ' + stops[i].color.colorValue( el ) + ); + } + + // Now, finally, we're ready to render the gradient fill. Set the start and end colors to + // the first and last stop colors; this just sets outer bounds for the gradient. + fill['angle'] = vmlAngle; + fill['type'] = 'gradient'; + fill['method'] = 'sigma'; + fill['color'] = stops[0].color.colorValue( el ); + fill['color2'] = stops[stopCount - 1].color.colorValue( el ); + if( fill['colors'] ) { //sometimes the colors object isn't initialized so we have to assign it directly (?) + fill['colors'].value = vmlColors.join( ',' ); + } else { + fill['colors'] = vmlColors.join( ',' ); + } + }, + + + /** + * Hide the actual background image and color of the element. + */ + hideBackground: function() { + var rs = this.targetElement.runtimeStyle; + rs.backgroundImage = 'url(about:blank)'; //ensures the background area reacts to mouse events + rs.backgroundColor = 'transparent'; + }, + + destroy: function() { + PIE.RendererBase.destroy.call( this ); + var rs = this.targetElement.runtimeStyle; + rs.backgroundImage = rs.backgroundColor = ''; + } + +} ); +/** + * Renderer for element borders. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BorderRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 4, + boxName: 'border', + + needsUpdate: function() { + var si = this.styleInfos; + return si.borderInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderRadiusInfo.isActive() && + !si.borderImageInfo.isActive() && + si.borderInfo.isActive(); //check BorderStyleInfo last because it's the most expensive + }, + + /** + * Draw the border shape(s) + */ + draw: function() { + var el = this.targetElement, + props = this.styleInfos.borderInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + shape, stroke, s, + segments, seg, i, len; + + if( props ) { + this.hideBorder(); + + segments = this.getBorderSegments( 2 ); + for( i = 0, len = segments.length; i < len; i++) { + seg = segments[i]; + shape = this.getShape( 'borderPiece' + i, seg.stroke ? 'stroke' : 'fill', this.getBox() ); + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = seg.path; + s = shape.style; + s.width = w; + s.height = h; + + shape.filled = !!seg.fill; + shape.stroked = !!seg.stroke; + if( seg.stroke ) { + stroke = shape.stroke; + stroke['weight'] = seg.weight + 'px'; + stroke.color = seg.color.colorValue( el ); + stroke['dashstyle'] = seg.stroke === 'dashed' ? '2 2' : seg.stroke === 'dotted' ? '1 1' : 'solid'; + stroke['linestyle'] = seg.stroke === 'double' && seg.weight > 2 ? 'ThinThin' : 'Single'; + } else { + shape.fill.color = seg.fill.colorValue( el ); + } + } + + // remove any previously-created border shapes which didn't get used above + while( this.deleteShape( 'borderPiece' + i++ ) ) {} + } + }, + + + /** + * Get the VML path definitions for the border segment(s). + * @param {number=} mult If specified, all coordinates will be multiplied by this number + * @return {Array.<string>} + */ + getBorderSegments: function( mult ) { + var el = this.targetElement, + bounds, elW, elH, + borderInfo = this.styleInfos.borderInfo, + segments = [], + floor, ceil, wT, wR, wB, wL, + round = Math.round, + borderProps, radiusInfo, radii, widths, styles, colors; + + if( borderInfo.isActive() ) { + borderProps = borderInfo.getProps(); + + widths = borderProps.widths; + styles = borderProps.styles; + colors = borderProps.colors; + + if( borderProps.widthsSame && borderProps.stylesSame && borderProps.colorsSame ) { + if( colors['t'].alpha() > 0 ) { + // shortcut for identical border on all sides - only need 1 stroked shape + wT = widths['t'].pixels( el ); //thickness + wR = wT / 2; //shrink + segments.push( { + path: this.getBoxPath( { t: wR, r: wR, b: wR, l: wR }, mult ), + stroke: styles['t'], + color: colors['t'], + weight: wT + } ); + } + } + else { + mult = mult || 1; + bounds = this.boundsInfo.getBounds(); + elW = bounds.w; + elH = bounds.h; + + wT = round( widths['t'].pixels( el ) ); + wR = round( widths['r'].pixels( el ) ); + wB = round( widths['b'].pixels( el ) ); + wL = round( widths['l'].pixels( el ) ); + var pxWidths = { + 't': wT, + 'r': wR, + 'b': wB, + 'l': wL + }; + + radiusInfo = this.styleInfos.borderRadiusInfo; + if( radiusInfo.isActive() ) { + radii = this.getRadiiPixels( radiusInfo.getProps() ); + } + + floor = Math.floor; + ceil = Math.ceil; + + function radius( xy, corner ) { + return radii ? radii[ xy ][ corner ] : 0; + } + + function curve( corner, shrinkX, shrinkY, startAngle, ccw, doMove ) { + var rx = radius( 'x', corner), + ry = radius( 'y', corner), + deg = 65535, + isRight = corner.charAt( 1 ) === 'r', + isBottom = corner.charAt( 0 ) === 'b'; + return ( rx > 0 && ry > 0 ) ? + ( doMove ? 'al' : 'ae' ) + + ( isRight ? ceil( elW - rx ) : floor( rx ) ) * mult + ',' + // center x + ( isBottom ? ceil( elH - ry ) : floor( ry ) ) * mult + ',' + // center y + ( floor( rx ) - shrinkX ) * mult + ',' + // width + ( floor( ry ) - shrinkY ) * mult + ',' + // height + ( startAngle * deg ) + ',' + // start angle + ( 45 * deg * ( ccw ? 1 : -1 ) // angle change + ) : ( + ( doMove ? 'm' : 'l' ) + + ( isRight ? elW - shrinkX : shrinkX ) * mult + ',' + + ( isBottom ? elH - shrinkY : shrinkY ) * mult + ); + } + + function line( side, shrink, ccw, doMove ) { + var + start = ( + side === 't' ? + floor( radius( 'x', 'tl') ) * mult + ',' + ceil( shrink ) * mult : + side === 'r' ? + ceil( elW - shrink ) * mult + ',' + floor( radius( 'y', 'tr') ) * mult : + side === 'b' ? + ceil( elW - radius( 'x', 'br') ) * mult + ',' + floor( elH - shrink ) * mult : + // side === 'l' ? + floor( shrink ) * mult + ',' + ceil( elH - radius( 'y', 'bl') ) * mult + ), + end = ( + side === 't' ? + ceil( elW - radius( 'x', 'tr') ) * mult + ',' + ceil( shrink ) * mult : + side === 'r' ? + ceil( elW - shrink ) * mult + ',' + ceil( elH - radius( 'y', 'br') ) * mult : + side === 'b' ? + floor( radius( 'x', 'bl') ) * mult + ',' + floor( elH - shrink ) * mult : + // side === 'l' ? + floor( shrink ) * mult + ',' + floor( radius( 'y', 'tl') ) * mult + ); + return ccw ? ( doMove ? 'm' + end : '' ) + 'l' + start : + ( doMove ? 'm' + start : '' ) + 'l' + end; + } + + + function addSide( side, sideBefore, sideAfter, cornerBefore, cornerAfter, baseAngle ) { + var vert = side === 'l' || side === 'r', + sideW = pxWidths[ side ], + beforeX, beforeY, afterX, afterY; + + if( sideW > 0 && styles[ side ] !== 'none' && colors[ side ].alpha() > 0 ) { + beforeX = pxWidths[ vert ? side : sideBefore ]; + beforeY = pxWidths[ vert ? sideBefore : side ]; + afterX = pxWidths[ vert ? side : sideAfter ]; + afterY = pxWidths[ vert ? sideAfter : side ]; + + if( styles[ side ] === 'dashed' || styles[ side ] === 'dotted' ) { + segments.push( { + path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + + curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), + fill: colors[ side ] + } ); + segments.push( { + path: line( side, sideW / 2, 0, 1 ), + stroke: styles[ side ], + weight: sideW, + color: colors[ side ] + } ); + segments.push( { + path: curve( cornerAfter, afterX, afterY, baseAngle, 0, 1 ) + + curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ), + fill: colors[ side ] + } ); + } + else { + segments.push( { + path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + + line( side, sideW, 0, 0 ) + + curve( cornerAfter, afterX, afterY, baseAngle, 0, 0 ) + + + ( styles[ side ] === 'double' && sideW > 2 ? + curve( cornerAfter, afterX - floor( afterX / 3 ), afterY - floor( afterY / 3 ), baseAngle - 45, 1, 0 ) + + line( side, ceil( sideW / 3 * 2 ), 1, 0 ) + + curve( cornerBefore, beforeX - floor( beforeX / 3 ), beforeY - floor( beforeY / 3 ), baseAngle, 1, 0 ) + + 'x ' + + curve( cornerBefore, floor( beforeX / 3 ), floor( beforeY / 3 ), baseAngle + 45, 0, 1 ) + + line( side, floor( sideW / 3 ), 1, 0 ) + + curve( cornerAfter, floor( afterX / 3 ), floor( afterY / 3 ), baseAngle, 0, 0 ) + : '' ) + + + curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ) + + line( side, 0, 1, 0 ) + + curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), + fill: colors[ side ] + } ); + } + } + } + + addSide( 't', 'l', 'r', 'tl', 'tr', 90 ); + addSide( 'r', 't', 'b', 'tr', 'br', 0 ); + addSide( 'b', 'r', 'l', 'br', 'bl', -90 ); + addSide( 'l', 'b', 't', 'bl', 'tl', -180 ); + } + } + + return segments; + }, + + destroy: function() { + var me = this; + if (me.finalized || !me.styleInfos.borderImageInfo.isActive()) { + me.targetElement.runtimeStyle.borderColor = ''; + } + PIE.RendererBase.destroy.call( me ); + } + + +} ); +/** + * Renderer for border-image + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BorderImageRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 5, + pieceNames: [ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl', 'c' ], + + needsUpdate: function() { + return this.styleInfos.borderImageInfo.changed(); + }, + + isActive: function() { + return this.styleInfos.borderImageInfo.isActive(); + }, + + draw: function() { + this.getBox(); //make sure pieces are created + + var props = this.styleInfos.borderImageInfo.getProps(), + borderProps = this.styleInfos.borderInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + el = this.targetElement, + pieces = this.pieces; + + PIE.Util.withImageSize( props.src, function( imgSize ) { + var elW = bounds.w, + elH = bounds.h, + zero = PIE.getLength( '0' ), + widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), + widthT = widths['t'].pixels( el ), + widthR = widths['r'].pixels( el ), + widthB = widths['b'].pixels( el ), + widthL = widths['l'].pixels( el ), + slices = props.slice, + sliceT = slices['t'].pixels( el ), + sliceR = slices['r'].pixels( el ), + sliceB = slices['b'].pixels( el ), + sliceL = slices['l'].pixels( el ); + + // Piece positions and sizes + function setSizeAndPos( piece, w, h, x, y ) { + var s = pieces[piece].style, + max = Math.max; + s.width = max(w, 0); + s.height = max(h, 0); + s.left = x; + s.top = y; + } + setSizeAndPos( 'tl', widthL, widthT, 0, 0 ); + setSizeAndPos( 't', elW - widthL - widthR, widthT, widthL, 0 ); + setSizeAndPos( 'tr', widthR, widthT, elW - widthR, 0 ); + setSizeAndPos( 'r', widthR, elH - widthT - widthB, elW - widthR, widthT ); + setSizeAndPos( 'br', widthR, widthB, elW - widthR, elH - widthB ); + setSizeAndPos( 'b', elW - widthL - widthR, widthB, widthL, elH - widthB ); + setSizeAndPos( 'bl', widthL, widthB, 0, elH - widthB ); + setSizeAndPos( 'l', widthL, elH - widthT - widthB, 0, widthT ); + setSizeAndPos( 'c', elW - widthL - widthR, elH - widthT - widthB, widthL, widthT ); + + + // image croppings + function setCrops( sides, crop, val ) { + for( var i=0, len=sides.length; i < len; i++ ) { + pieces[ sides[i] ]['imagedata'][ crop ] = val; + } + } + + // corners + setCrops( [ 'tl', 't', 'tr' ], 'cropBottom', ( imgSize.h - sliceT ) / imgSize.h ); + setCrops( [ 'tl', 'l', 'bl' ], 'cropRight', ( imgSize.w - sliceL ) / imgSize.w ); + setCrops( [ 'bl', 'b', 'br' ], 'cropTop', ( imgSize.h - sliceB ) / imgSize.h ); + setCrops( [ 'tr', 'r', 'br' ], 'cropLeft', ( imgSize.w - sliceR ) / imgSize.w ); + + // edges and center + // TODO right now this treats everything like 'stretch', need to support other schemes + //if( props.repeat.v === 'stretch' ) { + setCrops( [ 'l', 'r', 'c' ], 'cropTop', sliceT / imgSize.h ); + setCrops( [ 'l', 'r', 'c' ], 'cropBottom', sliceB / imgSize.h ); + //} + //if( props.repeat.h === 'stretch' ) { + setCrops( [ 't', 'b', 'c' ], 'cropLeft', sliceL / imgSize.w ); + setCrops( [ 't', 'b', 'c' ], 'cropRight', sliceR / imgSize.w ); + //} + + // center fill + pieces['c'].style.display = props.fill ? '' : 'none'; + }, this ); + }, + + getBox: function() { + var box = this.parent.getLayer( this.boxZIndex ), + s, piece, i, + pieceNames = this.pieceNames, + len = pieceNames.length; + + if( !box ) { + box = doc.createElement( 'border-image' ); + s = box.style; + s.position = 'absolute'; + + this.pieces = {}; + + for( i = 0; i < len; i++ ) { + piece = this.pieces[ pieceNames[i] ] = PIE.Util.createVmlElement( 'rect' ); + piece.appendChild( PIE.Util.createVmlElement( 'imagedata' ) ); + s = piece.style; + s['behavior'] = 'url(#default#VML)'; + s.position = "absolute"; + s.top = s.left = 0; + piece['imagedata'].src = this.styleInfos.borderImageInfo.getProps().src; + piece.stroked = false; + piece.filled = false; + box.appendChild( piece ); + } + + this.parent.addLayer( this.boxZIndex, box ); + } + + return box; + }, + + prepareUpdate: function() { + if (this.isActive()) { + var me = this, + el = me.targetElement, + rs = el.runtimeStyle, + widths = me.styleInfos.borderImageInfo.getProps().widths; + + // Force border-style to solid so it doesn't collapse + rs.borderStyle = 'solid'; + + // If widths specified in border-image shorthand, override border-width + // NOTE px units needed here as this gets used by the IE9 renderer too + if ( widths ) { + rs.borderTopWidth = widths['t'].pixels( el ) + 'px'; + rs.borderRightWidth = widths['r'].pixels( el ) + 'px'; + rs.borderBottomWidth = widths['b'].pixels( el ) + 'px'; + rs.borderLeftWidth = widths['l'].pixels( el ) + 'px'; + } + + // Make the border transparent + me.hideBorder(); + } + }, + + destroy: function() { + var me = this, + rs = me.targetElement.runtimeStyle; + rs.borderStyle = ''; + if (me.finalized || !me.styleInfos.borderInfo.isActive()) { + rs.borderColor = rs.borderWidth = ''; + } + PIE.RendererBase.destroy.call( this ); + } + +} ); +/** + * Renderer for outset box-shadows + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 1, + boxName: 'outset-box-shadow', + + needsUpdate: function() { + var si = this.styleInfos; + return si.boxShadowInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var boxShadowInfo = this.styleInfos.boxShadowInfo; + return boxShadowInfo.isActive() && boxShadowInfo.getProps().outset[0]; + }, + + draw: function() { + var me = this, + el = this.targetElement, + box = this.getBox(), + styleInfos = this.styleInfos, + shadowInfos = styleInfos.boxShadowInfo.getProps().outset, + radii = styleInfos.borderRadiusInfo.getProps(), + len = shadowInfos.length, + i = len, j, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + clipAdjust = PIE.ieVersion === 8 ? 1 : 0, //workaround for IE8 bug where VML leaks out top/left of clip region by 1px + corners = [ 'tl', 'tr', 'br', 'bl' ], corner, + shadowInfo, shape, fill, ss, xOff, yOff, spread, blur, shrink, color, alpha, path, + totalW, totalH, focusX, focusY, isBottom, isRight; + + + function getShadowShape( index, corner, xOff, yOff, color, blur, path ) { + var shape = me.getShape( 'shadow' + index + corner, 'fill', box, len - index ), + fill = shape.fill; + + // Position and size + shape['coordsize'] = w * 2 + ',' + h * 2; + shape['coordorigin'] = '1,1'; + + // Color and opacity + shape['stroked'] = false; + shape['filled'] = true; + fill.color = color.colorValue( el ); + if( blur ) { + fill['type'] = 'gradienttitle'; //makes the VML gradient follow the shape's outline - hooray for undocumented features?!?! + fill['color2'] = fill.color; + fill['opacity'] = 0; + } + + // Path + shape.path = path; + + // This needs to go last for some reason, to prevent rendering at incorrect size + ss = shape.style; + ss.left = xOff; + ss.top = yOff; + ss.width = w; + ss.height = h; + + return shape; + } + + + while( i-- ) { + shadowInfo = shadowInfos[ i ]; + xOff = shadowInfo.xOffset.pixels( el ); + yOff = shadowInfo.yOffset.pixels( el ); + spread = shadowInfo.spread.pixels( el ); + blur = shadowInfo.blur.pixels( el ); + color = shadowInfo.color; + // Shape path + shrink = -spread - blur; + if( !radii && blur ) { + // If blurring, use a non-null border radius info object so that getBoxPath will + // round the corners of the expanded shadow shape rather than squaring them off. + radii = PIE.BorderRadiusStyleInfo.ALL_ZERO; + } + path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii ); + + if( blur ) { + totalW = ( spread + blur ) * 2 + w; + totalH = ( spread + blur ) * 2 + h; + focusX = totalW ? blur * 2 / totalW : 0; + focusY = totalH ? blur * 2 / totalH : 0; + if( blur - spread > w / 2 || blur - spread > h / 2 ) { + // If the blur is larger than half the element's narrowest dimension, we cannot do + // this with a single shape gradient, because its focussize would have to be less than + // zero which results in ugly artifacts. Instead we create four shapes, each with its + // gradient focus past center, and then clip them so each only shows the quadrant + // opposite the focus. + for( j = 4; j--; ) { + corner = corners[j]; + isBottom = corner.charAt( 0 ) === 'b'; + isRight = corner.charAt( 1 ) === 'r'; + shape = getShadowShape( i, corner, xOff, yOff, color, blur, path ); + fill = shape.fill; + fill['focusposition'] = ( isRight ? 1 - focusX : focusX ) + ',' + + ( isBottom ? 1 - focusY : focusY ); + fill['focussize'] = '0,0'; + + // Clip to show only the appropriate quadrant. Add 1px to the top/left clip values + // in IE8 to prevent a bug where IE8 displays one pixel outside the clip region. + shape.style.clip = 'rect(' + ( ( isBottom ? totalH / 2 : 0 ) + clipAdjust ) + 'px,' + + ( isRight ? totalW : totalW / 2 ) + 'px,' + + ( isBottom ? totalH : totalH / 2 ) + 'px,' + + ( ( isRight ? totalW / 2 : 0 ) + clipAdjust ) + 'px)'; + } + } else { + // TODO delete old quadrant shapes if resizing expands past the barrier + shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); + fill = shape.fill; + fill['focusposition'] = focusX + ',' + focusY; + fill['focussize'] = ( 1 - focusX * 2 ) + ',' + ( 1 - focusY * 2 ); + } + } else { + shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); + alpha = color.alpha(); + if( alpha < 1 ) { + // shape.style.filter = 'alpha(opacity=' + ( alpha * 100 ) + ')'; + // ss.filter = 'progid:DXImageTransform.Microsoft.BasicImage(opacity=' + ( alpha ) + ')'; + shape.fill.opacity = alpha; + } + } + } + } + +} ); +/** + * Renderer for re-rendering img elements using VML. Kicks in if the img has + * a border-radius applied, or if the -pie-png-fix flag is set. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.ImgRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 6, + boxName: 'imgEl', + + needsUpdate: function() { + var si = this.styleInfos; + return this.targetElement.src !== this._lastSrc || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderRadiusInfo.isActive() || si.backgroundInfo.isPngFix(); + }, + + draw: function() { + this._lastSrc = src; + this.hideActualImg(); + + var shape = this.getShape( 'img', 'fill', this.getBox() ), + fill = shape.fill, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + borderProps = this.styleInfos.borderInfo.getProps(), + borderWidths = borderProps && borderProps.widths, + el = this.targetElement, + src = el.src, + round = Math.round, + cs = el.currentStyle, + getLength = PIE.getLength, + s, zero; + + // In IE6, the BorderRenderer will have hidden the border by moving the border-width to + // the padding; therefore we want to pretend the borders have no width so they aren't doubled + // when adding in the current padding value below. + if( !borderWidths || PIE.ieVersion < 7 ) { + zero = PIE.getLength( '0' ); + borderWidths = { 't': zero, 'r': zero, 'b': zero, 'l': zero }; + } + + shape.stroked = false; + fill.type = 'frame'; + fill.src = src; + fill.position = (w ? 0.5 / w : 0) + ',' + (h ? 0.5 / h : 0); + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( { + t: round( borderWidths['t'].pixels( el ) + getLength( cs.paddingTop ).pixels( el ) ), + r: round( borderWidths['r'].pixels( el ) + getLength( cs.paddingRight ).pixels( el ) ), + b: round( borderWidths['b'].pixels( el ) + getLength( cs.paddingBottom ).pixels( el ) ), + l: round( borderWidths['l'].pixels( el ) + getLength( cs.paddingLeft ).pixels( el ) ) + }, 2 ); + s = shape.style; + s.width = w; + s.height = h; + }, + + hideActualImg: function() { + this.targetElement.runtimeStyle.filter = 'alpha(opacity=0)'; + }, + + destroy: function() { + PIE.RendererBase.destroy.call( this ); + this.targetElement.runtimeStyle.filter = ''; + } + +} ); +/** + * Root renderer for IE9; manages the rendering layers in the element's background + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.IE9RootRenderer = PIE.RendererBase.newRenderer( { + + updatePos: PIE.emptyFn, + updateSize: PIE.emptyFn, + updateVisibility: PIE.emptyFn, + updateProps: PIE.emptyFn, + + outerCommasRE: /^,+|,+$/g, + innerCommasRE: /,+/g, + + setBackgroundLayer: function(zIndex, bg) { + var me = this, + bgLayers = me._bgLayers || ( me._bgLayers = [] ), + undef; + bgLayers[zIndex] = bg || undef; + }, + + finishUpdate: function() { + var me = this, + bgLayers = me._bgLayers, + bg; + if( bgLayers && ( bg = bgLayers.join( ',' ).replace( me.outerCommasRE, '' ).replace( me.innerCommasRE, ',' ) ) !== me._lastBg ) { + me._lastBg = me.targetElement.runtimeStyle.background = bg; + } + }, + + destroy: function() { + this.targetElement.runtimeStyle.background = ''; + delete this._bgLayers; + } + +} ); +/** + * Renderer for element backgrounds, specific for IE9. Only handles translating CSS3 gradients + * to an equivalent SVG data URI. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( { + + bgLayerZIndex: 1, + + needsUpdate: function() { + var si = this.styleInfos; + return si.backgroundInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.backgroundInfo.isActive() || si.borderImageInfo.isActive(); + }, + + draw: function() { + var me = this, + props = me.styleInfos.backgroundInfo.getProps(), + bg, images, i = 0, img, bgAreaSize, bgSize; + + if ( props ) { + bg = []; + + images = props.bgImages; + if ( images ) { + while( img = images[ i++ ] ) { + if (img.imgType === 'linear-gradient' ) { + bgAreaSize = me.getBgAreaSize( img.bgOrigin ); + bgSize = ( img.bgSize || PIE.BgSize.DEFAULT ).pixels( + me.targetElement, bgAreaSize.w, bgAreaSize.h, bgAreaSize.w, bgAreaSize.h + ), + bg.push( + 'url(data:image/svg+xml,' + escape( me.getGradientSvg( img, bgSize.w, bgSize.h ) ) + ') ' + + me.bgPositionToString( img.bgPosition ) + ' / ' + bgSize.w + 'px ' + bgSize.h + 'px ' + + ( img.bgAttachment || '' ) + ' ' + ( img.bgOrigin || '' ) + ' ' + ( img.bgClip || '' ) + ); + } else { + bg.push( img.origString ); + } + } + } + + if ( props.color ) { + bg.push( props.color.val ); + } + + me.parent.setBackgroundLayer(me.bgLayerZIndex, bg.join(',')); + } + }, + + bgPositionToString: function( bgPosition ) { + return bgPosition ? bgPosition.tokens.map(function(token) { + return token.tokenValue; + }).join(' ') : '0 0'; + }, + + getBgAreaSize: function( bgOrigin ) { + var me = this, + el = me.targetElement, + bounds = me.boundsInfo.getBounds(), + elW = bounds.w, + elH = bounds.h, + w = elW, + h = elH, + borders, getLength, cs; + + if( bgOrigin !== 'border-box' ) { + borders = me.styleInfos.borderInfo.getProps(); + if( borders && ( borders = borders.widths ) ) { + w -= borders[ 'l' ].pixels( el ) + borders[ 'l' ].pixels( el ); + h -= borders[ 't' ].pixels( el ) + borders[ 'b' ].pixels( el ); + } + } + + if ( bgOrigin === 'content-box' ) { + getLength = PIE.getLength; + cs = el.currentStyle; + w -= getLength( cs.paddingLeft ).pixels( el ) + getLength( cs.paddingRight ).pixels( el ); + h -= getLength( cs.paddingTop ).pixels( el ) + getLength( cs.paddingBottom ).pixels( el ); + } + + return { w: w, h: h }; + }, + + getGradientSvg: function( info, bgWidth, bgHeight ) { + var el = this.targetElement, + stopsInfo = info.stops, + stopCount = stopsInfo.length, + metrics = PIE.GradientUtil.getGradientMetrics( el, bgWidth, bgHeight, info ), + startX = metrics.startX, + startY = metrics.startY, + endX = metrics.endX, + endY = metrics.endY, + lineLength = metrics.lineLength, + stopPx, + i, j, before, after, + svg; + + // Find the pixel offsets along the CSS3 gradient-line for each stop. + stopPx = []; + for( i = 0; i < stopCount; i++ ) { + stopPx.push( stopsInfo[i].offset ? stopsInfo[i].offset.pixels( el, lineLength ) : + i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); + } + // Fill in gaps with evenly-spaced offsets + for( i = 1; i < stopCount; i++ ) { + if( stopPx[ i ] === null ) { + before = stopPx[ i - 1 ]; + j = i; + do { + after = stopPx[ ++j ]; + } while( after === null ); + stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); + } + } + + svg = [ + '<svg width="' + bgWidth + '" height="' + bgHeight + '" xmlns="http://www.w3.org/2000/svg">' + + '<defs>' + + '<linearGradient id="g" gradientUnits="userSpaceOnUse"' + + ' x1="' + ( startX / bgWidth * 100 ) + '%" y1="' + ( startY / bgHeight * 100 ) + '%" x2="' + ( endX / bgWidth * 100 ) + '%" y2="' + ( endY / bgHeight * 100 ) + '%">' + ]; + + // Convert to percentage along the SVG gradient line and add to the stops list + for( i = 0; i < stopCount; i++ ) { + svg.push( + '<stop offset="' + ( stopPx[ i ] / lineLength ) + + '" stop-color="' + stopsInfo[i].color.colorValue( el ) + + '" stop-opacity="' + stopsInfo[i].color.alpha() + '"/>' + ); + } + + svg.push( + '</linearGradient>' + + '</defs>' + + '<rect width="100%" height="100%" fill="url(#g)"/>' + + '</svg>' + ); + + return svg.join( '' ); + }, + + destroy: function() { + this.parent.setBackgroundLayer( this.bgLayerZIndex ); + } + +} ); +/** + * Renderer for border-image + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( { + + REPEAT: 'repeat', + STRETCH: 'stretch', + ROUND: 'round', + + bgLayerZIndex: 0, + + needsUpdate: function() { + return this.styleInfos.borderImageInfo.changed(); + }, + + isActive: function() { + return this.styleInfos.borderImageInfo.isActive(); + }, + + draw: function() { + var me = this, + props = me.styleInfos.borderImageInfo.getProps(), + borderProps = me.styleInfos.borderInfo.getProps(), + bounds = me.boundsInfo.getBounds(), + repeat = props.repeat, + repeatH = repeat.h, + repeatV = repeat.v, + el = me.targetElement, + isAsync = 0; + + PIE.Util.withImageSize( props.src, function( imgSize ) { + var elW = bounds.w, + elH = bounds.h, + imgW = imgSize.w, + imgH = imgSize.h, + + // The image cannot be referenced as a URL directly in the SVG because IE9 throws a strange + // security exception (perhaps due to cross-origin policy within data URIs?) Therefore we + // work around this by converting the image data into a data URI itself using a transient + // canvas. This unfortunately requires the border-image src to be within the same domain, + // which isn't a limitation in true border-image, so we need to try and find a better fix. + imgSrc = me.imageToDataURI( props.src, imgW, imgH ), + + REPEAT = me.REPEAT, + STRETCH = me.STRETCH, + ROUND = me.ROUND, + ceil = Math.ceil, + + zero = PIE.getLength( '0' ), + widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), + widthT = widths['t'].pixels( el ), + widthR = widths['r'].pixels( el ), + widthB = widths['b'].pixels( el ), + widthL = widths['l'].pixels( el ), + slices = props.slice, + sliceT = slices['t'].pixels( el ), + sliceR = slices['r'].pixels( el ), + sliceB = slices['b'].pixels( el ), + sliceL = slices['l'].pixels( el ), + centerW = elW - widthL - widthR, + middleH = elH - widthT - widthB, + imgCenterW = imgW - sliceL - sliceR, + imgMiddleH = imgH - sliceT - sliceB, + + // Determine the size of each tile - 'round' is handled below + tileSizeT = repeatH === STRETCH ? centerW : imgCenterW * widthT / sliceT, + tileSizeR = repeatV === STRETCH ? middleH : imgMiddleH * widthR / sliceR, + tileSizeB = repeatH === STRETCH ? centerW : imgCenterW * widthB / sliceB, + tileSizeL = repeatV === STRETCH ? middleH : imgMiddleH * widthL / sliceL, + + svg, + patterns = [], + rects = [], + i = 0; + + // For 'round', subtract from each tile's size enough so that they fill the space a whole number of times + if (repeatH === ROUND) { + tileSizeT -= (tileSizeT - (centerW % tileSizeT || tileSizeT)) / ceil(centerW / tileSizeT); + tileSizeB -= (tileSizeB - (centerW % tileSizeB || tileSizeB)) / ceil(centerW / tileSizeB); + } + if (repeatV === ROUND) { + tileSizeR -= (tileSizeR - (middleH % tileSizeR || tileSizeR)) / ceil(middleH / tileSizeR); + tileSizeL -= (tileSizeL - (middleH % tileSizeL || tileSizeL)) / ceil(middleH / tileSizeL); + } + + + // Build the SVG for the border-image rendering. Add each piece as a pattern, which is then stretched + // or repeated as the fill of a rect of appropriate size. + svg = [ + '<svg width="' + elW + '" height="' + elH + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' + ]; + + function addImage( x, y, w, h, cropX, cropY, cropW, cropH, tileW, tileH ) { + patterns.push( + '<pattern patternUnits="userSpaceOnUse" id="pattern' + i + '" ' + + 'x="' + (repeatH === REPEAT ? x + w / 2 - tileW / 2 : x) + '" ' + + 'y="' + (repeatV === REPEAT ? y + h / 2 - tileH / 2 : y) + '" ' + + 'width="' + tileW + '" height="' + tileH + '">' + + '<svg width="' + tileW + '" height="' + tileH + '" viewBox="' + cropX + ' ' + cropY + ' ' + cropW + ' ' + cropH + '" preserveAspectRatio="none">' + + '<image xlink:href="' + imgSrc + '" x="0" y="0" width="' + imgW + '" height="' + imgH + '" />' + + '</svg>' + + '</pattern>' + ); + rects.push( + '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" fill="url(#pattern' + i + ')" />' + ); + i++; + } + addImage( 0, 0, widthL, widthT, 0, 0, sliceL, sliceT, widthL, widthT ); // top left + addImage( widthL, 0, centerW, widthT, sliceL, 0, imgCenterW, sliceT, tileSizeT, widthT ); // top center + addImage( elW - widthR, 0, widthR, widthT, imgW - sliceR, 0, sliceR, sliceT, widthR, widthT ); // top right + addImage( 0, widthT, widthL, middleH, 0, sliceT, sliceL, imgMiddleH, widthL, tileSizeL ); // middle left + if ( props.fill ) { // center fill + addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH, + tileSizeT || tileSizeB || imgCenterW, tileSizeL || tileSizeR || imgMiddleH ); + } + addImage( elW - widthR, widthT, widthR, middleH, imgW - sliceR, sliceT, sliceR, imgMiddleH, widthR, tileSizeR ); // middle right + addImage( 0, elH - widthB, widthL, widthB, 0, imgH - sliceB, sliceL, sliceB, widthL, widthB ); // bottom left + addImage( widthL, elH - widthB, centerW, widthB, sliceL, imgH - sliceB, imgCenterW, sliceB, tileSizeB, widthB ); // bottom center + addImage( elW - widthR, elH - widthB, widthR, widthB, imgW - sliceR, imgH - sliceB, sliceR, sliceB, widthR, widthB ); // bottom right + + svg.push( + '<defs>' + + patterns.join('\n') + + '</defs>' + + rects.join('\n') + + '</svg>' + ); + + me.parent.setBackgroundLayer( me.bgLayerZIndex, 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box' ); + + // If the border-image's src wasn't immediately available, the SVG for its background layer + // will have been created asynchronously after the main element's update has finished; we'll + // therefore need to force the root renderer to sync to the final background once finished. + if( isAsync ) { + me.parent.finishUpdate(); + } + }, me ); + + isAsync = 1; + }, + + /** + * Convert a given image to a data URI + */ + imageToDataURI: (function() { + var uris = {}; + return function( src, width, height ) { + var uri = uris[ src ], + image, canvas; + if ( !uri ) { + image = new Image(); + canvas = doc.createElement( 'canvas' ); + image.src = src; + canvas.width = width; + canvas.height = height; + canvas.getContext( '2d' ).drawImage( image, 0, 0 ); + uri = uris[ src ] = canvas.toDataURL(); + } + return uri; + } + })(), + + prepareUpdate: PIE.BorderImageRenderer.prototype.prepareUpdate, + + destroy: function() { + var me = this, + rs = me.targetElement.runtimeStyle; + me.parent.setBackgroundLayer( me.bgLayerZIndex ); + rs.borderColor = rs.borderStyle = rs.borderWidth = ''; + } + +} ); + +PIE.Element = (function() { + + var wrappers = {}, + lazyInitCssProp = PIE.CSS_PREFIX + 'lazy-init', + pollCssProp = PIE.CSS_PREFIX + 'poll', + trackActiveCssProp = PIE.CSS_PREFIX + 'track-active', + trackHoverCssProp = PIE.CSS_PREFIX + 'track-hover', + hoverClass = PIE.CLASS_PREFIX + 'hover', + activeClass = PIE.CLASS_PREFIX + 'active', + focusClass = PIE.CLASS_PREFIX + 'focus', + firstChildClass = PIE.CLASS_PREFIX + 'first-child', + ignorePropertyNames = { 'background':1, 'bgColor':1, 'display': 1 }, + classNameRegExes = {}, + dummyArray = []; + + + function addClass( el, className ) { + el.className += ' ' + className; + } + + function removeClass( el, className ) { + var re = classNameRegExes[ className ] || + ( classNameRegExes[ className ] = new RegExp( '\\b' + className + '\\b', 'g' ) ); + el.className = el.className.replace( re, '' ); + } + + function delayAddClass( el, className /*, className2*/ ) { + var classes = dummyArray.slice.call( arguments, 1 ), + i = classes.length; + setTimeout( function() { + if( el ) { + while( i-- ) { + addClass( el, classes[ i ] ); + } + } + }, 0 ); + } + + function delayRemoveClass( el, className /*, className2*/ ) { + var classes = dummyArray.slice.call( arguments, 1 ), + i = classes.length; + setTimeout( function() { + if( el ) { + while( i-- ) { + removeClass( el, classes[ i ] ); + } + } + }, 0 ); + } + + + + function Element( el ) { + var renderers, + rootRenderer, + boundsInfo = new PIE.BoundsInfo( el ), + styleInfos, + styleInfosArr, + initializing, + initialized, + eventsAttached, + eventListeners = [], + delayed, + destroyed, + poll; + + /** + * Initialize PIE for this element. + */ + function init() { + if( !initialized ) { + var docEl, + bounds, + ieDocMode = PIE.ieDocMode, + cs = el.currentStyle, + lazy = cs.getAttribute( lazyInitCssProp ) === 'true', + trackActive = cs.getAttribute( trackActiveCssProp ) !== 'false', + trackHover = cs.getAttribute( trackHoverCssProp ) !== 'false', + childRenderers; + + // Polling for size/position changes: default to on in IE8, off otherwise, overridable by -pie-poll + poll = cs.getAttribute( pollCssProp ); + poll = ieDocMode > 7 ? poll !== 'false' : poll === 'true'; + + // Force layout so move/resize events will fire. Set this as soon as possible to avoid layout changes + // after load, but make sure it only gets called the first time through to avoid recursive calls to init(). + if( !initializing ) { + initializing = 1; + el.runtimeStyle.zoom = 1; + initFirstChildPseudoClass(); + } + + boundsInfo.lock(); + + // If the -pie-lazy-init:true flag is set, check if the element is outside the viewport and if so, delay initialization + if( lazy && ( bounds = boundsInfo.getBounds() ) && ( docEl = doc.documentElement || doc.body ) && + ( bounds.y > docEl.clientHeight || bounds.x > docEl.clientWidth || bounds.y + bounds.h < 0 || bounds.x + bounds.w < 0 ) ) { + if( !delayed ) { + delayed = 1; + PIE.OnScroll.observe( init ); + } + } else { + initialized = 1; + delayed = initializing = 0; + PIE.OnScroll.unobserve( init ); + + // Create the style infos and renderers + if ( ieDocMode === 9 ) { + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderImageInfo + ]; + rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + } else { + + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), + boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), + visibilityInfo: new PIE.VisibilityStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderInfo, + styleInfos.borderImageInfo, + styleInfos.borderRadiusInfo, + styleInfos.boxShadowInfo, + styleInfos.visibilityInfo + ]; + rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.BoxShadowOutsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + //new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + if( el.tagName === 'IMG' ) { + childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) ); + } + rootRenderer.childRenderers = childRenderers; // circular reference, can't pass in constructor; TODO is there a cleaner way? + } + renderers = [ rootRenderer ].concat( childRenderers ); + + // Add property change listeners to ancestors if requested + initAncestorEventListeners(); + + // Add to list of polled elements in IE8 + if( poll ) { + PIE.Heartbeat.observe( update ); + PIE.Heartbeat.run(); + } + + // Trigger rendering + update( 1 ); + } + + if( !eventsAttached ) { + eventsAttached = 1; + if( ieDocMode < 9 ) { + addListener( el, 'onmove', handleMoveOrResize ); + } + addListener( el, 'onresize', handleMoveOrResize ); + addListener( el, 'onpropertychange', propChanged ); + if( trackHover ) { + addListener( el, 'onmouseenter', mouseEntered ); + } + if( trackHover || trackActive ) { + addListener( el, 'onmouseleave', mouseLeft ); + } + if( trackActive ) { + addListener( el, 'onmousedown', mousePressed ); + } + if( el.tagName in PIE.focusableElements ) { + addListener( el, 'onfocus', focused ); + addListener( el, 'onblur', blurred ); + } + PIE.OnResize.observe( handleMoveOrResize ); + + PIE.OnUnload.observe( removeEventListeners ); + } + + boundsInfo.unlock(); + } + } + + + + + /** + * Event handler for onmove and onresize events. Invokes update() only if the element's + * bounds have previously been calculated, to prevent multiple runs during page load when + * the element has no initial CSS3 properties. + */ + function handleMoveOrResize() { + if( boundsInfo && boundsInfo.hasBeenQueried() ) { + update(); + } + } + + + /** + * Update position and/or size as necessary. Both move and resize events call + * this rather than the updatePos/Size functions because sometimes, particularly + * during page load, one will fire but the other won't. + */ + function update( force ) { + if( !destroyed ) { + if( initialized ) { + var i, len = renderers.length; + + lockAll(); + for( i = 0; i < len; i++ ) { + renderers[i].prepareUpdate(); + } + if( force || boundsInfo.positionChanged() ) { + /* TODO just using getBoundingClientRect (used internally by BoundsInfo) for detecting + position changes may not always be accurate; it's possible that + an element will actually move relative to its positioning parent, but its position + relative to the viewport will stay the same. Need to come up with a better way to + track movement. The most accurate would be the same logic used in RootRenderer.updatePos() + but that is a more expensive operation since it does some DOM walking, and we want this + check to be as fast as possible. */ + for( i = 0; i < len; i++ ) { + renderers[i].updatePos(); + } + } + if( force || boundsInfo.sizeChanged() ) { + for( i = 0; i < len; i++ ) { + renderers[i].updateSize(); + } + } + rootRenderer.finishUpdate(); + unlockAll(); + } + else if( !initializing ) { + init(); + } + } + } + + /** + * Handle property changes to trigger update when appropriate. + */ + function propChanged() { + var i, len = renderers.length, + renderer, + e = event; + + // Some elements like <table> fire onpropertychange events for old-school background properties + // ('background', 'bgColor') when runtimeStyle background properties are changed, which + // results in an infinite loop; therefore we filter out those property names. Also, 'display' + // is ignored because size calculations don't work correctly immediately when its onpropertychange + // event fires, and because it will trigger an onresize event anyway. + if( !destroyed && !( e && e.propertyName in ignorePropertyNames ) ) { + if( initialized ) { + lockAll(); + for( i = 0; i < len; i++ ) { + renderers[i].prepareUpdate(); + } + for( i = 0; i < len; i++ ) { + renderer = renderers[i]; + // Make sure position is synced if the element hasn't already been rendered. + // TODO this feels sloppy - look into merging propChanged and update functions + if( !renderer.isPositioned ) { + renderer.updatePos(); + } + if( renderer.needsUpdate() ) { + renderer.updateProps(); + } + } + rootRenderer.finishUpdate(); + unlockAll(); + } + else if( !initializing ) { + init(); + } + } + } + + + /** + * Handle mouseenter events. Adds a custom class to the element to allow IE6 to add + * hover styles to non-link elements, and to trigger a propertychange update. + */ + function mouseEntered() { + //must delay this because the mouseenter event fires before the :hover styles are added. + delayAddClass( el, hoverClass ); + } + + /** + * Handle mouseleave events + */ + function mouseLeft() { + //must delay this because the mouseleave event fires before the :hover styles are removed. + delayRemoveClass( el, hoverClass, activeClass ); + } + + /** + * Handle mousedown events. Adds a custom class to the element to allow IE6 to add + * active styles to non-link elements, and to trigger a propertychange update. + */ + function mousePressed() { + //must delay this because the mousedown event fires before the :active styles are added. + delayAddClass( el, activeClass ); + + // listen for mouseups on the document; can't just be on the element because the user might + // have dragged out of the element while the mouse button was held down + PIE.OnMouseup.observe( mouseReleased ); + } + + /** + * Handle mouseup events + */ + function mouseReleased() { + //must delay this because the mouseup event fires before the :active styles are removed. + delayRemoveClass( el, activeClass ); + + PIE.OnMouseup.unobserve( mouseReleased ); + } + + /** + * Handle focus events. Adds a custom class to the element to trigger a propertychange update. + */ + function focused() { + //must delay this because the focus event fires before the :focus styles are added. + delayAddClass( el, focusClass ); + } + + /** + * Handle blur events + */ + function blurred() { + //must delay this because the blur event fires before the :focus styles are removed. + delayRemoveClass( el, focusClass ); + } + + + /** + * Handle property changes on ancestors of the element; see initAncestorEventListeners() + * which adds these listeners as requested with the -pie-watch-ancestors CSS property. + */ + function ancestorPropChanged() { + var name = event.propertyName; + if( name === 'className' || name === 'id' ) { + propChanged(); + } + } + + function lockAll() { + boundsInfo.lock(); + for( var i = styleInfosArr.length; i--; ) { + styleInfosArr[i].lock(); + } + } + + function unlockAll() { + for( var i = styleInfosArr.length; i--; ) { + styleInfosArr[i].unlock(); + } + boundsInfo.unlock(); + } + + + function addListener( targetEl, type, handler ) { + targetEl.attachEvent( type, handler ); + eventListeners.push( [ targetEl, type, handler ] ); + } + + /** + * Remove all event listeners from the element and any monitored ancestors. + */ + function removeEventListeners() { + if (eventsAttached) { + var i = eventListeners.length, + listener; + + while( i-- ) { + listener = eventListeners[ i ]; + listener[ 0 ].detachEvent( listener[ 1 ], listener[ 2 ] ); + } + + PIE.OnUnload.unobserve( removeEventListeners ); + eventsAttached = 0; + eventListeners = []; + } + } + + + /** + * Clean everything up when the behavior is removed from the element, or the element + * is manually destroyed. + */ + function destroy() { + if( !destroyed ) { + var i, len; + + removeEventListeners(); + + destroyed = 1; + + // destroy any active renderers + if( renderers ) { + for( i = 0, len = renderers.length; i < len; i++ ) { + renderers[i].finalized = 1; + renderers[i].destroy(); + } + } + + // Remove from list of polled elements in IE8 + if( poll ) { + PIE.Heartbeat.unobserve( update ); + } + // Stop onresize listening + PIE.OnResize.unobserve( update ); + + // Kill references + renderers = boundsInfo = styleInfos = styleInfosArr = el = null; + } + } + + + /** + * If requested via the custom -pie-watch-ancestors CSS property, add onpropertychange and + * other event listeners to ancestor(s) of the element so we can pick up style changes + * based on CSS rules using descendant selectors. + */ + function initAncestorEventListeners() { + var watch = el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'watch-ancestors' ), + i, a; + if( watch ) { + watch = parseInt( watch, 10 ); + i = 0; + a = el.parentNode; + while( a && ( watch === 'NaN' || i++ < watch ) ) { + addListener( a, 'onpropertychange', ancestorPropChanged ); + addListener( a, 'onmouseenter', mouseEntered ); + addListener( a, 'onmouseleave', mouseLeft ); + addListener( a, 'onmousedown', mousePressed ); + if( a.tagName in PIE.focusableElements ) { + addListener( a, 'onfocus', focused ); + addListener( a, 'onblur', blurred ); + } + a = a.parentNode; + } + } + } + + + /** + * If the target element is a first child, add a pie_first-child class to it. This allows using + * the added class as a workaround for the fact that PIE's rendering element breaks the :first-child + * pseudo-class selector. + */ + function initFirstChildPseudoClass() { + var tmpEl = el, + isFirst = 1; + while( tmpEl = tmpEl.previousSibling ) { + if( tmpEl.nodeType === 1 ) { + isFirst = 0; + break; + } + } + if( isFirst ) { + addClass( el, firstChildClass ); + } + } + + + // These methods are all already bound to this instance so there's no need to wrap them + // in a closure to maintain the 'this' scope object when calling them. + this.init = init; + this.update = update; + this.destroy = destroy; + this.el = el; + } + + Element.getInstance = function( el ) { + var id = PIE.Util.getUID( el ); + return wrappers[ id ] || ( wrappers[ id ] = new Element( el ) ); + }; + + Element.destroy = function( el ) { + var id = PIE.Util.getUID( el ), + wrapper = wrappers[ id ]; + if( wrapper ) { + wrapper.destroy(); + delete wrappers[ id ]; + } + }; + + Element.destroyAll = function() { + var els = [], wrapper; + if( wrappers ) { + for( var w in wrappers ) { + if( wrappers.hasOwnProperty( w ) ) { + wrapper = wrappers[ w ]; + els.push( wrapper.el ); + wrapper.destroy(); + } + } + wrappers = {}; + } + return els; + }; + + return Element; +})(); + +/* + * This file exposes the public API for invoking PIE. + */ + + +/** + * @property supportsVML + * True if the current IE browser environment has a functioning VML engine. Should be true + * in most IEs, but in rare cases may be false. If false, PIE will exit immediately when + * attached to an element; this property may be used for debugging or by external scripts + * to perform some special action when VML support is absent. + * @type {boolean} + */ +PIE[ 'supportsVML' ] = PIE.supportsVML; + + +/** + * Programatically attach PIE to a single element. + * @param {Element} el + */ +PIE[ 'attach' ] = function( el ) { + if (PIE.ieDocMode < 10 && PIE.supportsVML) { + PIE.Element.getInstance( el ).init(); + } +}; + + +/** + * Programatically detach PIE from a single element. + * @param {Element} el + */ +PIE[ 'detach' ] = function( el ) { + PIE.Element.destroy( el ); +}; + + +} // if( !PIE ) +var el = element; + +function init() { + if ( doc.media !== 'print' ) { // IE strangely attaches a second copy of the behavior to elements when printing + var PIE = window[ 'PIE' ]; + if( PIE ) { + PIE['attach']( el ); + } + } +} + +function cleanup() { + if ( doc.media !== 'print' ) { + var PIE = window[ 'PIE' ]; + if (PIE) { + PIE['detach']( el ); + el = 0; + } + } +} + +if( el.readyState === 'complete' ) { + init(); +} +</script> +</PUBLIC:COMPONENT> diff --git a/themes/mantra/resources/js/PIE/PIE_uncompressed.js b/themes/mantra/resources/js/PIE/PIE_uncompressed.js new file mode 100644 index 00000000..85f6785e --- /dev/null +++ b/themes/mantra/resources/js/PIE/PIE_uncompressed.js @@ -0,0 +1,4474 @@ +/* +PIE: CSS3 rendering for IE +Version 1.0.0 +http://css3pie.com +Dual-licensed for use under the Apache License Version 2.0 or the General Public License (GPL) Version 2. +*/ +(function(){ +var doc = document;var PIE = window['PIE']; + +if( !PIE ) { + PIE = window['PIE'] = { + CSS_PREFIX: '-pie-', + STYLE_PREFIX: 'Pie', + CLASS_PREFIX: 'pie_', + tableCellTags: { + 'TD': 1, + 'TH': 1 + }, + + /** + * Lookup table of elements which cannot take custom children. + */ + childlessElements: { + 'TABLE':1, + 'THEAD':1, + 'TBODY':1, + 'TFOOT':1, + 'TR':1, + 'INPUT':1, + 'TEXTAREA':1, + 'SELECT':1, + 'OPTION':1, + 'IMG':1, + 'HR':1 + }, + + /** + * Elements that can receive user focus + */ + focusableElements: { + 'A':1, + 'INPUT':1, + 'TEXTAREA':1, + 'SELECT':1, + 'BUTTON':1 + }, + + /** + * Values of the type attribute for input elements displayed as buttons + */ + inputButtonTypes: { + 'submit':1, + 'button':1, + 'reset':1 + }, + + emptyFn: function() {} + }; + + // Force the background cache to be used. No reason it shouldn't be. + try { + doc.execCommand( 'BackgroundImageCache', false, true ); + } catch(e) {} + + (function() { + /* + * IE version detection approach by James Padolsey, with modifications -- from + * http://james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/ + */ + var ieVersion = 4, + div = doc.createElement('div'), + all = div.getElementsByTagName('i'), + shape; + while ( + div.innerHTML = '<!--[if gt IE ' + (++ieVersion) + ']><i></i><![endif]-->', + all[0] + ) {} + PIE.ieVersion = ieVersion; + + // Detect IE6 + if( ieVersion === 6 ) { + // IE6 can't access properties with leading dash, but can without it. + PIE.CSS_PREFIX = PIE.CSS_PREFIX.replace( /^-/, '' ); + } + + PIE.ieDocMode = doc.documentMode || PIE.ieVersion; + + // Detect VML support (a small number of IE installs don't have a working VML engine) + div.innerHTML = '<v:shape adj="1"/>'; + shape = div.firstChild; + shape.style['behavior'] = 'url(#default#VML)'; + PIE.supportsVML = (typeof shape['adj'] === "object"); + }()); +/** + * Utility functions + */ +(function() { + var vmlCreatorDoc, + idNum = 0, + imageSizes = {}; + + + PIE.Util = { + + /** + * To create a VML element, it must be created by a Document which has the VML + * namespace set. Unfortunately, if you try to add the namespace programatically + * into the main document, you will get an "Unspecified error" when trying to + * access document.namespaces before the document is finished loading. To get + * around this, we create a DocumentFragment, which in IE land is apparently a + * full-fledged Document. It allows adding namespaces immediately, so we add the + * namespace there and then have it create the VML element. + * @param {string} tag The tag name for the VML element + * @return {Element} The new VML element + */ + createVmlElement: function( tag ) { + var vmlPrefix = 'css3vml'; + if( !vmlCreatorDoc ) { + vmlCreatorDoc = doc.createDocumentFragment(); + vmlCreatorDoc.namespaces.add( vmlPrefix, 'urn:schemas-microsoft-com:vml' ); + } + return vmlCreatorDoc.createElement( vmlPrefix + ':' + tag ); + }, + + + /** + * Generate and return a unique ID for a given object. The generated ID is stored + * as a property of the object for future reuse. + * @param {Object} obj + */ + getUID: function( obj ) { + return obj && obj[ '_pieId' ] || ( obj[ '_pieId' ] = '_' + ++idNum ); + }, + + + /** + * Simple utility for merging objects + * @param {Object} obj1 The main object into which all others will be merged + * @param {...Object} var_args Other objects which will be merged into the first, in order + */ + merge: function( obj1 ) { + var i, len, p, objN, args = arguments; + for( i = 1, len = args.length; i < len; i++ ) { + objN = args[i]; + for( p in objN ) { + if( objN.hasOwnProperty( p ) ) { + obj1[ p ] = objN[ p ]; + } + } + } + return obj1; + }, + + + /** + * Execute a callback function, passing it the dimensions of a given image once + * they are known. + * @param {string} src The source URL of the image + * @param {function({w:number, h:number})} func The callback function to be called once the image dimensions are known + * @param {Object} ctx A context object which will be used as the 'this' value within the executed callback function + */ + withImageSize: function( src, func, ctx ) { + var size = imageSizes[ src ], img, queue; + if( size ) { + // If we have a queue, add to it + if( Object.prototype.toString.call( size ) === '[object Array]' ) { + size.push( [ func, ctx ] ); + } + // Already have the size cached, call func right away + else { + func.call( ctx, size ); + } + } else { + queue = imageSizes[ src ] = [ [ func, ctx ] ]; //create queue + img = new Image(); + img.onload = function() { + size = imageSizes[ src ] = { w: img.width, h: img.height }; + for( var i = 0, len = queue.length; i < len; i++ ) { + queue[ i ][ 0 ].call( queue[ i ][ 1 ], size ); + } + img.onload = null; + }; + img.src = src; + } + } + }; +})();/** + * Utility functions for handling gradients + */ +PIE.GradientUtil = { + + getGradientMetrics: function( el, width, height, gradientInfo ) { + var angle = gradientInfo.angle, + startPos = gradientInfo.gradientStart, + startX, startY, + endX, endY, + startCornerX, startCornerY, + endCornerX, endCornerY, + deltaX, deltaY, + p, UNDEF; + + // Find the "start" and "end" corners; these are the corners furthest along the gradient line. + // This is used below to find the start/end positions of the CSS3 gradient-line, and also in finding + // the total length of the VML rendered gradient-line corner to corner. + function findCorners() { + startCornerX = ( angle >= 90 && angle < 270 ) ? width : 0; + startCornerY = angle < 180 ? height : 0; + endCornerX = width - startCornerX; + endCornerY = height - startCornerY; + } + + // Normalize the angle to a value between [0, 360) + function normalizeAngle() { + while( angle < 0 ) { + angle += 360; + } + angle = angle % 360; + } + + // Find the start and end points of the gradient + if( startPos ) { + startPos = startPos.coords( el, width, height ); + startX = startPos.x; + startY = startPos.y; + } + if( angle ) { + angle = angle.degrees(); + + normalizeAngle(); + findCorners(); + + // If no start position was specified, then choose a corner as the starting point. + if( !startPos ) { + startX = startCornerX; + startY = startCornerY; + } + + // Find the end position by extending a perpendicular line from the gradient-line which + // intersects the corner opposite from the starting corner. + p = PIE.GradientUtil.perpendicularIntersect( startX, startY, angle, endCornerX, endCornerY ); + endX = p[0]; + endY = p[1]; + } + else if( startPos ) { + // Start position but no angle specified: find the end point by rotating 180deg around the center + endX = width - startX; + endY = height - startY; + } + else { + // Neither position nor angle specified; create vertical gradient from top to bottom + startX = startY = endX = 0; + endY = height; + } + deltaX = endX - startX; + deltaY = endY - startY; + + if( angle === UNDEF ) { + // Get the angle based on the change in x/y from start to end point. Checks first for horizontal + // or vertical angles so they get exact whole numbers rather than what atan2 gives. + angle = ( !deltaX ? ( deltaY < 0 ? 90 : 270 ) : + ( !deltaY ? ( deltaX < 0 ? 180 : 0 ) : + -Math.atan2( deltaY, deltaX ) / Math.PI * 180 + ) + ); + normalizeAngle(); + findCorners(); + } + + return { + angle: angle, + startX: startX, + startY: startY, + endX: endX, + endY: endY, + startCornerX: startCornerX, + startCornerY: startCornerY, + endCornerX: endCornerX, + endCornerY: endCornerY, + deltaX: deltaX, + deltaY: deltaY, + lineLength: PIE.GradientUtil.distance( startX, startY, endX, endY ) + } + }, + + /** + * Find the point along a given line (defined by a starting point and an angle), at which + * that line is intersected by a perpendicular line extending through another point. + * @param x1 - x coord of the starting point + * @param y1 - y coord of the starting point + * @param angle - angle of the line extending from the starting point (in degrees) + * @param x2 - x coord of point along the perpendicular line + * @param y2 - y coord of point along the perpendicular line + * @return [ x, y ] + */ + perpendicularIntersect: function( x1, y1, angle, x2, y2 ) { + // Handle straight vertical and horizontal angles, for performance and to avoid + // divide-by-zero errors. + if( angle === 0 || angle === 180 ) { + return [ x2, y1 ]; + } + else if( angle === 90 || angle === 270 ) { + return [ x1, y2 ]; + } + else { + // General approach: determine the Ax+By=C formula for each line (the slope of the second + // line is the negative inverse of the first) and then solve for where both formulas have + // the same x/y values. + var a1 = Math.tan( -angle * Math.PI / 180 ), + c1 = a1 * x1 - y1, + a2 = -1 / a1, + c2 = a2 * x2 - y2, + d = a2 - a1, + endX = ( c2 - c1 ) / d, + endY = ( a1 * c2 - a2 * c1 ) / d; + return [ endX, endY ]; + } + }, + + /** + * Find the distance between two points + * @param {Number} p1x + * @param {Number} p1y + * @param {Number} p2x + * @param {Number} p2y + * @return {Number} the distance + */ + distance: function( p1x, p1y, p2x, p2y ) { + var dx = p2x - p1x, + dy = p2y - p1y; + return Math.abs( + dx === 0 ? dy : + dy === 0 ? dx : + Math.sqrt( dx * dx + dy * dy ) + ); + } + +};/** + * + */ +PIE.Observable = function() { + /** + * List of registered observer functions + */ + this.observers = []; + + /** + * Hash of function ids to their position in the observers list, for fast lookup + */ + this.indexes = {}; +}; +PIE.Observable.prototype = { + + observe: function( fn ) { + var id = PIE.Util.getUID( fn ), + indexes = this.indexes, + observers = this.observers; + if( !( id in indexes ) ) { + indexes[ id ] = observers.length; + observers.push( fn ); + } + }, + + unobserve: function( fn ) { + var id = PIE.Util.getUID( fn ), + indexes = this.indexes; + if( id && id in indexes ) { + delete this.observers[ indexes[ id ] ]; + delete indexes[ id ]; + } + }, + + fire: function() { + var o = this.observers, + i = o.length; + while( i-- ) { + o[ i ] && o[ i ](); + } + } + +};/* + * Simple heartbeat timer - this is a brute-force workaround for syncing issues caused by IE not + * always firing the onmove and onresize events when elements are moved or resized. We check a few + * times every second to make sure the elements have the correct position and size. See Element.js + * which adds heartbeat listeners based on the custom -pie-poll flag, which defaults to true in IE8-9 + * and false elsewhere. + */ + +PIE.Heartbeat = new PIE.Observable(); +PIE.Heartbeat.run = function() { + var me = this, + interval; + if( !me.running ) { + interval = doc.documentElement.currentStyle.getAttribute( PIE.CSS_PREFIX + 'poll-interval' ) || 250; + (function beat() { + me.fire(); + setTimeout(beat, interval); + })(); + me.running = 1; + } +}; +/** + * Create an observable listener for the onunload event + */ +(function() { + PIE.OnUnload = new PIE.Observable(); + + function handleUnload() { + PIE.OnUnload.fire(); + window.detachEvent( 'onunload', handleUnload ); + window[ 'PIE' ] = null; + } + + window.attachEvent( 'onunload', handleUnload ); + + /** + * Attach an event which automatically gets detached onunload + */ + PIE.OnUnload.attachManagedEvent = function( target, name, handler ) { + target.attachEvent( name, handler ); + this.observe( function() { + target.detachEvent( name, handler ); + } ); + }; +})()/** + * Create a single observable listener for window resize events. + */ +PIE.OnResize = new PIE.Observable(); + +PIE.OnUnload.attachManagedEvent( window, 'onresize', function() { PIE.OnResize.fire(); } ); +/** + * Create a single observable listener for scroll events. Used for lazy loading based + * on the viewport, and for fixed position backgrounds. + */ +(function() { + PIE.OnScroll = new PIE.Observable(); + + function scrolled() { + PIE.OnScroll.fire(); + } + + PIE.OnUnload.attachManagedEvent( window, 'onscroll', scrolled ); + + PIE.OnResize.observe( scrolled ); +})(); +/** + * Listen for printing events, destroy all active PIE instances when printing, and + * restore them afterward. + */ +(function() { + + var elements; + + function beforePrint() { + elements = PIE.Element.destroyAll(); + } + + function afterPrint() { + if( elements ) { + for( var i = 0, len = elements.length; i < len; i++ ) { + PIE[ 'attach' ]( elements[i] ); + } + elements = 0; + } + } + + if( PIE.ieDocMode < 9 ) { + PIE.OnUnload.attachManagedEvent( window, 'onbeforeprint', beforePrint ); + PIE.OnUnload.attachManagedEvent( window, 'onafterprint', afterPrint ); + } + +})();/** + * Create a single observable listener for document mouseup events. + */ +PIE.OnMouseup = new PIE.Observable(); + +PIE.OnUnload.attachManagedEvent( doc, 'onmouseup', function() { PIE.OnMouseup.fire(); } ); +/** + * Wrapper for length and percentage style values. The value is immutable. A singleton instance per unique + * value is returned from PIE.getLength() - always use that instead of instantiating directly. + * @constructor + * @param {string} val The CSS string representing the length. It is assumed that this will already have + * been validated as a valid length or percentage syntax. + */ +PIE.Length = (function() { + var lengthCalcEl = doc.createElement( 'length-calc' ), + parent = doc.body || doc.documentElement, + s = lengthCalcEl.style, + conversions = {}, + units = [ 'mm', 'cm', 'in', 'pt', 'pc' ], + i = units.length, + instances = {}; + + s.position = 'absolute'; + s.top = s.left = '-9999px'; + + parent.appendChild( lengthCalcEl ); + while( i-- ) { + s.width = '100' + units[i]; + conversions[ units[i] ] = lengthCalcEl.offsetWidth / 100; + } + parent.removeChild( lengthCalcEl ); + + // All calcs from here on will use 1em + s.width = '1em'; + + + function Length( val ) { + this.val = val; + } + Length.prototype = { + /** + * Regular expression for matching the length unit + * @private + */ + unitRE: /(px|em|ex|mm|cm|in|pt|pc|%)$/, + + /** + * Get the numeric value of the length + * @return {number} The value + */ + getNumber: function() { + var num = this.num, + UNDEF; + if( num === UNDEF ) { + num = this.num = parseFloat( this.val ); + } + return num; + }, + + /** + * Get the unit of the length + * @return {string} The unit + */ + getUnit: function() { + var unit = this.unit, + m; + if( !unit ) { + m = this.val.match( this.unitRE ); + unit = this.unit = ( m && m[0] ) || 'px'; + } + return unit; + }, + + /** + * Determine whether this is a percentage length value + * @return {boolean} + */ + isPercentage: function() { + return this.getUnit() === '%'; + }, + + /** + * Resolve this length into a number of pixels. + * @param {Element} el - the context element, used to resolve font-relative values + * @param {(function():number|number)=} pct100 - the number of pixels that equal a 100% percentage. This can be either a number or a + * function which will be called to return the number. + */ + pixels: function( el, pct100 ) { + var num = this.getNumber(), + unit = this.getUnit(); + switch( unit ) { + case "px": + return num; + case "%": + return num * ( typeof pct100 === 'function' ? pct100() : pct100 ) / 100; + case "em": + return num * this.getEmPixels( el ); + case "ex": + return num * this.getEmPixels( el ) / 2; + default: + return num * conversions[ unit ]; + } + }, + + /** + * The em and ex units are relative to the font-size of the current element, + * however if the font-size is set using non-pixel units then we get that value + * rather than a pixel conversion. To get around this, we keep a floating element + * with width:1em which we insert into the target element and then read its offsetWidth. + * For elements that won't accept a child we insert into the parent node and perform + * additional calculation. If the font-size *is* specified in pixels, then we use that + * directly to avoid the expensive DOM manipulation. + * @param {Element} el + * @return {number} + */ + getEmPixels: function( el ) { + var fs = el.currentStyle.fontSize, + px, parent, me; + + if( fs.indexOf( 'px' ) > 0 ) { + return parseFloat( fs ); + } + else if( el.tagName in PIE.childlessElements ) { + me = this; + parent = el.parentNode; + return PIE.getLength( fs ).pixels( parent, function() { + return me.getEmPixels( parent ); + } ); + } + else { + el.appendChild( lengthCalcEl ); + px = lengthCalcEl.offsetWidth; + if( lengthCalcEl.parentNode === el ) { //not sure how this could be false but it sometimes is + el.removeChild( lengthCalcEl ); + } + return px; + } + } + }; + + + /** + * Retrieve a PIE.Length instance for the given value. A shared singleton instance is returned for each unique value. + * @param {string} val The CSS string representing the length. It is assumed that this will already have + * been validated as a valid length or percentage syntax. + */ + PIE.getLength = function( val ) { + return instances[ val ] || ( instances[ val ] = new Length( val ) ); + }; + + return Length; +})(); +/** + * Wrapper for a CSS3 bg-position value. Takes up to 2 position keywords and 2 lengths/percentages. + * @constructor + * @param {Array.<PIE.Tokenizer.Token>} tokens The tokens making up the background position value. + */ +PIE.BgPosition = (function() { + + var length_fifty = PIE.getLength( '50%' ), + vert_idents = { 'top': 1, 'center': 1, 'bottom': 1 }, + horiz_idents = { 'left': 1, 'center': 1, 'right': 1 }; + + + function BgPosition( tokens ) { + this.tokens = tokens; + } + BgPosition.prototype = { + /** + * Normalize the values into the form: + * [ xOffsetSide, xOffsetLength, yOffsetSide, yOffsetLength ] + * where: xOffsetSide is either 'left' or 'right', + * yOffsetSide is either 'top' or 'bottom', + * and x/yOffsetLength are both PIE.Length objects. + * @return {Array} + */ + getValues: function() { + if( !this._values ) { + var tokens = this.tokens, + len = tokens.length, + Tokenizer = PIE.Tokenizer, + identType = Tokenizer.Type, + length_zero = PIE.getLength( '0' ), + type_ident = identType.IDENT, + type_length = identType.LENGTH, + type_percent = identType.PERCENT, + type, value, + vals = [ 'left', length_zero, 'top', length_zero ]; + + // If only one value, the second is assumed to be 'center' + if( len === 1 ) { + tokens.push( new Tokenizer.Token( type_ident, 'center' ) ); + len++; + } + + // Two values - CSS2 + if( len === 2 ) { + // If both idents, they can appear in either order, so switch them if needed + if( type_ident & ( tokens[0].tokenType | tokens[1].tokenType ) && + tokens[0].tokenValue in vert_idents && tokens[1].tokenValue in horiz_idents ) { + tokens.push( tokens.shift() ); + } + if( tokens[0].tokenType & type_ident ) { + if( tokens[0].tokenValue === 'center' ) { + vals[1] = length_fifty; + } else { + vals[0] = tokens[0].tokenValue; + } + } + else if( tokens[0].isLengthOrPercent() ) { + vals[1] = PIE.getLength( tokens[0].tokenValue ); + } + if( tokens[1].tokenType & type_ident ) { + if( tokens[1].tokenValue === 'center' ) { + vals[3] = length_fifty; + } else { + vals[2] = tokens[1].tokenValue; + } + } + else if( tokens[1].isLengthOrPercent() ) { + vals[3] = PIE.getLength( tokens[1].tokenValue ); + } + } + + // Three or four values - CSS3 + else { + // TODO + } + + this._values = vals; + } + return this._values; + }, + + /** + * Find the coordinates of the background image from the upper-left corner of the background area. + * Note that these coordinate values are not rounded. + * @param {Element} el + * @param {number} width - the width for percentages (background area width minus image width) + * @param {number} height - the height for percentages (background area height minus image height) + * @return {Object} { x: Number, y: Number } + */ + coords: function( el, width, height ) { + var vals = this.getValues(), + pxX = vals[1].pixels( el, width ), + pxY = vals[3].pixels( el, height ); + + return { + x: vals[0] === 'right' ? width - pxX : pxX, + y: vals[2] === 'bottom' ? height - pxY : pxY + }; + } + }; + + return BgPosition; +})(); +/** + * Wrapper for a CSS3 background-size value. + * @constructor + * @param {String|PIE.Length} w The width parameter + * @param {String|PIE.Length} h The height parameter, if any + */ +PIE.BgSize = (function() { + + var CONTAIN = 'contain', + COVER = 'cover', + AUTO = 'auto'; + + + function BgSize( w, h ) { + this.w = w; + this.h = h; + } + BgSize.prototype = { + + pixels: function( el, areaW, areaH, imgW, imgH ) { + var me = this, + w = me.w, + h = me.h, + areaRatio = areaW / areaH, + imgRatio = imgW / imgH; + + if ( w === CONTAIN ) { + w = imgRatio > areaRatio ? areaW : areaH * imgRatio; + h = imgRatio > areaRatio ? areaW / imgRatio : areaH; + } + else if ( w === COVER ) { + w = imgRatio < areaRatio ? areaW : areaH * imgRatio; + h = imgRatio < areaRatio ? areaW / imgRatio : areaH; + } + else if ( w === AUTO ) { + h = ( h === AUTO ? imgH : h.pixels( el, areaH ) ); + w = h * imgRatio; + } + else { + w = w.pixels( el, areaW ); + h = ( h === AUTO ? w / imgRatio : h.pixels( el, areaH ) ); + } + + return { w: w, h: h }; + } + + }; + + BgSize.DEFAULT = new BgSize( AUTO, AUTO ); + + return BgSize; +})(); +/** + * Wrapper for angle values; handles conversion to degrees from all allowed angle units + * @constructor + * @param {string} val The raw CSS value for the angle. It is assumed it has been pre-validated. + */ +PIE.Angle = (function() { + function Angle( val ) { + this.val = val; + } + Angle.prototype = { + unitRE: /[a-z]+$/i, + + /** + * @return {string} The unit of the angle value + */ + getUnit: function() { + return this._unit || ( this._unit = this.val.match( this.unitRE )[0].toLowerCase() ); + }, + + /** + * Get the numeric value of the angle in degrees. + * @return {number} The degrees value + */ + degrees: function() { + var deg = this._deg, u, n; + if( deg === undefined ) { + u = this.getUnit(); + n = parseFloat( this.val, 10 ); + deg = this._deg = ( u === 'deg' ? n : u === 'rad' ? n / Math.PI * 180 : u === 'grad' ? n / 400 * 360 : u === 'turn' ? n * 360 : 0 ); + } + return deg; + } + }; + + return Angle; +})();/** + * Abstraction for colors values. Allows detection of rgba values. A singleton instance per unique + * value is returned from PIE.getColor() - always use that instead of instantiating directly. + * @constructor + * @param {string} val The raw CSS string value for the color + */ +PIE.Color = (function() { + var instances = {}; + + function Color( val ) { + this.val = val; + } + + /** + * Regular expression for matching rgba colors and extracting their components + * @type {RegExp} + */ + Color.rgbaRE = /\s*rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d+|\d*\.\d+)\s*\)\s*/; + + Color.names = { + "aliceblue":"F0F8FF", "antiquewhite":"FAEBD7", "aqua":"0FF", + "aquamarine":"7FFFD4", "azure":"F0FFFF", "beige":"F5F5DC", + "bisque":"FFE4C4", "black":"000", "blanchedalmond":"FFEBCD", + "blue":"00F", "blueviolet":"8A2BE2", "brown":"A52A2A", + "burlywood":"DEB887", "cadetblue":"5F9EA0", "chartreuse":"7FFF00", + "chocolate":"D2691E", "coral":"FF7F50", "cornflowerblue":"6495ED", + "cornsilk":"FFF8DC", "crimson":"DC143C", "cyan":"0FF", + "darkblue":"00008B", "darkcyan":"008B8B", "darkgoldenrod":"B8860B", + "darkgray":"A9A9A9", "darkgreen":"006400", "darkkhaki":"BDB76B", + "darkmagenta":"8B008B", "darkolivegreen":"556B2F", "darkorange":"FF8C00", + "darkorchid":"9932CC", "darkred":"8B0000", "darksalmon":"E9967A", + "darkseagreen":"8FBC8F", "darkslateblue":"483D8B", "darkslategray":"2F4F4F", + "darkturquoise":"00CED1", "darkviolet":"9400D3", "deeppink":"FF1493", + "deepskyblue":"00BFFF", "dimgray":"696969", "dodgerblue":"1E90FF", + "firebrick":"B22222", "floralwhite":"FFFAF0", "forestgreen":"228B22", + "fuchsia":"F0F", "gainsboro":"DCDCDC", "ghostwhite":"F8F8FF", + "gold":"FFD700", "goldenrod":"DAA520", "gray":"808080", + "green":"008000", "greenyellow":"ADFF2F", "honeydew":"F0FFF0", + "hotpink":"FF69B4", "indianred":"CD5C5C", "indigo":"4B0082", + "ivory":"FFFFF0", "khaki":"F0E68C", "lavender":"E6E6FA", + "lavenderblush":"FFF0F5", "lawngreen":"7CFC00", "lemonchiffon":"FFFACD", + "lightblue":"ADD8E6", "lightcoral":"F08080", "lightcyan":"E0FFFF", + "lightgoldenrodyellow":"FAFAD2", "lightgreen":"90EE90", "lightgrey":"D3D3D3", + "lightpink":"FFB6C1", "lightsalmon":"FFA07A", "lightseagreen":"20B2AA", + "lightskyblue":"87CEFA", "lightslategray":"789", "lightsteelblue":"B0C4DE", + "lightyellow":"FFFFE0", "lime":"0F0", "limegreen":"32CD32", + "linen":"FAF0E6", "magenta":"F0F", "maroon":"800000", + "mediumauqamarine":"66CDAA", "mediumblue":"0000CD", "mediumorchid":"BA55D3", + "mediumpurple":"9370D8", "mediumseagreen":"3CB371", "mediumslateblue":"7B68EE", + "mediumspringgreen":"00FA9A", "mediumturquoise":"48D1CC", "mediumvioletred":"C71585", + "midnightblue":"191970", "mintcream":"F5FFFA", "mistyrose":"FFE4E1", + "moccasin":"FFE4B5", "navajowhite":"FFDEAD", "navy":"000080", + "oldlace":"FDF5E6", "olive":"808000", "olivedrab":"688E23", + "orange":"FFA500", "orangered":"FF4500", "orchid":"DA70D6", + "palegoldenrod":"EEE8AA", "palegreen":"98FB98", "paleturquoise":"AFEEEE", + "palevioletred":"D87093", "papayawhip":"FFEFD5", "peachpuff":"FFDAB9", + "peru":"CD853F", "pink":"FFC0CB", "plum":"DDA0DD", + "powderblue":"B0E0E6", "purple":"800080", "red":"F00", + "rosybrown":"BC8F8F", "royalblue":"4169E1", "saddlebrown":"8B4513", + "salmon":"FA8072", "sandybrown":"F4A460", "seagreen":"2E8B57", + "seashell":"FFF5EE", "sienna":"A0522D", "silver":"C0C0C0", + "skyblue":"87CEEB", "slateblue":"6A5ACD", "slategray":"708090", + "snow":"FFFAFA", "springgreen":"00FF7F", "steelblue":"4682B4", + "tan":"D2B48C", "teal":"008080", "thistle":"D8BFD8", + "tomato":"FF6347", "turquoise":"40E0D0", "violet":"EE82EE", + "wheat":"F5DEB3", "white":"FFF", "whitesmoke":"F5F5F5", + "yellow":"FF0", "yellowgreen":"9ACD32" + }; + + Color.prototype = { + /** + * @private + */ + parse: function() { + if( !this._color ) { + var me = this, + v = me.val, + vLower, + m = v.match( Color.rgbaRE ); + if( m ) { + me._color = 'rgb(' + m[1] + ',' + m[2] + ',' + m[3] + ')'; + me._alpha = parseFloat( m[4] ); + } + else { + if( ( vLower = v.toLowerCase() ) in Color.names ) { + v = '#' + Color.names[vLower]; + } + me._color = v; + me._alpha = ( v === 'transparent' ? 0 : 1 ); + } + } + }, + + /** + * Retrieve the value of the color in a format usable by IE natively. This will be the same as + * the raw input value, except for rgba values which will be converted to an rgb value. + * @param {Element} el The context element, used to get 'currentColor' keyword value. + * @return {string} Color value + */ + colorValue: function( el ) { + this.parse(); + return this._color === 'currentColor' ? el.currentStyle.color : this._color; + }, + + /** + * Retrieve the alpha value of the color. Will be 1 for all values except for rgba values + * with an alpha component. + * @return {number} The alpha value, from 0 to 1. + */ + alpha: function() { + this.parse(); + return this._alpha; + } + }; + + + /** + * Retrieve a PIE.Color instance for the given value. A shared singleton instance is returned for each unique value. + * @param {string} val The CSS string representing the color. It is assumed that this will already have + * been validated as a valid color syntax. + */ + PIE.getColor = function(val) { + return instances[ val ] || ( instances[ val ] = new Color( val ) ); + }; + + return Color; +})();/** + * A tokenizer for CSS value strings. + * @constructor + * @param {string} css The CSS value string + */ +PIE.Tokenizer = (function() { + function Tokenizer( css ) { + this.css = css; + this.ch = 0; + this.tokens = []; + this.tokenIndex = 0; + } + + /** + * Enumeration of token type constants. + * @enum {number} + */ + var Type = Tokenizer.Type = { + ANGLE: 1, + CHARACTER: 2, + COLOR: 4, + DIMEN: 8, + FUNCTION: 16, + IDENT: 32, + LENGTH: 64, + NUMBER: 128, + OPERATOR: 256, + PERCENT: 512, + STRING: 1024, + URL: 2048 + }; + + /** + * A single token + * @constructor + * @param {number} type The type of the token - see PIE.Tokenizer.Type + * @param {string} value The value of the token + */ + Tokenizer.Token = function( type, value ) { + this.tokenType = type; + this.tokenValue = value; + }; + Tokenizer.Token.prototype = { + isLength: function() { + return this.tokenType & Type.LENGTH || ( this.tokenType & Type.NUMBER && this.tokenValue === '0' ); + }, + isLengthOrPercent: function() { + return this.isLength() || this.tokenType & Type.PERCENT; + } + }; + + Tokenizer.prototype = { + whitespace: /\s/, + number: /^[\+\-]?(\d*\.)?\d+/, + url: /^url\(\s*("([^"]*)"|'([^']*)'|([!#$%&*-~]*))\s*\)/i, + ident: /^\-?[_a-z][\w-]*/i, + string: /^("([^"]*)"|'([^']*)')/, + operator: /^[\/,]/, + hash: /^#[\w]+/, + hashColor: /^#([\da-f]{6}|[\da-f]{3})/i, + + unitTypes: { + 'px': Type.LENGTH, 'em': Type.LENGTH, 'ex': Type.LENGTH, + 'mm': Type.LENGTH, 'cm': Type.LENGTH, 'in': Type.LENGTH, + 'pt': Type.LENGTH, 'pc': Type.LENGTH, + 'deg': Type.ANGLE, 'rad': Type.ANGLE, 'grad': Type.ANGLE + }, + + colorFunctions: { + 'rgb': 1, 'rgba': 1, 'hsl': 1, 'hsla': 1 + }, + + + /** + * Advance to and return the next token in the CSS string. If the end of the CSS string has + * been reached, null will be returned. + * @param {boolean} forget - if true, the token will not be stored for the purposes of backtracking with prev(). + * @return {PIE.Tokenizer.Token} + */ + next: function( forget ) { + var css, ch, firstChar, match, val, + me = this; + + function newToken( type, value ) { + var tok = new Tokenizer.Token( type, value ); + if( !forget ) { + me.tokens.push( tok ); + me.tokenIndex++; + } + return tok; + } + function failure() { + me.tokenIndex++; + return null; + } + + // In case we previously backed up, return the stored token in the next slot + if( this.tokenIndex < this.tokens.length ) { + return this.tokens[ this.tokenIndex++ ]; + } + + // Move past leading whitespace characters + while( this.whitespace.test( this.css.charAt( this.ch ) ) ) { + this.ch++; + } + if( this.ch >= this.css.length ) { + return failure(); + } + + ch = this.ch; + css = this.css.substring( this.ch ); + firstChar = css.charAt( 0 ); + switch( firstChar ) { + case '#': + if( match = css.match( this.hashColor ) ) { + this.ch += match[0].length; + return newToken( Type.COLOR, match[0] ); + } + break; + + case '"': + case "'": + if( match = css.match( this.string ) ) { + this.ch += match[0].length; + return newToken( Type.STRING, match[2] || match[3] || '' ); + } + break; + + case "/": + case ",": + this.ch++; + return newToken( Type.OPERATOR, firstChar ); + + case 'u': + if( match = css.match( this.url ) ) { + this.ch += match[0].length; + return newToken( Type.URL, match[2] || match[3] || match[4] || '' ); + } + } + + // Numbers and values starting with numbers + if( match = css.match( this.number ) ) { + val = match[0]; + this.ch += val.length; + + // Check if it is followed by a unit + if( css.charAt( val.length ) === '%' ) { + this.ch++; + return newToken( Type.PERCENT, val + '%' ); + } + if( match = css.substring( val.length ).match( this.ident ) ) { + val += match[0]; + this.ch += match[0].length; + return newToken( this.unitTypes[ match[0].toLowerCase() ] || Type.DIMEN, val ); + } + + // Plain ol' number + return newToken( Type.NUMBER, val ); + } + + // Identifiers + if( match = css.match( this.ident ) ) { + val = match[0]; + this.ch += val.length; + + // Named colors + if( val.toLowerCase() in PIE.Color.names || val === 'currentColor' || val === 'transparent' ) { + return newToken( Type.COLOR, val ); + } + + // Functions + if( css.charAt( val.length ) === '(' ) { + this.ch++; + + // Color values in function format: rgb, rgba, hsl, hsla + if( val.toLowerCase() in this.colorFunctions ) { + function isNum( tok ) { + return tok && tok.tokenType & Type.NUMBER; + } + function isNumOrPct( tok ) { + return tok && ( tok.tokenType & ( Type.NUMBER | Type.PERCENT ) ); + } + function isValue( tok, val ) { + return tok && tok.tokenValue === val; + } + function next() { + return me.next( 1 ); + } + + if( ( val.charAt(0) === 'r' ? isNumOrPct( next() ) : isNum( next() ) ) && + isValue( next(), ',' ) && + isNumOrPct( next() ) && + isValue( next(), ',' ) && + isNumOrPct( next() ) && + ( val === 'rgb' || val === 'hsa' || ( + isValue( next(), ',' ) && + isNum( next() ) + ) ) && + isValue( next(), ')' ) ) { + return newToken( Type.COLOR, this.css.substring( ch, this.ch ) ); + } + return failure(); + } + + return newToken( Type.FUNCTION, val ); + } + + // Other identifier + return newToken( Type.IDENT, val ); + } + + // Standalone character + this.ch++; + return newToken( Type.CHARACTER, firstChar ); + }, + + /** + * Determine whether there is another token + * @return {boolean} + */ + hasNext: function() { + var next = this.next(); + this.prev(); + return !!next; + }, + + /** + * Back up and return the previous token + * @return {PIE.Tokenizer.Token} + */ + prev: function() { + return this.tokens[ this.tokenIndex-- - 2 ]; + }, + + /** + * Retrieve all the tokens in the CSS string + * @return {Array.<PIE.Tokenizer.Token>} + */ + all: function() { + while( this.next() ) {} + return this.tokens; + }, + + /** + * Return a list of tokens from the current position until the given function returns + * true. The final token will not be included in the list. + * @param {function():boolean} func - test function + * @param {boolean} require - if true, then if the end of the CSS string is reached + * before the test function returns true, null will be returned instead of the + * tokens that have been found so far. + * @return {Array.<PIE.Tokenizer.Token>} + */ + until: function( func, require ) { + var list = [], t, hit; + while( t = this.next() ) { + if( func( t ) ) { + hit = true; + this.prev(); + break; + } + list.push( t ); + } + return require && !hit ? null : list; + } + }; + + return Tokenizer; +})();/** + * Handles calculating, caching, and detecting changes to size and position of the element. + * @constructor + * @param {Element} el the target element + */ +PIE.BoundsInfo = function( el ) { + this.targetElement = el; +}; +PIE.BoundsInfo.prototype = { + + _locked: 0, + + positionChanged: function() { + var last = this._lastBounds, + bounds; + return !last || ( ( bounds = this.getBounds() ) && ( last.x !== bounds.x || last.y !== bounds.y ) ); + }, + + sizeChanged: function() { + var last = this._lastBounds, + bounds; + return !last || ( ( bounds = this.getBounds() ) && ( last.w !== bounds.w || last.h !== bounds.h ) ); + }, + + getLiveBounds: function() { + var el = this.targetElement, + rect = el.getBoundingClientRect(), + isIE9 = PIE.ieDocMode === 9, + isIE7 = PIE.ieVersion === 7, + width = rect.right - rect.left; + return { + x: rect.left, + y: rect.top, + // In some cases scrolling the page will cause IE9 to report incorrect dimensions + // in the rect returned by getBoundingClientRect, so we must query offsetWidth/Height + // instead. Also IE7 is inconsistent in using logical vs. device pixels in measurements + // so we must calculate the ratio and use it in certain places as a position adjustment. + w: isIE9 || isIE7 ? el.offsetWidth : width, + h: isIE9 || isIE7 ? el.offsetHeight : rect.bottom - rect.top, + logicalZoomRatio: ( isIE7 && width ) ? el.offsetWidth / width : 1 + }; + }, + + getBounds: function() { + return this._locked ? + ( this._lockedBounds || ( this._lockedBounds = this.getLiveBounds() ) ) : + this.getLiveBounds(); + }, + + hasBeenQueried: function() { + return !!this._lastBounds; + }, + + lock: function() { + ++this._locked; + }, + + unlock: function() { + if( !--this._locked ) { + if( this._lockedBounds ) this._lastBounds = this._lockedBounds; + this._lockedBounds = null; + } + } + +}; +(function() { + +function cacheWhenLocked( fn ) { + var uid = PIE.Util.getUID( fn ); + return function() { + if( this._locked ) { + var cache = this._lockedValues || ( this._lockedValues = {} ); + return ( uid in cache ) ? cache[ uid ] : ( cache[ uid ] = fn.call( this ) ); + } else { + return fn.call( this ); + } + } +} + + +PIE.StyleInfoBase = { + + _locked: 0, + + /** + * Create a new StyleInfo class, with the standard constructor, and augmented by + * the StyleInfoBase's members. + * @param proto + */ + newStyleInfo: function( proto ) { + function StyleInfo( el ) { + this.targetElement = el; + this._lastCss = this.getCss(); + } + PIE.Util.merge( StyleInfo.prototype, PIE.StyleInfoBase, proto ); + StyleInfo._propsCache = {}; + return StyleInfo; + }, + + /** + * Get an object representation of the target CSS style, caching it for each unique + * CSS value string. + * @return {Object} + */ + getProps: function() { + var css = this.getCss(), + cache = this.constructor._propsCache; + return css ? ( css in cache ? cache[ css ] : ( cache[ css ] = this.parseCss( css ) ) ) : null; + }, + + /** + * Get the raw CSS value for the target style + * @return {string} + */ + getCss: cacheWhenLocked( function() { + var el = this.targetElement, + ctor = this.constructor, + s = el.style, + cs = el.currentStyle, + cssProp = this.cssProperty, + styleProp = this.styleProperty, + prefixedCssProp = ctor._prefixedCssProp || ( ctor._prefixedCssProp = PIE.CSS_PREFIX + cssProp ), + prefixedStyleProp = ctor._prefixedStyleProp || ( ctor._prefixedStyleProp = PIE.STYLE_PREFIX + styleProp.charAt(0).toUpperCase() + styleProp.substring(1) ); + return s[ prefixedStyleProp ] || cs.getAttribute( prefixedCssProp ) || s[ styleProp ] || cs.getAttribute( cssProp ); + } ), + + /** + * Determine whether the target CSS style is active. + * @return {boolean} + */ + isActive: cacheWhenLocked( function() { + return !!this.getProps(); + } ), + + /** + * Determine whether the target CSS style has changed since the last time it was used. + * @return {boolean} + */ + changed: cacheWhenLocked( function() { + var currentCss = this.getCss(), + changed = currentCss !== this._lastCss; + this._lastCss = currentCss; + return changed; + } ), + + cacheWhenLocked: cacheWhenLocked, + + lock: function() { + ++this._locked; + }, + + unlock: function() { + if( !--this._locked ) { + delete this._lockedValues; + } + } +}; + +})();/** + * Handles parsing, caching, and detecting changes to background (and -pie-background) CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BackgroundStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: PIE.CSS_PREFIX + 'background', + styleProperty: PIE.STYLE_PREFIX + 'Background', + + attachIdents: { 'scroll':1, 'fixed':1, 'local':1 }, + repeatIdents: { 'repeat-x':1, 'repeat-y':1, 'repeat':1, 'no-repeat':1 }, + originAndClipIdents: { 'padding-box':1, 'border-box':1, 'content-box':1 }, + positionIdents: { 'top':1, 'right':1, 'bottom':1, 'left':1, 'center':1 }, + sizeIdents: { 'contain':1, 'cover':1 }, + propertyNames: { + CLIP: 'backgroundClip', + COLOR: 'backgroundColor', + IMAGE: 'backgroundImage', + ORIGIN: 'backgroundOrigin', + POSITION: 'backgroundPosition', + REPEAT: 'backgroundRepeat', + SIZE: 'backgroundSize' + }, + + /** + * For background styles, we support the -pie-background property but fall back to the standard + * backround* properties. The reason we have to use the prefixed version is that IE natively + * parses the standard properties and if it sees something it doesn't know how to parse, for example + * multiple values or gradient definitions, it will throw that away and not make it available through + * currentStyle. + * + * Format of return object: + * { + * color: <PIE.Color>, + * bgImages: [ + * { + * imgType: 'image', + * imgUrl: 'image.png', + * imgRepeat: <'no-repeat' | 'repeat-x' | 'repeat-y' | 'repeat'>, + * bgPosition: <PIE.BgPosition>, + * bgAttachment: <'scroll' | 'fixed' | 'local'>, + * bgOrigin: <'border-box' | 'padding-box' | 'content-box'>, + * bgClip: <'border-box' | 'padding-box'>, + * bgSize: <PIE.BgSize>, + * origString: 'url(img.png) no-repeat top left' + * }, + * { + * imgType: 'linear-gradient', + * gradientStart: <PIE.BgPosition>, + * angle: <PIE.Angle>, + * stops: [ + * { color: <PIE.Color>, offset: <PIE.Length> }, + * { color: <PIE.Color>, offset: <PIE.Length> }, ... + * ] + * } + * ] + * } + * @param {String} css + * @override + */ + parseCss: function( css ) { + var el = this.targetElement, + cs = el.currentStyle, + tokenizer, token, image, + tok_type = PIE.Tokenizer.Type, + type_operator = tok_type.OPERATOR, + type_ident = tok_type.IDENT, + type_color = tok_type.COLOR, + tokType, tokVal, + beginCharIndex = 0, + positionIdents = this.positionIdents, + gradient, stop, width, height, + props = { bgImages: [] }; + + function isBgPosToken( token ) { + return token && token.isLengthOrPercent() || ( token.tokenType & type_ident && token.tokenValue in positionIdents ); + } + + function sizeToken( token ) { + return token && ( ( token.isLengthOrPercent() && PIE.getLength( token.tokenValue ) ) || ( token.tokenValue === 'auto' && 'auto' ) ); + } + + // If the CSS3-specific -pie-background property is present, parse it + if( this.getCss3() ) { + tokenizer = new PIE.Tokenizer( css ); + image = {}; + + while( token = tokenizer.next() ) { + tokType = token.tokenType; + tokVal = token.tokenValue; + + if( !image.imgType && tokType & tok_type.FUNCTION && tokVal === 'linear-gradient' ) { + gradient = { stops: [], imgType: tokVal }; + stop = {}; + while( token = tokenizer.next() ) { + tokType = token.tokenType; + tokVal = token.tokenValue; + + // If we reached the end of the function and had at least 2 stops, flush the info + if( tokType & tok_type.CHARACTER && tokVal === ')' ) { + if( stop.color ) { + gradient.stops.push( stop ); + } + if( gradient.stops.length > 1 ) { + PIE.Util.merge( image, gradient ); + } + break; + } + + // Color stop - must start with color + if( tokType & type_color ) { + // if we already have an angle/position, make sure that the previous token was a comma + if( gradient.angle || gradient.gradientStart ) { + token = tokenizer.prev(); + if( token.tokenType !== type_operator ) { + break; //fail + } + tokenizer.next(); + } + + stop = { + color: PIE.getColor( tokVal ) + }; + // check for offset following color + token = tokenizer.next(); + if( token.isLengthOrPercent() ) { + stop.offset = PIE.getLength( token.tokenValue ); + } else { + tokenizer.prev(); + } + } + // Angle - can only appear in first spot + else if( tokType & tok_type.ANGLE && !gradient.angle && !stop.color && !gradient.stops.length ) { + gradient.angle = new PIE.Angle( token.tokenValue ); + } + else if( isBgPosToken( token ) && !gradient.gradientStart && !stop.color && !gradient.stops.length ) { + tokenizer.prev(); + gradient.gradientStart = new PIE.BgPosition( + tokenizer.until( function( t ) { + return !isBgPosToken( t ); + }, false ) + ); + } + else if( tokType & type_operator && tokVal === ',' ) { + if( stop.color ) { + gradient.stops.push( stop ); + stop = {}; + } + } + else { + // Found something we didn't recognize; fail without adding image + break; + } + } + } + else if( !image.imgType && tokType & tok_type.URL ) { + image.imgUrl = tokVal; + image.imgType = 'image'; + } + else if( isBgPosToken( token ) && !image.bgPosition ) { + tokenizer.prev(); + image.bgPosition = new PIE.BgPosition( + tokenizer.until( function( t ) { + return !isBgPosToken( t ); + }, false ) + ); + } + else if( tokType & type_ident ) { + if( tokVal in this.repeatIdents && !image.imgRepeat ) { + image.imgRepeat = tokVal; + } + else if( tokVal in this.originAndClipIdents && !image.bgOrigin ) { + image.bgOrigin = tokVal; + if( ( token = tokenizer.next() ) && ( token.tokenType & type_ident ) && + token.tokenValue in this.originAndClipIdents ) { + image.bgClip = token.tokenValue; + } else { + image.bgClip = tokVal; + tokenizer.prev(); + } + } + else if( tokVal in this.attachIdents && !image.bgAttachment ) { + image.bgAttachment = tokVal; + } + else { + return null; + } + } + else if( tokType & type_color && !props.color ) { + props.color = PIE.getColor( tokVal ); + } + else if( tokType & type_operator && tokVal === '/' && !image.bgSize && image.bgPosition ) { + // background size + token = tokenizer.next(); + if( token.tokenType & type_ident && token.tokenValue in this.sizeIdents ) { + image.bgSize = new PIE.BgSize( token.tokenValue ); + } + else if( width = sizeToken( token ) ) { + height = sizeToken( tokenizer.next() ); + if ( !height ) { + height = width; + tokenizer.prev(); + } + image.bgSize = new PIE.BgSize( width, height ); + } + else { + return null; + } + } + // new layer + else if( tokType & type_operator && tokVal === ',' && image.imgType ) { + image.origString = css.substring( beginCharIndex, tokenizer.ch - 1 ); + beginCharIndex = tokenizer.ch; + props.bgImages.push( image ); + image = {}; + } + else { + // Found something unrecognized; chuck everything + return null; + } + } + + // leftovers + if( image.imgType ) { + image.origString = css.substring( beginCharIndex ); + props.bgImages.push( image ); + } + } + + // Otherwise, use the standard background properties; let IE give us the values rather than parsing them + else { + this.withActualBg( PIE.ieDocMode < 9 ? + function() { + var propNames = this.propertyNames, + posX = cs[propNames.POSITION + 'X'], + posY = cs[propNames.POSITION + 'Y'], + img = cs[propNames.IMAGE], + color = cs[propNames.COLOR]; + + if( color !== 'transparent' ) { + props.color = PIE.getColor( color ) + } + if( img !== 'none' ) { + props.bgImages = [ { + imgType: 'image', + imgUrl: new PIE.Tokenizer( img ).next().tokenValue, + imgRepeat: cs[propNames.REPEAT], + bgPosition: new PIE.BgPosition( new PIE.Tokenizer( posX + ' ' + posY ).all() ) + } ]; + } + } : + function() { + var propNames = this.propertyNames, + splitter = /\s*,\s*/, + images = cs[propNames.IMAGE].split( splitter ), + color = cs[propNames.COLOR], + repeats, positions, origins, clips, sizes, i, len, image, sizeParts; + + if( color !== 'transparent' ) { + props.color = PIE.getColor( color ) + } + + len = images.length; + if( len && images[0] !== 'none' ) { + repeats = cs[propNames.REPEAT].split( splitter ); + positions = cs[propNames.POSITION].split( splitter ); + origins = cs[propNames.ORIGIN].split( splitter ); + clips = cs[propNames.CLIP].split( splitter ); + sizes = cs[propNames.SIZE].split( splitter ); + + props.bgImages = []; + for( i = 0; i < len; i++ ) { + image = images[ i ]; + if( image && image !== 'none' ) { + sizeParts = sizes[i].split( ' ' ); + props.bgImages.push( { + origString: image + ' ' + repeats[ i ] + ' ' + positions[ i ] + ' / ' + sizes[ i ] + ' ' + + origins[ i ] + ' ' + clips[ i ], + imgType: 'image', + imgUrl: new PIE.Tokenizer( image ).next().tokenValue, + imgRepeat: repeats[ i ], + bgPosition: new PIE.BgPosition( new PIE.Tokenizer( positions[ i ] ).all() ), + bgOrigin: origins[ i ], + bgClip: clips[ i ], + bgSize: new PIE.BgSize( sizeParts[ 0 ], sizeParts[ 1 ] ) + } ); + } + } + } + } + ); + } + + return ( props.color || props.bgImages[0] ) ? props : null; + }, + + /** + * Execute a function with the actual background styles (not overridden with runtimeStyle + * properties set by the renderers) available via currentStyle. + * @param fn + */ + withActualBg: function( fn ) { + var isIE9 = PIE.ieDocMode > 8, + propNames = this.propertyNames, + rs = this.targetElement.runtimeStyle, + rsImage = rs[propNames.IMAGE], + rsColor = rs[propNames.COLOR], + rsRepeat = rs[propNames.REPEAT], + rsClip, rsOrigin, rsSize, rsPosition, ret; + + if( rsImage ) rs[propNames.IMAGE] = ''; + if( rsColor ) rs[propNames.COLOR] = ''; + if( rsRepeat ) rs[propNames.REPEAT] = ''; + if( isIE9 ) { + rsClip = rs[propNames.CLIP]; + rsOrigin = rs[propNames.ORIGIN]; + rsPosition = rs[propNames.POSITION]; + rsSize = rs[propNames.SIZE]; + if( rsClip ) rs[propNames.CLIP] = ''; + if( rsOrigin ) rs[propNames.ORIGIN] = ''; + if( rsPosition ) rs[propNames.POSITION] = ''; + if( rsSize ) rs[propNames.SIZE] = ''; + } + + ret = fn.call( this ); + + if( rsImage ) rs[propNames.IMAGE] = rsImage; + if( rsColor ) rs[propNames.COLOR] = rsColor; + if( rsRepeat ) rs[propNames.REPEAT] = rsRepeat; + if( isIE9 ) { + if( rsClip ) rs[propNames.CLIP] = rsClip; + if( rsOrigin ) rs[propNames.ORIGIN] = rsOrigin; + if( rsPosition ) rs[propNames.POSITION] = rsPosition; + if( rsSize ) rs[propNames.SIZE] = rsSize; + } + + return ret; + }, + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + return this.getCss3() || + this.withActualBg( function() { + var cs = this.targetElement.currentStyle, + propNames = this.propertyNames; + return cs[propNames.COLOR] + ' ' + cs[propNames.IMAGE] + ' ' + cs[propNames.REPEAT] + ' ' + + cs[propNames.POSITION + 'X'] + ' ' + cs[propNames.POSITION + 'Y']; + } ); + } ), + + getCss3: PIE.StyleInfoBase.cacheWhenLocked( function() { + var el = this.targetElement; + return el.style[ this.styleProperty ] || el.currentStyle.getAttribute( this.cssProperty ); + } ), + + /** + * Tests if style.PiePngFix or the -pie-png-fix property is set to true in IE6. + */ + isPngFix: function() { + var val = 0, el; + if( PIE.ieVersion < 7 ) { + el = this.targetElement; + val = ( '' + ( el.style[ PIE.STYLE_PREFIX + 'PngFix' ] || el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'png-fix' ) ) === 'true' ); + } + return val; + }, + + /** + * The isActive logic is slightly different, because getProps() always returns an object + * even if it is just falling back to the native background properties. But we only want + * to report is as being "active" if either the -pie-background override property is present + * and parses successfully or '-pie-png-fix' is set to true in IE6. + */ + isActive: PIE.StyleInfoBase.cacheWhenLocked( function() { + return (this.getCss3() || this.isPngFix()) && !!this.getProps(); + } ) + +} );/** + * Handles parsing, caching, and detecting changes to border CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BorderStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + sides: [ 'Top', 'Right', 'Bottom', 'Left' ], + namedWidths: { + 'thin': '1px', + 'medium': '3px', + 'thick': '5px' + }, + + parseCss: function( css ) { + var w = {}, + s = {}, + c = {}, + active = false, + colorsSame = true, + stylesSame = true, + widthsSame = true; + + this.withActualBorder( function() { + var el = this.targetElement, + cs = el.currentStyle, + i = 0, + style, color, width, lastStyle, lastColor, lastWidth, side, ltr; + for( ; i < 4; i++ ) { + side = this.sides[ i ]; + + ltr = side.charAt(0).toLowerCase(); + style = s[ ltr ] = cs[ 'border' + side + 'Style' ]; + color = cs[ 'border' + side + 'Color' ]; + width = cs[ 'border' + side + 'Width' ]; + + if( i > 0 ) { + if( style !== lastStyle ) { stylesSame = false; } + if( color !== lastColor ) { colorsSame = false; } + if( width !== lastWidth ) { widthsSame = false; } + } + lastStyle = style; + lastColor = color; + lastWidth = width; + + c[ ltr ] = PIE.getColor( color ); + + width = w[ ltr ] = PIE.getLength( s[ ltr ] === 'none' ? '0' : ( this.namedWidths[ width ] || width ) ); + if( width.pixels( this.targetElement ) > 0 ) { + active = true; + } + } + } ); + + return active ? { + widths: w, + styles: s, + colors: c, + widthsSame: widthsSame, + colorsSame: colorsSame, + stylesSame: stylesSame + } : null; + }, + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + var el = this.targetElement, + cs = el.currentStyle, + css; + + // Don't redraw or hide borders for cells in border-collapse:collapse tables + if( !( el.tagName in PIE.tableCellTags && el.offsetParent.currentStyle.borderCollapse === 'collapse' ) ) { + this.withActualBorder( function() { + css = cs.borderWidth + '|' + cs.borderStyle + '|' + cs.borderColor; + } ); + } + return css; + } ), + + /** + * Execute a function with the actual border styles (not overridden with runtimeStyle + * properties set by the renderers) available via currentStyle. + * @param fn + */ + withActualBorder: function( fn ) { + var rs = this.targetElement.runtimeStyle, + rsWidth = rs.borderWidth, + rsColor = rs.borderColor, + ret; + + if( rsWidth ) rs.borderWidth = ''; + if( rsColor ) rs.borderColor = ''; + + ret = fn.call( this ); + + if( rsWidth ) rs.borderWidth = rsWidth; + if( rsColor ) rs.borderColor = rsColor; + + return ret; + } + +} ); +/** + * Handles parsing, caching, and detecting changes to border-radius CSS + * @constructor + * @param {Element} el the target element + */ +(function() { + +PIE.BorderRadiusStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'border-radius', + styleProperty: 'borderRadius', + + parseCss: function( css ) { + var p = null, x, y, + tokenizer, token, length, + hasNonZero = false; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + + function collectLengths() { + var arr = [], num; + while( ( token = tokenizer.next() ) && token.isLengthOrPercent() ) { + length = PIE.getLength( token.tokenValue ); + num = length.getNumber(); + if( num < 0 ) { + return null; + } + if( num > 0 ) { + hasNonZero = true; + } + arr.push( length ); + } + return arr.length > 0 && arr.length < 5 ? { + 'tl': arr[0], + 'tr': arr[1] || arr[0], + 'br': arr[2] || arr[0], + 'bl': arr[3] || arr[1] || arr[0] + } : null; + } + + // Grab the initial sequence of lengths + if( x = collectLengths() ) { + // See if there is a slash followed by more lengths, for the y-axis radii + if( token ) { + if( token.tokenType & PIE.Tokenizer.Type.OPERATOR && token.tokenValue === '/' ) { + y = collectLengths(); + } + } else { + y = x; + } + + // Treat all-zero values the same as no value + if( hasNonZero && x && y ) { + p = { x: x, y : y }; + } + } + } + + return p; + } +} ); + +var zero = PIE.getLength( '0' ), + zeros = { 'tl': zero, 'tr': zero, 'br': zero, 'bl': zero }; +PIE.BorderRadiusStyleInfo.ALL_ZERO = { x: zeros, y: zeros }; + +})();/** + * Handles parsing, caching, and detecting changes to border-image CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BorderImageStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'border-image', + styleProperty: 'borderImage', + + repeatIdents: { 'stretch':1, 'round':1, 'repeat':1, 'space':1 }, + + parseCss: function( css ) { + var p = null, tokenizer, token, type, value, + slices, widths, outsets, + slashCount = 0, + Type = PIE.Tokenizer.Type, + IDENT = Type.IDENT, + NUMBER = Type.NUMBER, + PERCENT = Type.PERCENT; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + p = {}; + + function isSlash( token ) { + return token && ( token.tokenType & Type.OPERATOR ) && ( token.tokenValue === '/' ); + } + + function isFillIdent( token ) { + return token && ( token.tokenType & IDENT ) && ( token.tokenValue === 'fill' ); + } + + function collectSlicesEtc() { + slices = tokenizer.until( function( tok ) { + return !( tok.tokenType & ( NUMBER | PERCENT ) ); + } ); + + if( isFillIdent( tokenizer.next() ) && !p.fill ) { + p.fill = true; + } else { + tokenizer.prev(); + } + + if( isSlash( tokenizer.next() ) ) { + slashCount++; + widths = tokenizer.until( function( token ) { + return !token.isLengthOrPercent() && !( ( token.tokenType & IDENT ) && token.tokenValue === 'auto' ); + } ); + + if( isSlash( tokenizer.next() ) ) { + slashCount++; + outsets = tokenizer.until( function( token ) { + return !token.isLength(); + } ); + } + } else { + tokenizer.prev(); + } + } + + while( token = tokenizer.next() ) { + type = token.tokenType; + value = token.tokenValue; + + // Numbers and/or 'fill' keyword: slice values. May be followed optionally by width values, followed optionally by outset values + if( type & ( NUMBER | PERCENT ) && !slices ) { + tokenizer.prev(); + collectSlicesEtc(); + } + else if( isFillIdent( token ) && !p.fill ) { + p.fill = true; + collectSlicesEtc(); + } + + // Idents: one or values for 'repeat' + else if( ( type & IDENT ) && this.repeatIdents[value] && !p.repeat ) { + p.repeat = { h: value }; + if( token = tokenizer.next() ) { + if( ( token.tokenType & IDENT ) && this.repeatIdents[token.tokenValue] ) { + p.repeat.v = token.tokenValue; + } else { + tokenizer.prev(); + } + } + } + + // URL of the image + else if( ( type & Type.URL ) && !p.src ) { + p.src = value; + } + + // Found something unrecognized; exit. + else { + return null; + } + } + + // Validate what we collected + if( !p.src || !slices || slices.length < 1 || slices.length > 4 || + ( widths && widths.length > 4 ) || ( slashCount === 1 && widths.length < 1 ) || + ( outsets && outsets.length > 4 ) || ( slashCount === 2 && outsets.length < 1 ) ) { + return null; + } + + // Fill in missing values + if( !p.repeat ) { + p.repeat = { h: 'stretch' }; + } + if( !p.repeat.v ) { + p.repeat.v = p.repeat.h; + } + + function distributeSides( tokens, convertFn ) { + return { + 't': convertFn( tokens[0] ), + 'r': convertFn( tokens[1] || tokens[0] ), + 'b': convertFn( tokens[2] || tokens[0] ), + 'l': convertFn( tokens[3] || tokens[1] || tokens[0] ) + }; + } + + p.slice = distributeSides( slices, function( tok ) { + return PIE.getLength( ( tok.tokenType & NUMBER ) ? tok.tokenValue + 'px' : tok.tokenValue ); + } ); + + if( widths && widths[0] ) { + p.widths = distributeSides( widths, function( tok ) { + return tok.isLengthOrPercent() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; + } ); + } + + if( outsets && outsets[0] ) { + p.outset = distributeSides( outsets, function( tok ) { + return tok.isLength() ? PIE.getLength( tok.tokenValue ) : tok.tokenValue; + } ); + } + } + + return p; + } + +} );/** + * Handles parsing, caching, and detecting changes to box-shadow CSS + * @constructor + * @param {Element} el the target element + */ +PIE.BoxShadowStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + cssProperty: 'box-shadow', + styleProperty: 'boxShadow', + + parseCss: function( css ) { + var props, + getLength = PIE.getLength, + Type = PIE.Tokenizer.Type, + tokenizer; + + if( css ) { + tokenizer = new PIE.Tokenizer( css ); + props = { outset: [], inset: [] }; + + function parseItem() { + var token, type, value, color, lengths, inset, len; + + while( token = tokenizer.next() ) { + value = token.tokenValue; + type = token.tokenType; + + if( type & Type.OPERATOR && value === ',' ) { + break; + } + else if( token.isLength() && !lengths ) { + tokenizer.prev(); + lengths = tokenizer.until( function( token ) { + return !token.isLength(); + } ); + } + else if( type & Type.COLOR && !color ) { + color = value; + } + else if( type & Type.IDENT && value === 'inset' && !inset ) { + inset = true; + } + else { //encountered an unrecognized token; fail. + return false; + } + } + + len = lengths && lengths.length; + if( len > 1 && len < 5 ) { + ( inset ? props.inset : props.outset ).push( { + xOffset: getLength( lengths[0].tokenValue ), + yOffset: getLength( lengths[1].tokenValue ), + blur: getLength( lengths[2] ? lengths[2].tokenValue : '0' ), + spread: getLength( lengths[3] ? lengths[3].tokenValue : '0' ), + color: PIE.getColor( color || 'currentColor' ) + } ); + return true; + } + return false; + } + + while( parseItem() ) {} + } + + return props && ( props.inset.length || props.outset.length ) ? props : null; + } +} ); +/** + * Retrieves the state of the element's visibility and display + * @constructor + * @param {Element} el the target element + */ +PIE.VisibilityStyleInfo = PIE.StyleInfoBase.newStyleInfo( { + + getCss: PIE.StyleInfoBase.cacheWhenLocked( function() { + var cs = this.targetElement.currentStyle; + return cs.visibility + '|' + cs.display; + } ), + + parseCss: function() { + var el = this.targetElement, + rs = el.runtimeStyle, + cs = el.currentStyle, + rsVis = rs.visibility, + csVis; + + rs.visibility = ''; + csVis = cs.visibility; + rs.visibility = rsVis; + + return { + visible: csVis !== 'hidden', + displayed: cs.display !== 'none' + } + }, + + /** + * Always return false for isActive, since this property alone will not trigger + * a renderer to do anything. + */ + isActive: function() { + return false; + } + +} ); +PIE.RendererBase = { + + /** + * Create a new Renderer class, with the standard constructor, and augmented by + * the RendererBase's members. + * @param proto + */ + newRenderer: function( proto ) { + function Renderer( el, boundsInfo, styleInfos, parent ) { + this.targetElement = el; + this.boundsInfo = boundsInfo; + this.styleInfos = styleInfos; + this.parent = parent; + } + PIE.Util.merge( Renderer.prototype, PIE.RendererBase, proto ); + return Renderer; + }, + + /** + * Flag indicating the element has already been positioned at least once. + * @type {boolean} + */ + isPositioned: false, + + /** + * Determine if the renderer needs to be updated + * @return {boolean} + */ + needsUpdate: function() { + return false; + }, + + /** + * Run any preparation logic that would affect the main update logic of this + * renderer or any of the other renderers, e.g. things that might affect the + * element's size or style properties. + */ + prepareUpdate: PIE.emptyFn, + + /** + * Tell the renderer to update based on modified properties + */ + updateProps: function() { + this.destroy(); + if( this.isActive() ) { + this.draw(); + } + }, + + /** + * Tell the renderer to update based on modified element position + */ + updatePos: function() { + this.isPositioned = true; + }, + + /** + * Tell the renderer to update based on modified element dimensions + */ + updateSize: function() { + if( this.isActive() ) { + this.draw(); + } else { + this.destroy(); + } + }, + + + /** + * Add a layer element, with the given z-order index, to the renderer's main box element. We can't use + * z-index because that breaks when the root rendering box's z-index is 'auto' in IE8+ standards mode. + * So instead we make sure they are inserted into the DOM in the correct order. + * @param {number} index + * @param {Element} el + */ + addLayer: function( index, el ) { + this.removeLayer( index ); + for( var layers = this._layers || ( this._layers = [] ), i = index + 1, len = layers.length, layer; i < len; i++ ) { + layer = layers[i]; + if( layer ) { + break; + } + } + layers[index] = el; + this.getBox().insertBefore( el, layer || null ); + }, + + /** + * Retrieve a layer element by its index, or null if not present + * @param {number} index + * @return {Element} + */ + getLayer: function( index ) { + var layers = this._layers; + return layers && layers[index] || null; + }, + + /** + * Remove a layer element by its index + * @param {number} index + */ + removeLayer: function( index ) { + var layer = this.getLayer( index ), + box = this._box; + if( layer && box ) { + box.removeChild( layer ); + this._layers[index] = null; + } + }, + + + /** + * Get a VML shape by name, creating it if necessary. + * @param {string} name A name identifying the element + * @param {string=} subElName If specified a subelement of the shape will be created with this tag name + * @param {Element} parent The parent element for the shape; will be ignored if 'group' is specified + * @param {number=} group If specified, an ordinal group for the shape. 1 or greater. Groups are rendered + * using container elements in the correct order, to get correct z stacking without z-index. + */ + getShape: function( name, subElName, parent, group ) { + var shapes = this._shapes || ( this._shapes = {} ), + shape = shapes[ name ], + s; + + if( !shape ) { + shape = shapes[ name ] = PIE.Util.createVmlElement( 'shape' ); + if( subElName ) { + shape.appendChild( shape[ subElName ] = PIE.Util.createVmlElement( subElName ) ); + } + + if( group ) { + parent = this.getLayer( group ); + if( !parent ) { + this.addLayer( group, doc.createElement( 'group' + group ) ); + parent = this.getLayer( group ); + } + } + + parent.appendChild( shape ); + + s = shape.style; + s.position = 'absolute'; + s.left = s.top = 0; + s['behavior'] = 'url(#default#VML)'; + } + return shape; + }, + + /** + * Delete a named shape which was created by getShape(). Returns true if a shape with the + * given name was found and deleted, or false if there was no shape of that name. + * @param {string} name + * @return {boolean} + */ + deleteShape: function( name ) { + var shapes = this._shapes, + shape = shapes && shapes[ name ]; + if( shape ) { + shape.parentNode.removeChild( shape ); + delete shapes[ name ]; + } + return !!shape; + }, + + + /** + * For a given set of border radius length/percentage values, convert them to concrete pixel + * values based on the current size of the target element. + * @param {Object} radii + * @return {Object} + */ + getRadiiPixels: function( radii ) { + var el = this.targetElement, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + tlX, tlY, trX, trY, brX, brY, blX, blY, f; + + tlX = radii.x['tl'].pixels( el, w ); + tlY = radii.y['tl'].pixels( el, h ); + trX = radii.x['tr'].pixels( el, w ); + trY = radii.y['tr'].pixels( el, h ); + brX = radii.x['br'].pixels( el, w ); + brY = radii.y['br'].pixels( el, h ); + blX = radii.x['bl'].pixels( el, w ); + blY = radii.y['bl'].pixels( el, h ); + + // If any corner ellipses overlap, reduce them all by the appropriate factor. This formula + // is taken straight from the CSS3 Backgrounds and Borders spec. + f = Math.min( + w / ( tlX + trX ), + h / ( trY + brY ), + w / ( blX + brX ), + h / ( tlY + blY ) + ); + if( f < 1 ) { + tlX *= f; + tlY *= f; + trX *= f; + trY *= f; + brX *= f; + brY *= f; + blX *= f; + blY *= f; + } + + return { + x: { + 'tl': tlX, + 'tr': trX, + 'br': brX, + 'bl': blX + }, + y: { + 'tl': tlY, + 'tr': trY, + 'br': brY, + 'bl': blY + } + } + }, + + /** + * Return the VML path string for the element's background box, with corners rounded. + * @param {Object.<{t:number, r:number, b:number, l:number}>} shrink - if present, specifies number of + * pixels to shrink the box path inward from the element's four sides. + * @param {number=} mult If specified, all coordinates will be multiplied by this number + * @param {Object=} radii If specified, this will be used for the corner radii instead of the properties + * from this renderer's borderRadiusInfo object. + * @return {string} the VML path + */ + getBoxPath: function( shrink, mult, radii ) { + mult = mult || 1; + + var r, str, + bounds = this.boundsInfo.getBounds(), + w = bounds.w * mult, + h = bounds.h * mult, + radInfo = this.styleInfos.borderRadiusInfo, + floor = Math.floor, ceil = Math.ceil, + shrinkT = shrink ? shrink.t * mult : 0, + shrinkR = shrink ? shrink.r * mult : 0, + shrinkB = shrink ? shrink.b * mult : 0, + shrinkL = shrink ? shrink.l * mult : 0, + tlX, tlY, trX, trY, brX, brY, blX, blY; + + if( radii || radInfo.isActive() ) { + r = this.getRadiiPixels( radii || radInfo.getProps() ); + + tlX = r.x['tl'] * mult; + tlY = r.y['tl'] * mult; + trX = r.x['tr'] * mult; + trY = r.y['tr'] * mult; + brX = r.x['br'] * mult; + brY = r.y['br'] * mult; + blX = r.x['bl'] * mult; + blY = r.y['bl'] * mult; + + str = 'm' + floor( shrinkL ) + ',' + floor( tlY ) + + 'qy' + floor( tlX ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - trX ) + ',' + floor( shrinkT ) + + 'qx' + ceil( w - shrinkR ) + ',' + floor( trY ) + + 'l' + ceil( w - shrinkR ) + ',' + ceil( h - brY ) + + 'qy' + ceil( w - brX ) + ',' + ceil( h - shrinkB ) + + 'l' + floor( blX ) + ',' + ceil( h - shrinkB ) + + 'qx' + floor( shrinkL ) + ',' + ceil( h - blY ) + ' x e'; + } else { + // simplified path for non-rounded box + str = 'm' + floor( shrinkL ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - shrinkR ) + ',' + floor( shrinkT ) + + 'l' + ceil( w - shrinkR ) + ',' + ceil( h - shrinkB ) + + 'l' + floor( shrinkL ) + ',' + ceil( h - shrinkB ) + + 'xe'; + } + return str; + }, + + + /** + * Get the container element for the shapes, creating it if necessary. + */ + getBox: function() { + var box = this.parent.getLayer( this.boxZIndex ), s; + + if( !box ) { + box = doc.createElement( this.boxName ); + s = box.style; + s.position = 'absolute'; + s.top = s.left = 0; + this.parent.addLayer( this.boxZIndex, box ); + } + + return box; + }, + + + /** + * Hide the actual border of the element. In IE7 and up we can just set its color to transparent; + * however IE6 does not support transparent borders so we have to get tricky with it. Also, some elements + * like form buttons require removing the border width altogether, so for those we increase the padding + * by the border size. + */ + hideBorder: function() { + var el = this.targetElement, + cs = el.currentStyle, + rs = el.runtimeStyle, + tag = el.tagName, + isIE6 = PIE.ieVersion === 6, + sides, side, i; + + if( ( isIE6 && ( tag in PIE.childlessElements || tag === 'FIELDSET' ) ) || + tag === 'BUTTON' || ( tag === 'INPUT' && el.type in PIE.inputButtonTypes ) ) { + rs.borderWidth = ''; + sides = this.styleInfos.borderInfo.sides; + for( i = sides.length; i--; ) { + side = sides[ i ]; + rs[ 'padding' + side ] = ''; + rs[ 'padding' + side ] = ( PIE.getLength( cs[ 'padding' + side ] ) ).pixels( el ) + + ( PIE.getLength( cs[ 'border' + side + 'Width' ] ) ).pixels( el ) + + ( PIE.ieVersion !== 8 && i % 2 ? 1 : 0 ); //needs an extra horizontal pixel to counteract the extra "inner border" going away + } + rs.borderWidth = 0; + } + else if( isIE6 ) { + // Wrap all the element's children in a custom element, set the element to visiblity:hidden, + // and set the wrapper element to visiblity:visible. This hides the outer element's decorations + // (background and border) but displays all the contents. + // TODO find a better way to do this that doesn't mess up the DOM parent-child relationship, + // as this can interfere with other author scripts which add/modify/delete children. Also, this + // won't work for elements which cannot take children, e.g. input/button/textarea/img/etc. Look into + // using a compositor filter or some other filter which masks the border. + if( el.childNodes.length !== 1 || el.firstChild.tagName !== 'ie6-mask' ) { + var cont = doc.createElement( 'ie6-mask' ), + s = cont.style, child; + s.visibility = 'visible'; + s.zoom = 1; + while( child = el.firstChild ) { + cont.appendChild( child ); + } + el.appendChild( cont ); + rs.visibility = 'hidden'; + } + } + else { + rs.borderColor = 'transparent'; + } + }, + + unhideBorder: function() { + + }, + + + /** + * Destroy the rendered objects. This is a base implementation which handles common renderer + * structures, but individual renderers may override as necessary. + */ + destroy: function() { + this.parent.removeLayer( this.boxZIndex ); + delete this._shapes; + delete this._layers; + } +}; +/** + * Root renderer; creates the outermost container element and handles keeping it aligned + * with the target element's size and position. + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.RootRenderer = PIE.RendererBase.newRenderer( { + + isActive: function() { + var children = this.childRenderers; + for( var i in children ) { + if( children.hasOwnProperty( i ) && children[ i ].isActive() ) { + return true; + } + } + return false; + }, + + needsUpdate: function() { + return this.styleInfos.visibilityInfo.changed(); + }, + + updatePos: function() { + if( this.isActive() ) { + var el = this.getPositioningElement(), + par = el, + docEl, + parRect, + tgtCS = el.currentStyle, + tgtPos = tgtCS.position, + boxPos, + s = this.getBox().style, cs, + x = 0, y = 0, + elBounds = this.boundsInfo.getBounds(), + logicalZoomRatio = elBounds.logicalZoomRatio; + + if( tgtPos === 'fixed' && PIE.ieVersion > 6 ) { + x = elBounds.x * logicalZoomRatio; + y = elBounds.y * logicalZoomRatio; + boxPos = tgtPos; + } else { + // Get the element's offsets from its nearest positioned ancestor. Uses + // getBoundingClientRect for accuracy and speed. + do { + par = par.offsetParent; + } while( par && ( par.currentStyle.position === 'static' ) ); + if( par ) { + parRect = par.getBoundingClientRect(); + cs = par.currentStyle; + x = ( elBounds.x - parRect.left ) * logicalZoomRatio - ( parseFloat(cs.borderLeftWidth) || 0 ); + y = ( elBounds.y - parRect.top ) * logicalZoomRatio - ( parseFloat(cs.borderTopWidth) || 0 ); + } else { + docEl = doc.documentElement; + x = ( elBounds.x + docEl.scrollLeft - docEl.clientLeft ) * logicalZoomRatio; + y = ( elBounds.y + docEl.scrollTop - docEl.clientTop ) * logicalZoomRatio; + } + boxPos = 'absolute'; + } + + s.position = boxPos; + s.left = x; + s.top = y; + s.zIndex = tgtPos === 'static' ? -1 : tgtCS.zIndex; + this.isPositioned = true; + } + }, + + updateSize: PIE.emptyFn, + + updateVisibility: function() { + var vis = this.styleInfos.visibilityInfo.getProps(); + this.getBox().style.display = ( vis.visible && vis.displayed ) ? '' : 'none'; + }, + + updateProps: function() { + if( this.isActive() ) { + this.updateVisibility(); + } else { + this.destroy(); + } + }, + + getPositioningElement: function() { + var el = this.targetElement; + return el.tagName in PIE.tableCellTags ? el.offsetParent : el; + }, + + getBox: function() { + var box = this._box, el; + if( !box ) { + el = this.getPositioningElement(); + box = this._box = doc.createElement( 'css3-container' ); + box.style['direction'] = 'ltr'; //fix positioning bug in rtl environments + + this.updateVisibility(); + + el.parentNode.insertBefore( box, el ); + } + return box; + }, + + finishUpdate: PIE.emptyFn, + + destroy: function() { + var box = this._box, par; + if( box && ( par = box.parentNode ) ) { + par.removeChild( box ); + } + delete this._box; + delete this._layers; + } + +} ); +/** + * Renderer for element backgrounds. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BackgroundRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 2, + boxName: 'background', + + needsUpdate: function() { + var si = this.styleInfos; + return si.backgroundInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderImageInfo.isActive() || + si.borderRadiusInfo.isActive() || + si.backgroundInfo.isActive() || + ( si.boxShadowInfo.isActive() && si.boxShadowInfo.getProps().inset ); + }, + + /** + * Draw the shapes + */ + draw: function() { + var bounds = this.boundsInfo.getBounds(); + if( bounds.w && bounds.h ) { + this.drawBgColor(); + this.drawBgImages(); + } + }, + + /** + * Draw the background color shape + */ + drawBgColor: function() { + var props = this.styleInfos.backgroundInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + el = this.targetElement, + color = props && props.color, + shape, w, h, s, alpha; + + if( color && color.alpha() > 0 ) { + this.hideBackground(); + + shape = this.getShape( 'bgColor', 'fill', this.getBox(), 1 ); + w = bounds.w; + h = bounds.h; + shape.stroked = false; + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( null, 2 ); + s = shape.style; + s.width = w; + s.height = h; + shape.fill.color = color.colorValue( el ); + + alpha = color.alpha(); + if( alpha < 1 ) { + shape.fill.opacity = alpha; + } + } else { + this.deleteShape( 'bgColor' ); + } + }, + + /** + * Draw all the background image layers + */ + drawBgImages: function() { + var props = this.styleInfos.backgroundInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + images = props && props.bgImages, + img, shape, w, h, s, i; + + if( images ) { + this.hideBackground(); + + w = bounds.w; + h = bounds.h; + + i = images.length; + while( i-- ) { + img = images[i]; + shape = this.getShape( 'bgImage' + i, 'fill', this.getBox(), 2 ); + + shape.stroked = false; + shape.fill.type = 'tile'; + shape.fillcolor = 'none'; + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( 0, 2 ); + s = shape.style; + s.width = w; + s.height = h; + + if( img.imgType === 'linear-gradient' ) { + this.addLinearGradient( shape, img ); + } + else { + shape.fill.src = img.imgUrl; + this.positionBgImage( shape, i ); + } + } + } + + // Delete any bgImage shapes previously created which weren't used above + i = images ? images.length : 0; + while( this.deleteShape( 'bgImage' + i++ ) ) {} + }, + + + /** + * Set the position and clipping of the background image for a layer + * @param {Element} shape + * @param {number} index + */ + positionBgImage: function( shape, index ) { + var me = this; + PIE.Util.withImageSize( shape.fill.src, function( size ) { + var el = me.targetElement, + bounds = me.boundsInfo.getBounds(), + elW = bounds.w, + elH = bounds.h; + + // It's possible that the element dimensions are zero now but weren't when the original + // update executed, make sure that's not the case to avoid divide-by-zero error + if( elW && elH ) { + var fill = shape.fill, + si = me.styleInfos, + border = si.borderInfo.getProps(), + bw = border && border.widths, + bwT = bw ? bw['t'].pixels( el ) : 0, + bwR = bw ? bw['r'].pixels( el ) : 0, + bwB = bw ? bw['b'].pixels( el ) : 0, + bwL = bw ? bw['l'].pixels( el ) : 0, + bg = si.backgroundInfo.getProps().bgImages[ index ], + bgPos = bg.bgPosition ? bg.bgPosition.coords( el, elW - size.w - bwL - bwR, elH - size.h - bwT - bwB ) : { x:0, y:0 }, + repeat = bg.imgRepeat, + pxX, pxY, + clipT = 0, clipL = 0, + clipR = elW + 1, clipB = elH + 1, //make sure the default clip region is not inside the box (by a subpixel) + clipAdjust = PIE.ieVersion === 8 ? 0 : 1; //prior to IE8 requires 1 extra pixel in the image clip region + + // Positioning - find the pixel offset from the top/left and convert to a ratio + // The position is shifted by half a pixel, to adjust for the half-pixel coordorigin shift which is + // needed to fix antialiasing but makes the bg image fuzzy. + pxX = Math.round( bgPos.x ) + bwL + 0.5; + pxY = Math.round( bgPos.y ) + bwT + 0.5; + fill.position = ( pxX / elW ) + ',' + ( pxY / elH ); + + // Set the size of the image. We have to actually set it to px values otherwise it will not honor + // the user's browser zoom level and always display at its natural screen size. + fill['size']['x'] = 1; //Can be any value, just has to be set to "prime" it so the next line works. Weird! + fill['size'] = size.w + 'px,' + size.h + 'px'; + + // Repeating - clip the image shape + if( repeat && repeat !== 'repeat' ) { + if( repeat === 'repeat-x' || repeat === 'no-repeat' ) { + clipT = pxY + 1; + clipB = pxY + size.h + clipAdjust; + } + if( repeat === 'repeat-y' || repeat === 'no-repeat' ) { + clipL = pxX + 1; + clipR = pxX + size.w + clipAdjust; + } + shape.style.clip = 'rect(' + clipT + 'px,' + clipR + 'px,' + clipB + 'px,' + clipL + 'px)'; + } + } + } ); + }, + + + /** + * Draw the linear gradient for a gradient layer + * @param {Element} shape + * @param {Object} info The object holding the information about the gradient + */ + addLinearGradient: function( shape, info ) { + var el = this.targetElement, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + fill = shape.fill, + stops = info.stops, + stopCount = stops.length, + PI = Math.PI, + GradientUtil = PIE.GradientUtil, + perpendicularIntersect = GradientUtil.perpendicularIntersect, + distance = GradientUtil.distance, + metrics = GradientUtil.getGradientMetrics( el, w, h, info ), + angle = metrics.angle, + startX = metrics.startX, + startY = metrics.startY, + startCornerX = metrics.startCornerX, + startCornerY = metrics.startCornerY, + endCornerX = metrics.endCornerX, + endCornerY = metrics.endCornerY, + deltaX = metrics.deltaX, + deltaY = metrics.deltaY, + lineLength = metrics.lineLength, + vmlAngle, vmlGradientLength, vmlColors, + stopPx, vmlOffsetPct, + p, i, j, before, after; + + // In VML land, the angle of the rendered gradient depends on the aspect ratio of the shape's + // bounding box; for example specifying a 45 deg angle actually results in a gradient + // drawn diagonally from one corner to its opposite corner, which will only appear to the + // viewer as 45 degrees if the shape is equilateral. We adjust for this by taking the x/y deltas + // between the start and end points, multiply one of them by the shape's aspect ratio, + // and get their arctangent, resulting in an appropriate VML angle. If the angle is perfectly + // horizontal or vertical then we don't need to do this conversion. + vmlAngle = ( angle % 90 ) ? Math.atan2( deltaX * w / h, deltaY ) / PI * 180 : ( angle + 90 ); + + // VML angles are 180 degrees offset from CSS angles + vmlAngle += 180; + vmlAngle = vmlAngle % 360; + + // Add all the stops to the VML 'colors' list, including the first and last stops. + // For each, we find its pixel offset along the gradient-line; if the offset of a stop is less + // than that of its predecessor we increase it to be equal. We then map that pixel offset to a + // percentage along the VML gradient-line, which runs from shape corner to corner. + p = perpendicularIntersect( startCornerX, startCornerY, angle, endCornerX, endCornerY ); + vmlGradientLength = distance( startCornerX, startCornerY, p[0], p[1] ); + vmlColors = []; + p = perpendicularIntersect( startX, startY, angle, startCornerX, startCornerY ); + vmlOffsetPct = distance( startX, startY, p[0], p[1] ) / vmlGradientLength * 100; + + // Find the pixel offsets along the CSS3 gradient-line for each stop. + stopPx = []; + for( i = 0; i < stopCount; i++ ) { + stopPx.push( stops[i].offset ? stops[i].offset.pixels( el, lineLength ) : + i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); + } + // Fill in gaps with evenly-spaced offsets + for( i = 1; i < stopCount; i++ ) { + if( stopPx[ i ] === null ) { + before = stopPx[ i - 1 ]; + j = i; + do { + after = stopPx[ ++j ]; + } while( after === null ); + stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); + } + // Make sure each stop's offset is no less than the one before it + stopPx[ i ] = Math.max( stopPx[ i ], stopPx[ i - 1 ] ); + } + + // Convert to percentage along the VML gradient line and add to the VML 'colors' value + for( i = 0; i < stopCount; i++ ) { + vmlColors.push( + ( vmlOffsetPct + ( stopPx[ i ] / vmlGradientLength * 100 ) ) + '% ' + stops[i].color.colorValue( el ) + ); + } + + // Now, finally, we're ready to render the gradient fill. Set the start and end colors to + // the first and last stop colors; this just sets outer bounds for the gradient. + fill['angle'] = vmlAngle; + fill['type'] = 'gradient'; + fill['method'] = 'sigma'; + fill['color'] = stops[0].color.colorValue( el ); + fill['color2'] = stops[stopCount - 1].color.colorValue( el ); + if( fill['colors'] ) { //sometimes the colors object isn't initialized so we have to assign it directly (?) + fill['colors'].value = vmlColors.join( ',' ); + } else { + fill['colors'] = vmlColors.join( ',' ); + } + }, + + + /** + * Hide the actual background image and color of the element. + */ + hideBackground: function() { + var rs = this.targetElement.runtimeStyle; + rs.backgroundImage = 'url(about:blank)'; //ensures the background area reacts to mouse events + rs.backgroundColor = 'transparent'; + }, + + destroy: function() { + PIE.RendererBase.destroy.call( this ); + var rs = this.targetElement.runtimeStyle; + rs.backgroundImage = rs.backgroundColor = ''; + } + +} ); +/** + * Renderer for element borders. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BorderRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 4, + boxName: 'border', + + needsUpdate: function() { + var si = this.styleInfos; + return si.borderInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderRadiusInfo.isActive() && + !si.borderImageInfo.isActive() && + si.borderInfo.isActive(); //check BorderStyleInfo last because it's the most expensive + }, + + /** + * Draw the border shape(s) + */ + draw: function() { + var el = this.targetElement, + props = this.styleInfos.borderInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + shape, stroke, s, + segments, seg, i, len; + + if( props ) { + this.hideBorder(); + + segments = this.getBorderSegments( 2 ); + for( i = 0, len = segments.length; i < len; i++) { + seg = segments[i]; + shape = this.getShape( 'borderPiece' + i, seg.stroke ? 'stroke' : 'fill', this.getBox() ); + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = seg.path; + s = shape.style; + s.width = w; + s.height = h; + + shape.filled = !!seg.fill; + shape.stroked = !!seg.stroke; + if( seg.stroke ) { + stroke = shape.stroke; + stroke['weight'] = seg.weight + 'px'; + stroke.color = seg.color.colorValue( el ); + stroke['dashstyle'] = seg.stroke === 'dashed' ? '2 2' : seg.stroke === 'dotted' ? '1 1' : 'solid'; + stroke['linestyle'] = seg.stroke === 'double' && seg.weight > 2 ? 'ThinThin' : 'Single'; + } else { + shape.fill.color = seg.fill.colorValue( el ); + } + } + + // remove any previously-created border shapes which didn't get used above + while( this.deleteShape( 'borderPiece' + i++ ) ) {} + } + }, + + + /** + * Get the VML path definitions for the border segment(s). + * @param {number=} mult If specified, all coordinates will be multiplied by this number + * @return {Array.<string>} + */ + getBorderSegments: function( mult ) { + var el = this.targetElement, + bounds, elW, elH, + borderInfo = this.styleInfos.borderInfo, + segments = [], + floor, ceil, wT, wR, wB, wL, + round = Math.round, + borderProps, radiusInfo, radii, widths, styles, colors; + + if( borderInfo.isActive() ) { + borderProps = borderInfo.getProps(); + + widths = borderProps.widths; + styles = borderProps.styles; + colors = borderProps.colors; + + if( borderProps.widthsSame && borderProps.stylesSame && borderProps.colorsSame ) { + if( colors['t'].alpha() > 0 ) { + // shortcut for identical border on all sides - only need 1 stroked shape + wT = widths['t'].pixels( el ); //thickness + wR = wT / 2; //shrink + segments.push( { + path: this.getBoxPath( { t: wR, r: wR, b: wR, l: wR }, mult ), + stroke: styles['t'], + color: colors['t'], + weight: wT + } ); + } + } + else { + mult = mult || 1; + bounds = this.boundsInfo.getBounds(); + elW = bounds.w; + elH = bounds.h; + + wT = round( widths['t'].pixels( el ) ); + wR = round( widths['r'].pixels( el ) ); + wB = round( widths['b'].pixels( el ) ); + wL = round( widths['l'].pixels( el ) ); + var pxWidths = { + 't': wT, + 'r': wR, + 'b': wB, + 'l': wL + }; + + radiusInfo = this.styleInfos.borderRadiusInfo; + if( radiusInfo.isActive() ) { + radii = this.getRadiiPixels( radiusInfo.getProps() ); + } + + floor = Math.floor; + ceil = Math.ceil; + + function radius( xy, corner ) { + return radii ? radii[ xy ][ corner ] : 0; + } + + function curve( corner, shrinkX, shrinkY, startAngle, ccw, doMove ) { + var rx = radius( 'x', corner), + ry = radius( 'y', corner), + deg = 65535, + isRight = corner.charAt( 1 ) === 'r', + isBottom = corner.charAt( 0 ) === 'b'; + return ( rx > 0 && ry > 0 ) ? + ( doMove ? 'al' : 'ae' ) + + ( isRight ? ceil( elW - rx ) : floor( rx ) ) * mult + ',' + // center x + ( isBottom ? ceil( elH - ry ) : floor( ry ) ) * mult + ',' + // center y + ( floor( rx ) - shrinkX ) * mult + ',' + // width + ( floor( ry ) - shrinkY ) * mult + ',' + // height + ( startAngle * deg ) + ',' + // start angle + ( 45 * deg * ( ccw ? 1 : -1 ) // angle change + ) : ( + ( doMove ? 'm' : 'l' ) + + ( isRight ? elW - shrinkX : shrinkX ) * mult + ',' + + ( isBottom ? elH - shrinkY : shrinkY ) * mult + ); + } + + function line( side, shrink, ccw, doMove ) { + var + start = ( + side === 't' ? + floor( radius( 'x', 'tl') ) * mult + ',' + ceil( shrink ) * mult : + side === 'r' ? + ceil( elW - shrink ) * mult + ',' + floor( radius( 'y', 'tr') ) * mult : + side === 'b' ? + ceil( elW - radius( 'x', 'br') ) * mult + ',' + floor( elH - shrink ) * mult : + // side === 'l' ? + floor( shrink ) * mult + ',' + ceil( elH - radius( 'y', 'bl') ) * mult + ), + end = ( + side === 't' ? + ceil( elW - radius( 'x', 'tr') ) * mult + ',' + ceil( shrink ) * mult : + side === 'r' ? + ceil( elW - shrink ) * mult + ',' + ceil( elH - radius( 'y', 'br') ) * mult : + side === 'b' ? + floor( radius( 'x', 'bl') ) * mult + ',' + floor( elH - shrink ) * mult : + // side === 'l' ? + floor( shrink ) * mult + ',' + floor( radius( 'y', 'tl') ) * mult + ); + return ccw ? ( doMove ? 'm' + end : '' ) + 'l' + start : + ( doMove ? 'm' + start : '' ) + 'l' + end; + } + + + function addSide( side, sideBefore, sideAfter, cornerBefore, cornerAfter, baseAngle ) { + var vert = side === 'l' || side === 'r', + sideW = pxWidths[ side ], + beforeX, beforeY, afterX, afterY; + + if( sideW > 0 && styles[ side ] !== 'none' && colors[ side ].alpha() > 0 ) { + beforeX = pxWidths[ vert ? side : sideBefore ]; + beforeY = pxWidths[ vert ? sideBefore : side ]; + afterX = pxWidths[ vert ? side : sideAfter ]; + afterY = pxWidths[ vert ? sideAfter : side ]; + + if( styles[ side ] === 'dashed' || styles[ side ] === 'dotted' ) { + segments.push( { + path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + + curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), + fill: colors[ side ] + } ); + segments.push( { + path: line( side, sideW / 2, 0, 1 ), + stroke: styles[ side ], + weight: sideW, + color: colors[ side ] + } ); + segments.push( { + path: curve( cornerAfter, afterX, afterY, baseAngle, 0, 1 ) + + curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ), + fill: colors[ side ] + } ); + } + else { + segments.push( { + path: curve( cornerBefore, beforeX, beforeY, baseAngle + 45, 0, 1 ) + + line( side, sideW, 0, 0 ) + + curve( cornerAfter, afterX, afterY, baseAngle, 0, 0 ) + + + ( styles[ side ] === 'double' && sideW > 2 ? + curve( cornerAfter, afterX - floor( afterX / 3 ), afterY - floor( afterY / 3 ), baseAngle - 45, 1, 0 ) + + line( side, ceil( sideW / 3 * 2 ), 1, 0 ) + + curve( cornerBefore, beforeX - floor( beforeX / 3 ), beforeY - floor( beforeY / 3 ), baseAngle, 1, 0 ) + + 'x ' + + curve( cornerBefore, floor( beforeX / 3 ), floor( beforeY / 3 ), baseAngle + 45, 0, 1 ) + + line( side, floor( sideW / 3 ), 1, 0 ) + + curve( cornerAfter, floor( afterX / 3 ), floor( afterY / 3 ), baseAngle, 0, 0 ) + : '' ) + + + curve( cornerAfter, 0, 0, baseAngle - 45, 1, 0 ) + + line( side, 0, 1, 0 ) + + curve( cornerBefore, 0, 0, baseAngle, 1, 0 ), + fill: colors[ side ] + } ); + } + } + } + + addSide( 't', 'l', 'r', 'tl', 'tr', 90 ); + addSide( 'r', 't', 'b', 'tr', 'br', 0 ); + addSide( 'b', 'r', 'l', 'br', 'bl', -90 ); + addSide( 'l', 'b', 't', 'bl', 'tl', -180 ); + } + } + + return segments; + }, + + destroy: function() { + var me = this; + if (me.finalized || !me.styleInfos.borderImageInfo.isActive()) { + me.targetElement.runtimeStyle.borderColor = ''; + } + PIE.RendererBase.destroy.call( me ); + } + + +} ); +/** + * Renderer for border-image + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BorderImageRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 5, + pieceNames: [ 't', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl', 'c' ], + + needsUpdate: function() { + return this.styleInfos.borderImageInfo.changed(); + }, + + isActive: function() { + return this.styleInfos.borderImageInfo.isActive(); + }, + + draw: function() { + this.getBox(); //make sure pieces are created + + var props = this.styleInfos.borderImageInfo.getProps(), + borderProps = this.styleInfos.borderInfo.getProps(), + bounds = this.boundsInfo.getBounds(), + el = this.targetElement, + pieces = this.pieces; + + PIE.Util.withImageSize( props.src, function( imgSize ) { + var elW = bounds.w, + elH = bounds.h, + zero = PIE.getLength( '0' ), + widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), + widthT = widths['t'].pixels( el ), + widthR = widths['r'].pixels( el ), + widthB = widths['b'].pixels( el ), + widthL = widths['l'].pixels( el ), + slices = props.slice, + sliceT = slices['t'].pixels( el ), + sliceR = slices['r'].pixels( el ), + sliceB = slices['b'].pixels( el ), + sliceL = slices['l'].pixels( el ); + + // Piece positions and sizes + function setSizeAndPos( piece, w, h, x, y ) { + var s = pieces[piece].style, + max = Math.max; + s.width = max(w, 0); + s.height = max(h, 0); + s.left = x; + s.top = y; + } + setSizeAndPos( 'tl', widthL, widthT, 0, 0 ); + setSizeAndPos( 't', elW - widthL - widthR, widthT, widthL, 0 ); + setSizeAndPos( 'tr', widthR, widthT, elW - widthR, 0 ); + setSizeAndPos( 'r', widthR, elH - widthT - widthB, elW - widthR, widthT ); + setSizeAndPos( 'br', widthR, widthB, elW - widthR, elH - widthB ); + setSizeAndPos( 'b', elW - widthL - widthR, widthB, widthL, elH - widthB ); + setSizeAndPos( 'bl', widthL, widthB, 0, elH - widthB ); + setSizeAndPos( 'l', widthL, elH - widthT - widthB, 0, widthT ); + setSizeAndPos( 'c', elW - widthL - widthR, elH - widthT - widthB, widthL, widthT ); + + + // image croppings + function setCrops( sides, crop, val ) { + for( var i=0, len=sides.length; i < len; i++ ) { + pieces[ sides[i] ]['imagedata'][ crop ] = val; + } + } + + // corners + setCrops( [ 'tl', 't', 'tr' ], 'cropBottom', ( imgSize.h - sliceT ) / imgSize.h ); + setCrops( [ 'tl', 'l', 'bl' ], 'cropRight', ( imgSize.w - sliceL ) / imgSize.w ); + setCrops( [ 'bl', 'b', 'br' ], 'cropTop', ( imgSize.h - sliceB ) / imgSize.h ); + setCrops( [ 'tr', 'r', 'br' ], 'cropLeft', ( imgSize.w - sliceR ) / imgSize.w ); + + // edges and center + // TODO right now this treats everything like 'stretch', need to support other schemes + //if( props.repeat.v === 'stretch' ) { + setCrops( [ 'l', 'r', 'c' ], 'cropTop', sliceT / imgSize.h ); + setCrops( [ 'l', 'r', 'c' ], 'cropBottom', sliceB / imgSize.h ); + //} + //if( props.repeat.h === 'stretch' ) { + setCrops( [ 't', 'b', 'c' ], 'cropLeft', sliceL / imgSize.w ); + setCrops( [ 't', 'b', 'c' ], 'cropRight', sliceR / imgSize.w ); + //} + + // center fill + pieces['c'].style.display = props.fill ? '' : 'none'; + }, this ); + }, + + getBox: function() { + var box = this.parent.getLayer( this.boxZIndex ), + s, piece, i, + pieceNames = this.pieceNames, + len = pieceNames.length; + + if( !box ) { + box = doc.createElement( 'border-image' ); + s = box.style; + s.position = 'absolute'; + + this.pieces = {}; + + for( i = 0; i < len; i++ ) { + piece = this.pieces[ pieceNames[i] ] = PIE.Util.createVmlElement( 'rect' ); + piece.appendChild( PIE.Util.createVmlElement( 'imagedata' ) ); + s = piece.style; + s['behavior'] = 'url(#default#VML)'; + s.position = "absolute"; + s.top = s.left = 0; + piece['imagedata'].src = this.styleInfos.borderImageInfo.getProps().src; + piece.stroked = false; + piece.filled = false; + box.appendChild( piece ); + } + + this.parent.addLayer( this.boxZIndex, box ); + } + + return box; + }, + + prepareUpdate: function() { + if (this.isActive()) { + var me = this, + el = me.targetElement, + rs = el.runtimeStyle, + widths = me.styleInfos.borderImageInfo.getProps().widths; + + // Force border-style to solid so it doesn't collapse + rs.borderStyle = 'solid'; + + // If widths specified in border-image shorthand, override border-width + // NOTE px units needed here as this gets used by the IE9 renderer too + if ( widths ) { + rs.borderTopWidth = widths['t'].pixels( el ) + 'px'; + rs.borderRightWidth = widths['r'].pixels( el ) + 'px'; + rs.borderBottomWidth = widths['b'].pixels( el ) + 'px'; + rs.borderLeftWidth = widths['l'].pixels( el ) + 'px'; + } + + // Make the border transparent + me.hideBorder(); + } + }, + + destroy: function() { + var me = this, + rs = me.targetElement.runtimeStyle; + rs.borderStyle = ''; + if (me.finalized || !me.styleInfos.borderInfo.isActive()) { + rs.borderColor = rs.borderWidth = ''; + } + PIE.RendererBase.destroy.call( this ); + } + +} ); +/** + * Renderer for outset box-shadows + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.BoxShadowOutsetRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 1, + boxName: 'outset-box-shadow', + + needsUpdate: function() { + var si = this.styleInfos; + return si.boxShadowInfo.changed() || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var boxShadowInfo = this.styleInfos.boxShadowInfo; + return boxShadowInfo.isActive() && boxShadowInfo.getProps().outset[0]; + }, + + draw: function() { + var me = this, + el = this.targetElement, + box = this.getBox(), + styleInfos = this.styleInfos, + shadowInfos = styleInfos.boxShadowInfo.getProps().outset, + radii = styleInfos.borderRadiusInfo.getProps(), + len = shadowInfos.length, + i = len, j, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + clipAdjust = PIE.ieVersion === 8 ? 1 : 0, //workaround for IE8 bug where VML leaks out top/left of clip region by 1px + corners = [ 'tl', 'tr', 'br', 'bl' ], corner, + shadowInfo, shape, fill, ss, xOff, yOff, spread, blur, shrink, color, alpha, path, + totalW, totalH, focusX, focusY, isBottom, isRight; + + + function getShadowShape( index, corner, xOff, yOff, color, blur, path ) { + var shape = me.getShape( 'shadow' + index + corner, 'fill', box, len - index ), + fill = shape.fill; + + // Position and size + shape['coordsize'] = w * 2 + ',' + h * 2; + shape['coordorigin'] = '1,1'; + + // Color and opacity + shape['stroked'] = false; + shape['filled'] = true; + fill.color = color.colorValue( el ); + if( blur ) { + fill['type'] = 'gradienttitle'; //makes the VML gradient follow the shape's outline - hooray for undocumented features?!?! + fill['color2'] = fill.color; + fill['opacity'] = 0; + } + + // Path + shape.path = path; + + // This needs to go last for some reason, to prevent rendering at incorrect size + ss = shape.style; + ss.left = xOff; + ss.top = yOff; + ss.width = w; + ss.height = h; + + return shape; + } + + + while( i-- ) { + shadowInfo = shadowInfos[ i ]; + xOff = shadowInfo.xOffset.pixels( el ); + yOff = shadowInfo.yOffset.pixels( el ); + spread = shadowInfo.spread.pixels( el ); + blur = shadowInfo.blur.pixels( el ); + color = shadowInfo.color; + // Shape path + shrink = -spread - blur; + if( !radii && blur ) { + // If blurring, use a non-null border radius info object so that getBoxPath will + // round the corners of the expanded shadow shape rather than squaring them off. + radii = PIE.BorderRadiusStyleInfo.ALL_ZERO; + } + path = this.getBoxPath( { t: shrink, r: shrink, b: shrink, l: shrink }, 2, radii ); + + if( blur ) { + totalW = ( spread + blur ) * 2 + w; + totalH = ( spread + blur ) * 2 + h; + focusX = totalW ? blur * 2 / totalW : 0; + focusY = totalH ? blur * 2 / totalH : 0; + if( blur - spread > w / 2 || blur - spread > h / 2 ) { + // If the blur is larger than half the element's narrowest dimension, we cannot do + // this with a single shape gradient, because its focussize would have to be less than + // zero which results in ugly artifacts. Instead we create four shapes, each with its + // gradient focus past center, and then clip them so each only shows the quadrant + // opposite the focus. + for( j = 4; j--; ) { + corner = corners[j]; + isBottom = corner.charAt( 0 ) === 'b'; + isRight = corner.charAt( 1 ) === 'r'; + shape = getShadowShape( i, corner, xOff, yOff, color, blur, path ); + fill = shape.fill; + fill['focusposition'] = ( isRight ? 1 - focusX : focusX ) + ',' + + ( isBottom ? 1 - focusY : focusY ); + fill['focussize'] = '0,0'; + + // Clip to show only the appropriate quadrant. Add 1px to the top/left clip values + // in IE8 to prevent a bug where IE8 displays one pixel outside the clip region. + shape.style.clip = 'rect(' + ( ( isBottom ? totalH / 2 : 0 ) + clipAdjust ) + 'px,' + + ( isRight ? totalW : totalW / 2 ) + 'px,' + + ( isBottom ? totalH : totalH / 2 ) + 'px,' + + ( ( isRight ? totalW / 2 : 0 ) + clipAdjust ) + 'px)'; + } + } else { + // TODO delete old quadrant shapes if resizing expands past the barrier + shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); + fill = shape.fill; + fill['focusposition'] = focusX + ',' + focusY; + fill['focussize'] = ( 1 - focusX * 2 ) + ',' + ( 1 - focusY * 2 ); + } + } else { + shape = getShadowShape( i, '', xOff, yOff, color, blur, path ); + alpha = color.alpha(); + if( alpha < 1 ) { + // shape.style.filter = 'alpha(opacity=' + ( alpha * 100 ) + ')'; + // ss.filter = 'progid:DXImageTransform.Microsoft.BasicImage(opacity=' + ( alpha ) + ')'; + shape.fill.opacity = alpha; + } + } + } + } + +} ); +/** + * Renderer for re-rendering img elements using VML. Kicks in if the img has + * a border-radius applied, or if the -pie-png-fix flag is set. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.ImgRenderer = PIE.RendererBase.newRenderer( { + + boxZIndex: 6, + boxName: 'imgEl', + + needsUpdate: function() { + var si = this.styleInfos; + return this.targetElement.src !== this._lastSrc || si.borderRadiusInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.borderRadiusInfo.isActive() || si.backgroundInfo.isPngFix(); + }, + + draw: function() { + this._lastSrc = src; + this.hideActualImg(); + + var shape = this.getShape( 'img', 'fill', this.getBox() ), + fill = shape.fill, + bounds = this.boundsInfo.getBounds(), + w = bounds.w, + h = bounds.h, + borderProps = this.styleInfos.borderInfo.getProps(), + borderWidths = borderProps && borderProps.widths, + el = this.targetElement, + src = el.src, + round = Math.round, + cs = el.currentStyle, + getLength = PIE.getLength, + s, zero; + + // In IE6, the BorderRenderer will have hidden the border by moving the border-width to + // the padding; therefore we want to pretend the borders have no width so they aren't doubled + // when adding in the current padding value below. + if( !borderWidths || PIE.ieVersion < 7 ) { + zero = PIE.getLength( '0' ); + borderWidths = { 't': zero, 'r': zero, 'b': zero, 'l': zero }; + } + + shape.stroked = false; + fill.type = 'frame'; + fill.src = src; + fill.position = (w ? 0.5 / w : 0) + ',' + (h ? 0.5 / h : 0); + shape.coordsize = w * 2 + ',' + h * 2; + shape.coordorigin = '1,1'; + shape.path = this.getBoxPath( { + t: round( borderWidths['t'].pixels( el ) + getLength( cs.paddingTop ).pixels( el ) ), + r: round( borderWidths['r'].pixels( el ) + getLength( cs.paddingRight ).pixels( el ) ), + b: round( borderWidths['b'].pixels( el ) + getLength( cs.paddingBottom ).pixels( el ) ), + l: round( borderWidths['l'].pixels( el ) + getLength( cs.paddingLeft ).pixels( el ) ) + }, 2 ); + s = shape.style; + s.width = w; + s.height = h; + }, + + hideActualImg: function() { + this.targetElement.runtimeStyle.filter = 'alpha(opacity=0)'; + }, + + destroy: function() { + PIE.RendererBase.destroy.call( this ); + this.targetElement.runtimeStyle.filter = ''; + } + +} ); +/** + * Root renderer for IE9; manages the rendering layers in the element's background + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.IE9RootRenderer = PIE.RendererBase.newRenderer( { + + updatePos: PIE.emptyFn, + updateSize: PIE.emptyFn, + updateVisibility: PIE.emptyFn, + updateProps: PIE.emptyFn, + + outerCommasRE: /^,+|,+$/g, + innerCommasRE: /,+/g, + + setBackgroundLayer: function(zIndex, bg) { + var me = this, + bgLayers = me._bgLayers || ( me._bgLayers = [] ), + undef; + bgLayers[zIndex] = bg || undef; + }, + + finishUpdate: function() { + var me = this, + bgLayers = me._bgLayers, + bg; + if( bgLayers && ( bg = bgLayers.join( ',' ).replace( me.outerCommasRE, '' ).replace( me.innerCommasRE, ',' ) ) !== me._lastBg ) { + me._lastBg = me.targetElement.runtimeStyle.background = bg; + } + }, + + destroy: function() { + this.targetElement.runtimeStyle.background = ''; + delete this._bgLayers; + } + +} ); +/** + * Renderer for element backgrounds, specific for IE9. Only handles translating CSS3 gradients + * to an equivalent SVG data URI. + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + */ +PIE.IE9BackgroundRenderer = PIE.RendererBase.newRenderer( { + + bgLayerZIndex: 1, + + needsUpdate: function() { + var si = this.styleInfos; + return si.backgroundInfo.changed(); + }, + + isActive: function() { + var si = this.styleInfos; + return si.backgroundInfo.isActive() || si.borderImageInfo.isActive(); + }, + + draw: function() { + var me = this, + props = me.styleInfos.backgroundInfo.getProps(), + bg, images, i = 0, img, bgAreaSize, bgSize; + + if ( props ) { + bg = []; + + images = props.bgImages; + if ( images ) { + while( img = images[ i++ ] ) { + if (img.imgType === 'linear-gradient' ) { + bgAreaSize = me.getBgAreaSize( img.bgOrigin ); + bgSize = ( img.bgSize || PIE.BgSize.DEFAULT ).pixels( + me.targetElement, bgAreaSize.w, bgAreaSize.h, bgAreaSize.w, bgAreaSize.h + ), + bg.push( + 'url(data:image/svg+xml,' + escape( me.getGradientSvg( img, bgSize.w, bgSize.h ) ) + ') ' + + me.bgPositionToString( img.bgPosition ) + ' / ' + bgSize.w + 'px ' + bgSize.h + 'px ' + + ( img.bgAttachment || '' ) + ' ' + ( img.bgOrigin || '' ) + ' ' + ( img.bgClip || '' ) + ); + } else { + bg.push( img.origString ); + } + } + } + + if ( props.color ) { + bg.push( props.color.val ); + } + + me.parent.setBackgroundLayer(me.bgLayerZIndex, bg.join(',')); + } + }, + + bgPositionToString: function( bgPosition ) { + return bgPosition ? bgPosition.tokens.map(function(token) { + return token.tokenValue; + }).join(' ') : '0 0'; + }, + + getBgAreaSize: function( bgOrigin ) { + var me = this, + el = me.targetElement, + bounds = me.boundsInfo.getBounds(), + elW = bounds.w, + elH = bounds.h, + w = elW, + h = elH, + borders, getLength, cs; + + if( bgOrigin !== 'border-box' ) { + borders = me.styleInfos.borderInfo.getProps(); + if( borders && ( borders = borders.widths ) ) { + w -= borders[ 'l' ].pixels( el ) + borders[ 'l' ].pixels( el ); + h -= borders[ 't' ].pixels( el ) + borders[ 'b' ].pixels( el ); + } + } + + if ( bgOrigin === 'content-box' ) { + getLength = PIE.getLength; + cs = el.currentStyle; + w -= getLength( cs.paddingLeft ).pixels( el ) + getLength( cs.paddingRight ).pixels( el ); + h -= getLength( cs.paddingTop ).pixels( el ) + getLength( cs.paddingBottom ).pixels( el ); + } + + return { w: w, h: h }; + }, + + getGradientSvg: function( info, bgWidth, bgHeight ) { + var el = this.targetElement, + stopsInfo = info.stops, + stopCount = stopsInfo.length, + metrics = PIE.GradientUtil.getGradientMetrics( el, bgWidth, bgHeight, info ), + startX = metrics.startX, + startY = metrics.startY, + endX = metrics.endX, + endY = metrics.endY, + lineLength = metrics.lineLength, + stopPx, + i, j, before, after, + svg; + + // Find the pixel offsets along the CSS3 gradient-line for each stop. + stopPx = []; + for( i = 0; i < stopCount; i++ ) { + stopPx.push( stopsInfo[i].offset ? stopsInfo[i].offset.pixels( el, lineLength ) : + i === 0 ? 0 : i === stopCount - 1 ? lineLength : null ); + } + // Fill in gaps with evenly-spaced offsets + for( i = 1; i < stopCount; i++ ) { + if( stopPx[ i ] === null ) { + before = stopPx[ i - 1 ]; + j = i; + do { + after = stopPx[ ++j ]; + } while( after === null ); + stopPx[ i ] = before + ( after - before ) / ( j - i + 1 ); + } + } + + svg = [ + '<svg width="' + bgWidth + '" height="' + bgHeight + '" xmlns="http://www.w3.org/2000/svg">' + + '<defs>' + + '<linearGradient id="g" gradientUnits="userSpaceOnUse"' + + ' x1="' + ( startX / bgWidth * 100 ) + '%" y1="' + ( startY / bgHeight * 100 ) + '%" x2="' + ( endX / bgWidth * 100 ) + '%" y2="' + ( endY / bgHeight * 100 ) + '%">' + ]; + + // Convert to percentage along the SVG gradient line and add to the stops list + for( i = 0; i < stopCount; i++ ) { + svg.push( + '<stop offset="' + ( stopPx[ i ] / lineLength ) + + '" stop-color="' + stopsInfo[i].color.colorValue( el ) + + '" stop-opacity="' + stopsInfo[i].color.alpha() + '"/>' + ); + } + + svg.push( + '</linearGradient>' + + '</defs>' + + '<rect width="100%" height="100%" fill="url(#g)"/>' + + '</svg>' + ); + + return svg.join( '' ); + }, + + destroy: function() { + this.parent.setBackgroundLayer( this.bgLayerZIndex ); + } + +} ); +/** + * Renderer for border-image + * @constructor + * @param {Element} el The target element + * @param {Object} styleInfos The StyleInfo objects + * @param {PIE.RootRenderer} parent + */ +PIE.IE9BorderImageRenderer = PIE.RendererBase.newRenderer( { + + REPEAT: 'repeat', + STRETCH: 'stretch', + ROUND: 'round', + + bgLayerZIndex: 0, + + needsUpdate: function() { + return this.styleInfos.borderImageInfo.changed(); + }, + + isActive: function() { + return this.styleInfos.borderImageInfo.isActive(); + }, + + draw: function() { + var me = this, + props = me.styleInfos.borderImageInfo.getProps(), + borderProps = me.styleInfos.borderInfo.getProps(), + bounds = me.boundsInfo.getBounds(), + repeat = props.repeat, + repeatH = repeat.h, + repeatV = repeat.v, + el = me.targetElement, + isAsync = 0; + + PIE.Util.withImageSize( props.src, function( imgSize ) { + var elW = bounds.w, + elH = bounds.h, + imgW = imgSize.w, + imgH = imgSize.h, + + // The image cannot be referenced as a URL directly in the SVG because IE9 throws a strange + // security exception (perhaps due to cross-origin policy within data URIs?) Therefore we + // work around this by converting the image data into a data URI itself using a transient + // canvas. This unfortunately requires the border-image src to be within the same domain, + // which isn't a limitation in true border-image, so we need to try and find a better fix. + imgSrc = me.imageToDataURI( props.src, imgW, imgH ), + + REPEAT = me.REPEAT, + STRETCH = me.STRETCH, + ROUND = me.ROUND, + ceil = Math.ceil, + + zero = PIE.getLength( '0' ), + widths = props.widths || ( borderProps ? borderProps.widths : { 't': zero, 'r': zero, 'b': zero, 'l': zero } ), + widthT = widths['t'].pixels( el ), + widthR = widths['r'].pixels( el ), + widthB = widths['b'].pixels( el ), + widthL = widths['l'].pixels( el ), + slices = props.slice, + sliceT = slices['t'].pixels( el ), + sliceR = slices['r'].pixels( el ), + sliceB = slices['b'].pixels( el ), + sliceL = slices['l'].pixels( el ), + centerW = elW - widthL - widthR, + middleH = elH - widthT - widthB, + imgCenterW = imgW - sliceL - sliceR, + imgMiddleH = imgH - sliceT - sliceB, + + // Determine the size of each tile - 'round' is handled below + tileSizeT = repeatH === STRETCH ? centerW : imgCenterW * widthT / sliceT, + tileSizeR = repeatV === STRETCH ? middleH : imgMiddleH * widthR / sliceR, + tileSizeB = repeatH === STRETCH ? centerW : imgCenterW * widthB / sliceB, + tileSizeL = repeatV === STRETCH ? middleH : imgMiddleH * widthL / sliceL, + + svg, + patterns = [], + rects = [], + i = 0; + + // For 'round', subtract from each tile's size enough so that they fill the space a whole number of times + if (repeatH === ROUND) { + tileSizeT -= (tileSizeT - (centerW % tileSizeT || tileSizeT)) / ceil(centerW / tileSizeT); + tileSizeB -= (tileSizeB - (centerW % tileSizeB || tileSizeB)) / ceil(centerW / tileSizeB); + } + if (repeatV === ROUND) { + tileSizeR -= (tileSizeR - (middleH % tileSizeR || tileSizeR)) / ceil(middleH / tileSizeR); + tileSizeL -= (tileSizeL - (middleH % tileSizeL || tileSizeL)) / ceil(middleH / tileSizeL); + } + + + // Build the SVG for the border-image rendering. Add each piece as a pattern, which is then stretched + // or repeated as the fill of a rect of appropriate size. + svg = [ + '<svg width="' + elW + '" height="' + elH + '" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' + ]; + + function addImage( x, y, w, h, cropX, cropY, cropW, cropH, tileW, tileH ) { + patterns.push( + '<pattern patternUnits="userSpaceOnUse" id="pattern' + i + '" ' + + 'x="' + (repeatH === REPEAT ? x + w / 2 - tileW / 2 : x) + '" ' + + 'y="' + (repeatV === REPEAT ? y + h / 2 - tileH / 2 : y) + '" ' + + 'width="' + tileW + '" height="' + tileH + '">' + + '<svg width="' + tileW + '" height="' + tileH + '" viewBox="' + cropX + ' ' + cropY + ' ' + cropW + ' ' + cropH + '" preserveAspectRatio="none">' + + '<image xlink:href="' + imgSrc + '" x="0" y="0" width="' + imgW + '" height="' + imgH + '" />' + + '</svg>' + + '</pattern>' + ); + rects.push( + '<rect x="' + x + '" y="' + y + '" width="' + w + '" height="' + h + '" fill="url(#pattern' + i + ')" />' + ); + i++; + } + addImage( 0, 0, widthL, widthT, 0, 0, sliceL, sliceT, widthL, widthT ); // top left + addImage( widthL, 0, centerW, widthT, sliceL, 0, imgCenterW, sliceT, tileSizeT, widthT ); // top center + addImage( elW - widthR, 0, widthR, widthT, imgW - sliceR, 0, sliceR, sliceT, widthR, widthT ); // top right + addImage( 0, widthT, widthL, middleH, 0, sliceT, sliceL, imgMiddleH, widthL, tileSizeL ); // middle left + if ( props.fill ) { // center fill + addImage( widthL, widthT, centerW, middleH, sliceL, sliceT, imgCenterW, imgMiddleH, + tileSizeT || tileSizeB || imgCenterW, tileSizeL || tileSizeR || imgMiddleH ); + } + addImage( elW - widthR, widthT, widthR, middleH, imgW - sliceR, sliceT, sliceR, imgMiddleH, widthR, tileSizeR ); // middle right + addImage( 0, elH - widthB, widthL, widthB, 0, imgH - sliceB, sliceL, sliceB, widthL, widthB ); // bottom left + addImage( widthL, elH - widthB, centerW, widthB, sliceL, imgH - sliceB, imgCenterW, sliceB, tileSizeB, widthB ); // bottom center + addImage( elW - widthR, elH - widthB, widthR, widthB, imgW - sliceR, imgH - sliceB, sliceR, sliceB, widthR, widthB ); // bottom right + + svg.push( + '<defs>' + + patterns.join('\n') + + '</defs>' + + rects.join('\n') + + '</svg>' + ); + + me.parent.setBackgroundLayer( me.bgLayerZIndex, 'url(data:image/svg+xml,' + escape( svg.join( '' ) ) + ') no-repeat border-box border-box' ); + + // If the border-image's src wasn't immediately available, the SVG for its background layer + // will have been created asynchronously after the main element's update has finished; we'll + // therefore need to force the root renderer to sync to the final background once finished. + if( isAsync ) { + me.parent.finishUpdate(); + } + }, me ); + + isAsync = 1; + }, + + /** + * Convert a given image to a data URI + */ + imageToDataURI: (function() { + var uris = {}; + return function( src, width, height ) { + var uri = uris[ src ], + image, canvas; + if ( !uri ) { + image = new Image(); + canvas = doc.createElement( 'canvas' ); + image.src = src; + canvas.width = width; + canvas.height = height; + canvas.getContext( '2d' ).drawImage( image, 0, 0 ); + uri = uris[ src ] = canvas.toDataURL(); + } + return uri; + } + })(), + + prepareUpdate: PIE.BorderImageRenderer.prototype.prepareUpdate, + + destroy: function() { + var me = this, + rs = me.targetElement.runtimeStyle; + me.parent.setBackgroundLayer( me.bgLayerZIndex ); + rs.borderColor = rs.borderStyle = rs.borderWidth = ''; + } + +} ); + +PIE.Element = (function() { + + var wrappers = {}, + lazyInitCssProp = PIE.CSS_PREFIX + 'lazy-init', + pollCssProp = PIE.CSS_PREFIX + 'poll', + trackActiveCssProp = PIE.CSS_PREFIX + 'track-active', + trackHoverCssProp = PIE.CSS_PREFIX + 'track-hover', + hoverClass = PIE.CLASS_PREFIX + 'hover', + activeClass = PIE.CLASS_PREFIX + 'active', + focusClass = PIE.CLASS_PREFIX + 'focus', + firstChildClass = PIE.CLASS_PREFIX + 'first-child', + ignorePropertyNames = { 'background':1, 'bgColor':1, 'display': 1 }, + classNameRegExes = {}, + dummyArray = []; + + + function addClass( el, className ) { + el.className += ' ' + className; + } + + function removeClass( el, className ) { + var re = classNameRegExes[ className ] || + ( classNameRegExes[ className ] = new RegExp( '\\b' + className + '\\b', 'g' ) ); + el.className = el.className.replace( re, '' ); + } + + function delayAddClass( el, className /*, className2*/ ) { + var classes = dummyArray.slice.call( arguments, 1 ), + i = classes.length; + setTimeout( function() { + if( el ) { + while( i-- ) { + addClass( el, classes[ i ] ); + } + } + }, 0 ); + } + + function delayRemoveClass( el, className /*, className2*/ ) { + var classes = dummyArray.slice.call( arguments, 1 ), + i = classes.length; + setTimeout( function() { + if( el ) { + while( i-- ) { + removeClass( el, classes[ i ] ); + } + } + }, 0 ); + } + + + + function Element( el ) { + var renderers, + rootRenderer, + boundsInfo = new PIE.BoundsInfo( el ), + styleInfos, + styleInfosArr, + initializing, + initialized, + eventsAttached, + eventListeners = [], + delayed, + destroyed, + poll; + + /** + * Initialize PIE for this element. + */ + function init() { + if( !initialized ) { + var docEl, + bounds, + ieDocMode = PIE.ieDocMode, + cs = el.currentStyle, + lazy = cs.getAttribute( lazyInitCssProp ) === 'true', + trackActive = cs.getAttribute( trackActiveCssProp ) !== 'false', + trackHover = cs.getAttribute( trackHoverCssProp ) !== 'false', + childRenderers; + + // Polling for size/position changes: default to on in IE8, off otherwise, overridable by -pie-poll + poll = cs.getAttribute( pollCssProp ); + poll = ieDocMode > 7 ? poll !== 'false' : poll === 'true'; + + // Force layout so move/resize events will fire. Set this as soon as possible to avoid layout changes + // after load, but make sure it only gets called the first time through to avoid recursive calls to init(). + if( !initializing ) { + initializing = 1; + el.runtimeStyle.zoom = 1; + initFirstChildPseudoClass(); + } + + boundsInfo.lock(); + + // If the -pie-lazy-init:true flag is set, check if the element is outside the viewport and if so, delay initialization + if( lazy && ( bounds = boundsInfo.getBounds() ) && ( docEl = doc.documentElement || doc.body ) && + ( bounds.y > docEl.clientHeight || bounds.x > docEl.clientWidth || bounds.y + bounds.h < 0 || bounds.x + bounds.w < 0 ) ) { + if( !delayed ) { + delayed = 1; + PIE.OnScroll.observe( init ); + } + } else { + initialized = 1; + delayed = initializing = 0; + PIE.OnScroll.unobserve( init ); + + // Create the style infos and renderers + if ( ieDocMode === 9 ) { + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderImageInfo + ]; + rootRenderer = new PIE.IE9RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.IE9BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.IE9BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + } else { + + styleInfos = { + backgroundInfo: new PIE.BackgroundStyleInfo( el ), + borderInfo: new PIE.BorderStyleInfo( el ), + borderImageInfo: new PIE.BorderImageStyleInfo( el ), + borderRadiusInfo: new PIE.BorderRadiusStyleInfo( el ), + boxShadowInfo: new PIE.BoxShadowStyleInfo( el ), + visibilityInfo: new PIE.VisibilityStyleInfo( el ) + }; + styleInfosArr = [ + styleInfos.backgroundInfo, + styleInfos.borderInfo, + styleInfos.borderImageInfo, + styleInfos.borderRadiusInfo, + styleInfos.boxShadowInfo, + styleInfos.visibilityInfo + ]; + rootRenderer = new PIE.RootRenderer( el, boundsInfo, styleInfos ); + childRenderers = [ + new PIE.BoxShadowOutsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BackgroundRenderer( el, boundsInfo, styleInfos, rootRenderer ), + //new PIE.BoxShadowInsetRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderRenderer( el, boundsInfo, styleInfos, rootRenderer ), + new PIE.BorderImageRenderer( el, boundsInfo, styleInfos, rootRenderer ) + ]; + if( el.tagName === 'IMG' ) { + childRenderers.push( new PIE.ImgRenderer( el, boundsInfo, styleInfos, rootRenderer ) ); + } + rootRenderer.childRenderers = childRenderers; // circular reference, can't pass in constructor; TODO is there a cleaner way? + } + renderers = [ rootRenderer ].concat( childRenderers ); + + // Add property change listeners to ancestors if requested + initAncestorEventListeners(); + + // Add to list of polled elements in IE8 + if( poll ) { + PIE.Heartbeat.observe( update ); + PIE.Heartbeat.run(); + } + + // Trigger rendering + update( 1 ); + } + + if( !eventsAttached ) { + eventsAttached = 1; + if( ieDocMode < 9 ) { + addListener( el, 'onmove', handleMoveOrResize ); + } + addListener( el, 'onresize', handleMoveOrResize ); + addListener( el, 'onpropertychange', propChanged ); + if( trackHover ) { + addListener( el, 'onmouseenter', mouseEntered ); + } + if( trackHover || trackActive ) { + addListener( el, 'onmouseleave', mouseLeft ); + } + if( trackActive ) { + addListener( el, 'onmousedown', mousePressed ); + } + if( el.tagName in PIE.focusableElements ) { + addListener( el, 'onfocus', focused ); + addListener( el, 'onblur', blurred ); + } + PIE.OnResize.observe( handleMoveOrResize ); + + PIE.OnUnload.observe( removeEventListeners ); + } + + boundsInfo.unlock(); + } + } + + + + + /** + * Event handler for onmove and onresize events. Invokes update() only if the element's + * bounds have previously been calculated, to prevent multiple runs during page load when + * the element has no initial CSS3 properties. + */ + function handleMoveOrResize() { + if( boundsInfo && boundsInfo.hasBeenQueried() ) { + update(); + } + } + + + /** + * Update position and/or size as necessary. Both move and resize events call + * this rather than the updatePos/Size functions because sometimes, particularly + * during page load, one will fire but the other won't. + */ + function update( force ) { + if( !destroyed ) { + if( initialized ) { + var i, len = renderers.length; + + lockAll(); + for( i = 0; i < len; i++ ) { + renderers[i].prepareUpdate(); + } + if( force || boundsInfo.positionChanged() ) { + /* TODO just using getBoundingClientRect (used internally by BoundsInfo) for detecting + position changes may not always be accurate; it's possible that + an element will actually move relative to its positioning parent, but its position + relative to the viewport will stay the same. Need to come up with a better way to + track movement. The most accurate would be the same logic used in RootRenderer.updatePos() + but that is a more expensive operation since it does some DOM walking, and we want this + check to be as fast as possible. */ + for( i = 0; i < len; i++ ) { + renderers[i].updatePos(); + } + } + if( force || boundsInfo.sizeChanged() ) { + for( i = 0; i < len; i++ ) { + renderers[i].updateSize(); + } + } + rootRenderer.finishUpdate(); + unlockAll(); + } + else if( !initializing ) { + init(); + } + } + } + + /** + * Handle property changes to trigger update when appropriate. + */ + function propChanged() { + var i, len = renderers.length, + renderer, + e = event; + + // Some elements like <table> fire onpropertychange events for old-school background properties + // ('background', 'bgColor') when runtimeStyle background properties are changed, which + // results in an infinite loop; therefore we filter out those property names. Also, 'display' + // is ignored because size calculations don't work correctly immediately when its onpropertychange + // event fires, and because it will trigger an onresize event anyway. + if( !destroyed && !( e && e.propertyName in ignorePropertyNames ) ) { + if( initialized ) { + lockAll(); + for( i = 0; i < len; i++ ) { + renderers[i].prepareUpdate(); + } + for( i = 0; i < len; i++ ) { + renderer = renderers[i]; + // Make sure position is synced if the element hasn't already been rendered. + // TODO this feels sloppy - look into merging propChanged and update functions + if( !renderer.isPositioned ) { + renderer.updatePos(); + } + if( renderer.needsUpdate() ) { + renderer.updateProps(); + } + } + rootRenderer.finishUpdate(); + unlockAll(); + } + else if( !initializing ) { + init(); + } + } + } + + + /** + * Handle mouseenter events. Adds a custom class to the element to allow IE6 to add + * hover styles to non-link elements, and to trigger a propertychange update. + */ + function mouseEntered() { + //must delay this because the mouseenter event fires before the :hover styles are added. + delayAddClass( el, hoverClass ); + } + + /** + * Handle mouseleave events + */ + function mouseLeft() { + //must delay this because the mouseleave event fires before the :hover styles are removed. + delayRemoveClass( el, hoverClass, activeClass ); + } + + /** + * Handle mousedown events. Adds a custom class to the element to allow IE6 to add + * active styles to non-link elements, and to trigger a propertychange update. + */ + function mousePressed() { + //must delay this because the mousedown event fires before the :active styles are added. + delayAddClass( el, activeClass ); + + // listen for mouseups on the document; can't just be on the element because the user might + // have dragged out of the element while the mouse button was held down + PIE.OnMouseup.observe( mouseReleased ); + } + + /** + * Handle mouseup events + */ + function mouseReleased() { + //must delay this because the mouseup event fires before the :active styles are removed. + delayRemoveClass( el, activeClass ); + + PIE.OnMouseup.unobserve( mouseReleased ); + } + + /** + * Handle focus events. Adds a custom class to the element to trigger a propertychange update. + */ + function focused() { + //must delay this because the focus event fires before the :focus styles are added. + delayAddClass( el, focusClass ); + } + + /** + * Handle blur events + */ + function blurred() { + //must delay this because the blur event fires before the :focus styles are removed. + delayRemoveClass( el, focusClass ); + } + + + /** + * Handle property changes on ancestors of the element; see initAncestorEventListeners() + * which adds these listeners as requested with the -pie-watch-ancestors CSS property. + */ + function ancestorPropChanged() { + var name = event.propertyName; + if( name === 'className' || name === 'id' ) { + propChanged(); + } + } + + function lockAll() { + boundsInfo.lock(); + for( var i = styleInfosArr.length; i--; ) { + styleInfosArr[i].lock(); + } + } + + function unlockAll() { + for( var i = styleInfosArr.length; i--; ) { + styleInfosArr[i].unlock(); + } + boundsInfo.unlock(); + } + + + function addListener( targetEl, type, handler ) { + targetEl.attachEvent( type, handler ); + eventListeners.push( [ targetEl, type, handler ] ); + } + + /** + * Remove all event listeners from the element and any monitored ancestors. + */ + function removeEventListeners() { + if (eventsAttached) { + var i = eventListeners.length, + listener; + + while( i-- ) { + listener = eventListeners[ i ]; + listener[ 0 ].detachEvent( listener[ 1 ], listener[ 2 ] ); + } + + PIE.OnUnload.unobserve( removeEventListeners ); + eventsAttached = 0; + eventListeners = []; + } + } + + + /** + * Clean everything up when the behavior is removed from the element, or the element + * is manually destroyed. + */ + function destroy() { + if( !destroyed ) { + var i, len; + + removeEventListeners(); + + destroyed = 1; + + // destroy any active renderers + if( renderers ) { + for( i = 0, len = renderers.length; i < len; i++ ) { + renderers[i].finalized = 1; + renderers[i].destroy(); + } + } + + // Remove from list of polled elements in IE8 + if( poll ) { + PIE.Heartbeat.unobserve( update ); + } + // Stop onresize listening + PIE.OnResize.unobserve( update ); + + // Kill references + renderers = boundsInfo = styleInfos = styleInfosArr = el = null; + } + } + + + /** + * If requested via the custom -pie-watch-ancestors CSS property, add onpropertychange and + * other event listeners to ancestor(s) of the element so we can pick up style changes + * based on CSS rules using descendant selectors. + */ + function initAncestorEventListeners() { + var watch = el.currentStyle.getAttribute( PIE.CSS_PREFIX + 'watch-ancestors' ), + i, a; + if( watch ) { + watch = parseInt( watch, 10 ); + i = 0; + a = el.parentNode; + while( a && ( watch === 'NaN' || i++ < watch ) ) { + addListener( a, 'onpropertychange', ancestorPropChanged ); + addListener( a, 'onmouseenter', mouseEntered ); + addListener( a, 'onmouseleave', mouseLeft ); + addListener( a, 'onmousedown', mousePressed ); + if( a.tagName in PIE.focusableElements ) { + addListener( a, 'onfocus', focused ); + addListener( a, 'onblur', blurred ); + } + a = a.parentNode; + } + } + } + + + /** + * If the target element is a first child, add a pie_first-child class to it. This allows using + * the added class as a workaround for the fact that PIE's rendering element breaks the :first-child + * pseudo-class selector. + */ + function initFirstChildPseudoClass() { + var tmpEl = el, + isFirst = 1; + while( tmpEl = tmpEl.previousSibling ) { + if( tmpEl.nodeType === 1 ) { + isFirst = 0; + break; + } + } + if( isFirst ) { + addClass( el, firstChildClass ); + } + } + + + // These methods are all already bound to this instance so there's no need to wrap them + // in a closure to maintain the 'this' scope object when calling them. + this.init = init; + this.update = update; + this.destroy = destroy; + this.el = el; + } + + Element.getInstance = function( el ) { + var id = PIE.Util.getUID( el ); + return wrappers[ id ] || ( wrappers[ id ] = new Element( el ) ); + }; + + Element.destroy = function( el ) { + var id = PIE.Util.getUID( el ), + wrapper = wrappers[ id ]; + if( wrapper ) { + wrapper.destroy(); + delete wrappers[ id ]; + } + }; + + Element.destroyAll = function() { + var els = [], wrapper; + if( wrappers ) { + for( var w in wrappers ) { + if( wrappers.hasOwnProperty( w ) ) { + wrapper = wrappers[ w ]; + els.push( wrapper.el ); + wrapper.destroy(); + } + } + wrappers = {}; + } + return els; + }; + + return Element; +})(); + +/* + * This file exposes the public API for invoking PIE. + */ + + +/** + * @property supportsVML + * True if the current IE browser environment has a functioning VML engine. Should be true + * in most IEs, but in rare cases may be false. If false, PIE will exit immediately when + * attached to an element; this property may be used for debugging or by external scripts + * to perform some special action when VML support is absent. + * @type {boolean} + */ +PIE[ 'supportsVML' ] = PIE.supportsVML; + + +/** + * Programatically attach PIE to a single element. + * @param {Element} el + */ +PIE[ 'attach' ] = function( el ) { + if (PIE.ieDocMode < 10 && PIE.supportsVML) { + PIE.Element.getInstance( el ).init(); + } +}; + + +/** + * Programatically detach PIE from a single element. + * @param {Element} el + */ +PIE[ 'detach' ] = function( el ) { + PIE.Element.destroy( el ); +}; + + +} // if( !PIE ) +})();
\ No newline at end of file diff --git a/themes/mantra/resources/js/frontend.js b/themes/mantra/resources/js/frontend.js new file mode 100644 index 00000000..391a5550 --- /dev/null +++ b/themes/mantra/resources/js/frontend.js @@ -0,0 +1,190 @@ +/****************************** + Mantra Theme + custom scripting + (c) Cryout Creations + www.cryoutcreations.eu +*******************************/ + + +jQuery(document).ready(function() { + +/* Standard menu touch support for tablets */ +var custom_event = ('ontouchstart' in window) ? 'touchstart' : 'click'; /* check touch support */ +var ios = /iPhone|iPad|iPod/i.test(navigator.userAgent); + jQuery('#access .menu > ul > li a').on('click', function(e){ + var $link_id = jQuery(this).attr('href'); + if (jQuery(this).parent().data('clicked') == $link_id) { /* second touch */ + jQuery(this).parent().data('clicked', null); + } + else { /* first touch */ + if (custom_event != 'click' && !ios && (jQuery(this).parent().children('ul').length >0)) {e.preventDefault();} + jQuery(this).parent().data('clicked', $link_id); + } + }); + +/* Back to top button animation */ +jQuery(function() { + jQuery(window).scroll(function() { + var x=jQuery(this).scrollTop(); + + if(x != 0) { + jQuery('#toTop').addClass('showtop') + } else { + jQuery('#toTop').removeClass('showtop'); + } + + }); + jQuery('#toTop').click(function() { jQuery('body,html').animate({scrollTop:0},800); }); +}); + + +/* Menu animation */ +jQuery("#access ul ul").css({display: "none"}); /* Opera Fix */ +jQuery("#access").removeClass("jssafe"); /* JS failsafe */ +jQuery("#access .menu ul li").hoverIntent({ + over: function(){jQuery(this).children("ul").fadeIn(300);}, + out: function(){ jQuery(this).children('ul').fadeOut();}, + timeout:300} +); + + +/* detect and apply custom class for safari */ +if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { + jQuery('body').addClass('safari'); +} + +/* Add custom borders to images */ +jQuery("img.alignnone, img.alignleft, img.aligncenter, img.alignright").addClass(mantra_options.image_class); + + +}); +/* end document.ready */ + +/* Mobile Menu v2 */ +function mantra_mobilemenu_init() { + var state = false; + jQuery("#nav-toggle").click(function(){ + jQuery("#access").slideToggle(function(){ if (state) {jQuery(this).removeAttr( 'style' )}; state = ! state; } ); + }); +} + +jQuery(window).load(function() { + mantra_mobilemenu_init(); +}); + +/* Columns equalizer, used if at least one sidebar has a bg color */ +function equalizeHeights(){ + var h1 = jQuery("#primary").height(); + var h2 = jQuery("#secondary").height(); + var h3 = jQuery("#content").height(); + var max = Math.max(h1,h2,h3); + if (h1<max) { jQuery("#primary").height(max); }; + if (h2<max) { jQuery("#secondary").height(max); }; +} + +function makeDoubleDelegate(function1, function2) { +// concatenate functions + return function() { if (function1) function1(); if (function2) function2(); } +} + +function mantra_onload() { + if ( mantra_options.responsive == 1 ) { + /* Add responsive videos */ + if (jQuery(window).width() < 800) jQuery(".entry-content").fitVids(); + } + if ( mantra_options.equalizesidebars = 1 ) { + /* Check if sidebars have user colors and if so equalize their heights */ + equalizeHeights(); + } +}; // mantra_onload + +// make sure not to lose previous onload events +window.onload = makeDoubleDelegate(window.onload, mantra_onload ); + +/*! +* FitVids 1.0 +* +* Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com +* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ +* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ +* +* Date: Thu Sept 01 18:00:00 2011 -0500 +*/ + +(function( $ ){ + + $.fn.fitVids = function( options ) { + var settings = { + customSelector: null + } + + var div = document.createElement('div'), + ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0]; + + div.className = 'fit-vids-style'; + div.innerHTML = '­<style> .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wrapper iframe, .fluid-width-video-wrapper object, .fluid-width-video-wrapper embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style>'; + + ref.parentNode.insertBefore(div,ref); + + if ( options ) { + $.extend( settings, options ); + } + + return this.each(function(){ + var selectors = [ + "iframe[src*='player.vimeo.com']", + "iframe[src*='www.youtube.com']", + "iframe[src*='www.kickstarter.com']", + "object", + "embed" + ]; + + if (settings.customSelector) { + selectors.push(settings.customSelector); + } + + var $allVideos = $(this).find(selectors.join(',')); + + $allVideos.each(function(){ + var $this = $(this); + if (this.tagName.toLowerCase() == 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } + var height = this.tagName.toLowerCase() == 'object' ? $this.attr('height') : $this.height(), + aspectRatio = height / $this.width(); + if(!$this.attr('id')){ + var videoID = 'fitvid' + Math.floor(Math.random()*999999); + $this.attr('id', videoID); + } + $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%"); + $this.removeAttr('height').removeAttr('width'); + }); + }); + + } +})( jQuery ); + + +/*! + * hoverIntent r7 // 2013.03.11 // jQuery 1.9.1+ + * http://cherne.net/brian/resources/jquery.hoverIntent.html + * + * You may use hoverIntent under the terms of the MIT license. + * Copyright 2007, 2013 Brian Cherne + */ +(function(e){e.fn.hoverIntent=function(t,n,r){var i={interval:100,sensitivity:7,timeout:0};if(typeof t==="object"){i=e.extend(i,t)}else if(e.isFunction(n)){i=e.extend(i,{over:t,out:n,selector:r})}else{i=e.extend(i,{over:t,out:t,selector:n})}var s,o,u,a;var f=function(e){s=e.pageX;o=e.pageY};var l=function(t,n){n.hoverIntent_t=clearTimeout(n.hoverIntent_t);if(Math.abs(u-s)+Math.abs(a-o)<i.sensitivity){e(n).off("mousemove.hoverIntent",f);n.hoverIntent_s=1;return i.over.apply(n,[t])}else{u=s;a=o;n.hoverIntent_t=setTimeout(function(){l(t,n)},i.interval)}};var c=function(e,t){t.hoverIntent_t=clearTimeout(t.hoverIntent_t);t.hoverIntent_s=0;return i.out.apply(t,[e])};var h=function(t){var n=jQuery.extend({},t);var r=this;if(r.hoverIntent_t){r.hoverIntent_t=clearTimeout(r.hoverIntent_t)}if(t.type=="mouseenter"){u=n.pageX;a=n.pageY;e(r).on("mousemove.hoverIntent",f);if(r.hoverIntent_s!=1){r.hoverIntent_t=setTimeout(function(){l(n,r)},i.interval)}}else{e(r).off("mousemove.hoverIntent",f);if(r.hoverIntent_s==1){r.hoverIntent_t=setTimeout(function(){c(n,r)},i.timeout)}}};return this.on({"mouseenter.hoverIntent":h,"mouseleave.hoverIntent":h},i.selector)}})(jQuery) + + +/* Returns the version of Internet Explorer or a -1 + * (indicating the use of another browser). + */ +function getInternetExplorerVersion() +{ + var rv = -1; /* Return value assumes failure. */ + if (navigator.appName == 'Microsoft Internet Explorer') + { + var ua = navigator.userAgent; + var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); + if (re.exec(ua) != null) + rv = parseFloat( RegExp.$1 ); + } + return rv; +} diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png Binary files differnew file mode 100644 index 00000000..954e22db --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png Binary files differnew file mode 100644 index 00000000..64ece570 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png Binary files differnew file mode 100644 index 00000000..abdc0108 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png Binary files differnew file mode 100644 index 00000000..9b383f4d --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png Binary files differnew file mode 100644 index 00000000..a23baad2 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png Binary files differnew file mode 100644 index 00000000..42ccba26 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png Binary files differnew file mode 100644 index 00000000..39d5824d --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png Binary files differnew file mode 100644 index 00000000..f1273672 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png Binary files differnew file mode 100644 index 00000000..359397ac --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_222222_256x240.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_222222_256x240.png Binary files differnew file mode 100644 index 00000000..b273ff11 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_222222_256x240.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_228ef1_256x240.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_228ef1_256x240.png Binary files differnew file mode 100644 index 00000000..a641a371 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_228ef1_256x240.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png Binary files differnew file mode 100644 index 00000000..85e63e9f --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ef8c08_256x240.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png Binary files differnew file mode 100644 index 00000000..e117effa --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffd27a_256x240.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffffff_256x240.png b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffffff_256x240.png Binary files differnew file mode 100644 index 00000000..42f8f992 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/images/ui-icons_ffffff_256x240.png diff --git a/themes/mantra/resources/js/jqueryui/css/ui-lightness/jquery-ui-1.8.16.custom.css b/themes/mantra/resources/js/jqueryui/css/ui-lightness/jquery-ui-1.8.16.custom.css new file mode 100644 index 00000000..5547c7b9 --- /dev/null +++ b/themes/mantra/resources/js/jqueryui/css/ui-lightness/jquery-ui-1.8.16.custom.css @@ -0,0 +1,568 @@ +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } +.ui-helper-clearfix { display: inline-block; } +/* required comment for clearfix to work in Opera \*/ +* html .ui-helper-clearfix { height:1%; } +.ui-helper-clearfix { display:block; } +/* end clearfix */ +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Resizable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Resizable#theming + */ +.ui-resizable { position: relative;} +.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; } +.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } +.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } +.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } +.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } +.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } +.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } +.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } +.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } +.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* + * jQuery UI Selectable 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Selectable#theming + */ +.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } +/* + * jQuery UI Accordion 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Accordion#theming + */ +/* IE/Win - Fix animation bug - #4615 */ +.ui-accordion { width: 100%; } +.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } +.ui-accordion .ui-accordion-li-fix { display: inline; } +.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } +.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } +.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } +.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } +.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } +.ui-accordion .ui-accordion-content-active { display: block; } +/* + * jQuery UI Autocomplete 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Autocomplete#theming + */ +.ui-autocomplete { position: absolute; cursor: default; } + +/* workarounds */ +* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ + +/* + * jQuery UI Menu 1.8.16 + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu#theming + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; + float: left; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + float: left; + clear: left; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} +/* + * jQuery UI Button 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Button#theming + */ +.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ +.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ +button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ +.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } + +/*button text element */ +.ui-button .ui-button-text { display: block; line-height: 1.4; } +.ui-button-text-only .ui-button-text { padding: .4em 1em; } +.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } +.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } +.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } +.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } +/* no icon support for input elements, provide padding by default */ +input.ui-button { padding: .4em 1em; } + +/*button icon element(s) */ +.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } +.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } +.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } +.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } +.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } + +/*button sets*/ +.ui-buttonset { margin-right: 7px; } +.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } + +/* workarounds */ +button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ +/* + * jQuery UI Dialog 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Dialog#theming + */ +.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } +.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } +.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } +.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } +.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } +.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } +.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } +.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } +.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } +.ui-draggable .ui-dialog-titlebar { cursor: move; } +/* + * jQuery UI Slider 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Slider#theming + */ +.ui-slider { position: relative; text-align: left; } +.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } +.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } + +.ui-slider-horizontal { height: .8em; } +.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } +.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } +.ui-slider-horizontal .ui-slider-range-min { left: 0; } +.ui-slider-horizontal .ui-slider-range-max { right: 0; } + +.ui-slider-vertical { width: .8em; height: 100px; } +.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } +.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } +.ui-slider-vertical .ui-slider-range-min { bottom: 0; } +.ui-slider-vertical .ui-slider-range-max { top: 0; }/* + * jQuery UI Tabs 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Tabs#theming + */ +.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ +.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } +.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } +.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } +.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } +.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } +.ui-tabs .ui-tabs-hide { display: none !important; } +/* + * jQuery UI Datepicker 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +}/* + * jQuery UI Progressbar 1.8.16 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Progressbar#theming + */ +.ui-progressbar { height:2em; text-align: left; } +.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
\ No newline at end of file diff --git a/themes/mantra/resources/js/nivo-slider.js b/themes/mantra/resources/js/nivo-slider.js new file mode 100644 index 00000000..039f3cfb --- /dev/null +++ b/themes/mantra/resources/js/nivo-slider.js @@ -0,0 +1,10 @@ +/* + * jQuery Nivo Slider v3.2 + * http://nivo.dev7studios.com + * + * Copyright 2012, Dev7studios + * Free to use and abuse under the MIT license. + * http://www.opensource.org/licenses/mit-license.php + */ + +(function(e){var t=function(t,n){var r=e.extend({},e.fn.nivoSlider.defaults,n);var i={currentSlide:0,currentImage:"",totalSlides:0,running:false,paused:false,stop:false,controlNavEl:false};var s=e(t);s.data("nivo:vars",i).addClass("nivoSlider");var o=s.children();o.each(function(){var t=e(this);var n="";if(!t.is("img")){if(t.is("a")){t.addClass("nivo-imageLink");n=t}t=t.find("img:first")}var r=r===0?t.attr("width"):t.width(),s=s===0?t.attr("height"):t.height();if(n!==""){n.css("display","none")}t.css("display","none");i.totalSlides++});if(r.randomStart){r.startSlide=Math.floor(Math.random()*i.totalSlides)}if(r.startSlide>0){if(r.startSlide>=i.totalSlides){r.startSlide=i.totalSlides-1}i.currentSlide=r.startSlide}if(e(o[i.currentSlide]).is("img")){i.currentImage=e(o[i.currentSlide])}else{i.currentImage=e(o[i.currentSlide]).find("img:first")}if(e(o[i.currentSlide]).is("a")){e(o[i.currentSlide]).css("display","block")}var u=e("<img/>").addClass("nivo-main-image");u.attr("src",i.currentImage.attr("src")).show();s.append(u);e(window).resize(function(){s.children("img").width(s.width());u.attr("src",i.currentImage.attr("src"));u.stop().height("auto");e(".nivo-slice").remove();e(".nivo-box").remove()});s.append(e('<div class="nivo-caption"></div>'));var a=function(t){var n=e(".nivo-caption",s);if(i.currentImage.attr("title")!=""&&i.currentImage.attr("title")!=undefined){var r=i.currentImage.attr("title");if(r.substr(0,1)=="#")r=e(r).html();if(n.css("display")=="block"){setTimeout(function(){n.html(r)},t.animSpeed)}else{n.html(r);n.stop().fadeIn(t.animSpeed)}}else{n.stop().fadeOut(t.animSpeed)}};a(r);var f=0;if(!r.manualAdvance&&o.length>1){f=setInterval(function(){d(s,o,r,false)},r.pauseTime)}if(r.directionNav){s.append('<div class="nivo-directionNav"><a class="nivo-prevNav">'+r.prevText+'</a><a class="nivo-nextNav">'+r.nextText+"</a></div>");e(s).on("click","a.nivo-prevNav",function(){if(i.running){return false}clearInterval(f);f="";i.currentSlide-=2;d(s,o,r,"prev")});e(s).on("click","a.nivo-nextNav",function(){if(i.running){return false}clearInterval(f);f="";d(s,o,r,"next")})}if(r.controlNav){i.controlNavEl=e('<div class="nivo-controlNav"></div>');s.after(i.controlNavEl);for(var l=0;l<o.length;l++){if(r.controlNavThumbs){i.controlNavEl.addClass("nivo-thumbs-enabled");var c=o.eq(l);if(!c.is("img")){c=c.find("img:first")}if(c.attr("data-thumb"))i.controlNavEl.append('<a class="nivo-control" rel="'+l+'"><img src="'+c.attr("data-thumb")+'" alt="" /></a>')}else{i.controlNavEl.append('<a class="nivo-control" rel="'+l+'">'+(l+1)+"</a>")}}e("a:eq("+i.currentSlide+")",i.controlNavEl).addClass("active");e("a",i.controlNavEl).bind("click",function(){if(i.running)return false;if(e(this).hasClass("active"))return false;clearInterval(f);f="";u.attr("src",i.currentImage.attr("src"));i.currentSlide=e(this).attr("rel")-1;d(s,o,r,"control")})}if(r.pauseOnHover){s.hover(function(){i.paused=true;clearInterval(f);f=""},function(){i.paused=false;if(f===""&&!r.manualAdvance){f=setInterval(function(){d(s,o,r,false)},r.pauseTime)}})}s.bind("nivo:animFinished",function(){u.attr("src",i.currentImage.attr("src"));i.running=false;e(o).each(function(){if(e(this).is("a")){e(this).css("display","none")}});if(e(o[i.currentSlide]).is("a")){e(o[i.currentSlide]).css("display","block")}if(f===""&&!i.paused&&!r.manualAdvance){f=setInterval(function(){d(s,o,r,false)},r.pauseTime)}r.afterChange.call(this)});var h=function(t,n,r){if(e(r.currentImage).parent().is("a"))e(r.currentImage).parent().css("display","block");e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").width(t.width()).css("visibility","hidden").show();var i=e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").parent().is("a")?e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").parent().height():e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").height();for(var s=0;s<n.slices;s++){var o=Math.round(t.width()/n.slices);if(s===n.slices-1){t.append(e('<div class="nivo-slice" name="'+s+'"><img src="'+r.currentImage.attr("src")+'" style="position:absolute; width:'+t.width()+"px; height:auto; display:block !important; top:0; left:-"+(o+s*o-o)+'px;" /></div>').css({left:o*s+"px",width:t.width()-o*s+"px",height:i+"px",opacity:"0",overflow:"hidden"}))}else{t.append(e('<div class="nivo-slice" name="'+s+'"><img src="'+r.currentImage.attr("src")+'" style="position:absolute; width:'+t.width()+"px; height:auto; display:block !important; top:0; left:-"+(o+s*o-o)+'px;" /></div>').css({left:o*s+"px",width:o+"px",height:i+"px",opacity:"0",overflow:"hidden"}))}}e(".nivo-slice",t).height(i);u.stop().animate({height:e(r.currentImage).height()},n.animSpeed)};var p=function(t,n,r){if(e(r.currentImage).parent().is("a"))e(r.currentImage).parent().css("display","block");e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").width(t.width()).css("visibility","hidden").show();var i=Math.round(t.width()/n.boxCols),s=Math.round(e('img[src="'+r.currentImage.attr("src")+'"]',t).not(".nivo-main-image,.nivo-control img").height()/n.boxRows);for(var o=0;o<n.boxRows;o++){for(var a=0;a<n.boxCols;a++){if(a===n.boxCols-1){t.append(e('<div class="nivo-box" name="'+a+'" rel="'+o+'"><img src="'+r.currentImage.attr("src")+'" style="position:absolute; width:'+t.width()+"px; height:auto; display:block; top:-"+s*o+"px; left:-"+i*a+'px;" /></div>').css({opacity:0,left:i*a+"px",top:s*o+"px",width:t.width()-i*a+"px"}));e('.nivo-box[name="'+a+'"]',t).height(e('.nivo-box[name="'+a+'"] img',t).height()+"px")}else{t.append(e('<div class="nivo-box" name="'+a+'" rel="'+o+'"><img src="'+r.currentImage.attr("src")+'" style="position:absolute; width:'+t.width()+"px; height:auto; display:block; top:-"+s*o+"px; left:-"+i*a+'px;" /></div>').css({opacity:0,left:i*a+"px",top:s*o+"px",width:i+"px"}));e('.nivo-box[name="'+a+'"]',t).height(e('.nivo-box[name="'+a+'"] img',t).height()+"px")}}}u.stop().animate({height:e(r.currentImage).height()},n.animSpeed)};var d=function(t,n,r,i){var s=t.data("nivo:vars");if(s&&s.currentSlide===s.totalSlides-1){r.lastSlide.call(this)}if((!s||s.stop)&&!i){return false}r.beforeChange.call(this);if(!i){u.attr("src",s.currentImage.attr("src"))}else{if(i==="prev"){u.attr("src",s.currentImage.attr("src"))}if(i==="next"){u.attr("src",s.currentImage.attr("src"))}}s.currentSlide++;if(s.currentSlide===s.totalSlides){s.currentSlide=0;r.slideshowEnd.call(this)}if(s.currentSlide<0){s.currentSlide=s.totalSlides-1}if(e(n[s.currentSlide]).is("img")){s.currentImage=e(n[s.currentSlide])}else{s.currentImage=e(n[s.currentSlide]).find("img:first")}if(r.controlNav){e("a",s.controlNavEl).removeClass("active");e("a:eq("+s.currentSlide+")",s.controlNavEl).addClass("active")}a(r);e(".nivo-slice",t).remove();e(".nivo-box",t).remove();var o=r.effect,f="";if(r.effect==="random"){f=new Array("sliceDownRight","sliceDownLeft","sliceUpRight","sliceUpLeft","sliceUpDown","sliceUpDownLeft","fold","fade","boxRandom","boxRain","boxRainReverse","boxRainGrow","boxRainGrowReverse");o=f[Math.floor(Math.random()*(f.length+1))];if(o===undefined){o="fade"}}if(r.effect.indexOf(",")!==-1){f=r.effect.split(",");o=f[Math.floor(Math.random()*f.length)];if(o===undefined){o="fade"}}if(s.currentImage.attr("data-transition")){o=s.currentImage.attr("data-transition")}s.running=true;var l=0,c=0,d="",m="",g="",y="";if(o==="sliceDown"||o==="sliceDownRight"||o==="sliceDownLeft"){h(t,r,s);l=0;c=0;d=e(".nivo-slice",t);if(o==="sliceDownLeft"){d=e(".nivo-slice",t)._reverse()}d.each(function(){var n=e(this);n.css({top:"0px"});if(c===r.slices-1){setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed,"",function(){t.trigger("nivo:animFinished")})},100+l)}else{setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed)},100+l)}l+=50;c++})}else if(o==="sliceUp"||o==="sliceUpRight"||o==="sliceUpLeft"){h(t,r,s);l=0;c=0;d=e(".nivo-slice",t);if(o==="sliceUpLeft"){d=e(".nivo-slice",t)._reverse()}d.each(function(){var n=e(this);n.css({bottom:"0px"});if(c===r.slices-1){setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed,"",function(){t.trigger("nivo:animFinished")})},100+l)}else{setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed)},100+l)}l+=50;c++})}else if(o==="sliceUpDown"||o==="sliceUpDownRight"||o==="sliceUpDownLeft"){h(t,r,s);l=0;c=0;var b=0;d=e(".nivo-slice",t);if(o==="sliceUpDownLeft"){d=e(".nivo-slice",t)._reverse()}d.each(function(){var n=e(this);if(c===0){n.css("top","0px");c++}else{n.css("bottom","0px");c=0}if(b===r.slices-1){setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed,"",function(){t.trigger("nivo:animFinished")})},100+l)}else{setTimeout(function(){n.animate({opacity:"1.0"},r.animSpeed)},100+l)}l+=50;b++})}else if(o==="fold"){h(t,r,s);l=0;c=0;e(".nivo-slice",t).each(function(){var n=e(this);var i=n.width();n.css({top:"0px",width:"0px"});if(c===r.slices-1){setTimeout(function(){n.animate({width:i,opacity:"1.0"},r.animSpeed,"",function(){t.trigger("nivo:animFinished")})},100+l)}else{setTimeout(function(){n.animate({width:i,opacity:"1.0"},r.animSpeed)},100+l)}l+=50;c++})}else if(o==="fade"){h(t,r,s);m=e(".nivo-slice:first",t);m.css({width:t.width()+"px"});m.animate({opacity:"1.0"},r.animSpeed*2,"",function(){t.trigger("nivo:animFinished")})}else if(o==="slideInRight"){h(t,r,s);m=e(".nivo-slice:first",t);m.css({width:"0px",opacity:"1"});m.animate({width:t.width()+"px"},r.animSpeed*2,"",function(){t.trigger("nivo:animFinished")})}else if(o==="slideInLeft"){h(t,r,s);m=e(".nivo-slice:first",t);m.css({width:"0px",opacity:"1",left:"",right:"0px"});m.animate({width:t.width()+"px"},r.animSpeed*2,"",function(){m.css({left:"0px",right:""});t.trigger("nivo:animFinished")})}else if(o==="boxRandom"){p(t,r,s);g=r.boxCols*r.boxRows;c=0;l=0;y=v(e(".nivo-box",t));y.each(function(){var n=e(this);if(c===g-1){setTimeout(function(){n.animate({opacity:"1"},r.animSpeed,"",function(){t.trigger("nivo:animFinished")})},100+l)}else{setTimeout(function(){n.animate({opacity:"1"},r.animSpeed)},100+l)}l+=20;c++})}else if(o==="boxRain"||o==="boxRainReverse"||o==="boxRainGrow"||o==="boxRainGrowReverse"){p(t,r,s);g=r.boxCols*r.boxRows;c=0;l=0;var w=0;var E=0;var S=[];S[w]=[];y=e(".nivo-box",t);if(o==="boxRainReverse"||o==="boxRainGrowReverse"){y=e(".nivo-box",t)._reverse()}y.each(function(){S[w][E]=e(this);E++;if(E===r.boxCols){w++;E=0;S[w]=[]}});for(var x=0;x<r.boxCols*2;x++){var T=x;for(var N=0;N<r.boxRows;N++){if(T>=0&&T<r.boxCols){(function(n,i,s,u,a){var f=e(S[n][i]);var l=f.width();var c=f.height();if(o==="boxRainGrow"||o==="boxRainGrowReverse"){f.width(0).height(0)}if(u===a-1){setTimeout(function(){f.animate({opacity:"1",width:l,height:c},r.animSpeed/1.3,"",function(){t.trigger("nivo:animFinished")})},100+s)}else{setTimeout(function(){f.animate({opacity:"1",width:l,height:c},r.animSpeed/1.3)},100+s)}})(N,T,l,c,g);c++}T--}l+=100}}};var v=function(e){for(var t,n,r=e.length;r;t=parseInt(Math.random()*r,10),n=e[--r],e[r]=e[t],e[t]=n);return e};var m=function(e){if(this.console&&typeof console.log!=="undefined"){console.log(e)}};this.stop=function(){if(!e(t).data("nivo:vars").stop){e(t).data("nivo:vars").stop=true;m("Stop Slider")}};this.start=function(){if(e(t).data("nivo:vars").stop){e(t).data("nivo:vars").stop=false;m("Start Slider")}};r.afterLoad.call(this);return this};e.fn.nivoSlider=function(n){return this.each(function(r,i){var s=e(this);if(s.data("nivoslider")){return s.data("nivoslider")}var o=new t(this,n);s.data("nivoslider",o)})};e.fn.nivoSlider.defaults={effect:"random",slices:15,boxCols:8,boxRows:4,animSpeed:500,pauseTime:3e3,startSlide:0,directionNav:true,controlNav:true,controlNavThumbs:false,pauseOnHover:true,manualAdvance:false,prevText:"Prev",nextText:"Next",randomStart:false,beforeChange:function(){},afterChange:function(){},slideshowEnd:function(){},lastSlide:function(){},afterLoad:function(){}};e.fn._reverse=[].reverse})(jQuery) |