/* --------------------------------------------------------------------------------- file-start: js/lib/es5-shim.min.js */ (function(definition){if(typeof define=="function"){define(definition)}else if(typeof YUI=="function"){YUI.add("es5",definition)}else{definition()}})(function(){function Empty(){}if(!Function.prototype.bind){Function.prototype.bind=function bind(that){var target=this;if(typeof target!="function"){throw new TypeError("Function.prototype.bind called on incompatible "+target)}var args=slice.call(arguments,1);var bound=function(){if(this instanceof bound){var result=target.apply(this,args.concat(slice.call(arguments)));if(Object(result)===result){return result}return this}else{return target.apply(that,args.concat(slice.call(arguments)))}};if(target.prototype){Empty.prototype=target.prototype;bound.prototype=new Empty;Empty.prototype=null}return bound}}var call=Function.prototype.call;var prototypeOfArray=Array.prototype;var prototypeOfObject=Object.prototype;var slice=prototypeOfArray.slice;var _toString=call.bind(prototypeOfObject.toString);var owns=call.bind(prototypeOfObject.hasOwnProperty);var defineGetter;var defineSetter;var lookupGetter;var lookupSetter;var supportsAccessors;if(supportsAccessors=owns(prototypeOfObject,"__defineGetter__")){defineGetter=call.bind(prototypeOfObject.__defineGetter__);defineSetter=call.bind(prototypeOfObject.__defineSetter__);lookupGetter=call.bind(prototypeOfObject.__lookupGetter__);lookupSetter=call.bind(prototypeOfObject.__lookupSetter__)}if([1,2].splice(0).length!=2){var array_splice=Array.prototype.splice;Array.prototype.splice=function(start,deleteCount){if(!arguments.length){return[]}else{return array_splice.apply(this,[start===void 0?0:start,deleteCount===void 0?this.length-start:deleteCount].concat(slice.call(arguments,2)))}}}if([].unshift(0)!=1){var array_unshift=Array.prototype.unshift;Array.prototype.unshift=function(){array_unshift.apply(this,arguments);return this.length}}if(!Array.isArray){Array.isArray=function isArray(obj){return _toString(obj)=="[object Array]"}}var boxedString=Object("a"),splitString=boxedString[0]!="a"||!(0 in boxedString);if(!Array.prototype.forEach){Array.prototype.forEach=function forEach(fun){var object=toObject(this),self=splitString&&_toString(this)=="[object String]"?this.split(""):object,thisp=arguments[1],i=-1,length=self.length>>>0;if(_toString(fun)!="[object Function]"){throw new TypeError}while(++i>>0,result=Array(length),thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i>>0,result=[],value,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i>>0,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i>>0,thisp=arguments[1];if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}for(var i=0;i>>0;if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}if(!length&&arguments.length==1){throw new TypeError("reduce of empty array with no initial value")}var i=0;var result;if(arguments.length>=2){result=arguments[1]}else{do{if(i in self){result=self[i++];break}if(++i>=length){throw new TypeError("reduce of empty array with no initial value")}}while(true)}for(;i>>0;if(_toString(fun)!="[object Function]"){throw new TypeError(fun+" is not a function")}if(!length&&arguments.length==1){throw new TypeError("reduceRight of empty array with no initial value")}var result,i=length-1;if(arguments.length>=2){result=arguments[1]}else{do{if(i in self){result=self[i--];break}if(--i<0){throw new TypeError("reduceRight of empty array with no initial value")}}while(true)}do{if(i in this){result=fun.call(void 0,result,self[i],i,object)}}while(i--);return result}}if(!Array.prototype.indexOf||[0,1].indexOf(1,2)!=-1){Array.prototype.indexOf=function indexOf(sought){var self=splitString&&_toString(this)=="[object String]"?this.split(""):toObject(this),length=self.length>>>0;if(!length){return-1}var i=0;if(arguments.length>1){i=toInteger(arguments[1])}i=i>=0?i:Math.max(0,length+i);for(;i>>0;if(!length){return-1}var i=length-1;if(arguments.length>1){i=Math.min(i,toInteger(arguments[1]))}i=i>=0?i:length-Math.abs(i);for(;i>=0;i--){if(i in self&&sought===self[i]){return i}}return-1}}if(!Object.keys){var hasDontEnumBug=true,dontEnums=["toString","toLocaleString","valueOf","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","constructor"],dontEnumsLength=dontEnums.length;for(var key in{toString:null}){hasDontEnumBug=false}Object.keys=function keys(object){if(typeof object!="object"&&typeof object!="function"||object===null){throw new TypeError("Object.keys called on a non-object")}var keys=[];for(var name in object){if(owns(object,name)){keys.push(name)}}if(hasDontEnumBug){for(var i=0,ii=dontEnumsLength;i9999?"+":"")+("00000"+Math.abs(year)).slice(0<=year&&year<=9999?-4:-6);length=result.length;while(length--){value=result[length];if(value<10){result[length]="0"+value}}return year+"-"+result.slice(0,2).join("-")+"T"+result.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"}}var dateToJSONIsSupported=false;try{dateToJSONIsSupported=Date.prototype.toJSON&&new Date(NaN).toJSON()===null&&new Date(negativeDate).toJSON().indexOf(negativeYearString)!==-1&&Date.prototype.toJSON.call({toISOString:function(){return true}})}catch(e){}if(!dateToJSONIsSupported){Date.prototype.toJSON=function toJSON(key){var o=Object(this),tv=toPrimitive(o),toISO;if(typeof tv==="number"&&!isFinite(tv)){return null}toISO=o.toISOString;if(typeof toISO!="function"){throw new TypeError("toISOString property is not callable")}return toISO.call(o)}}if(!Date.parse||"Date.parse is buggy"){Date=function(NativeDate){function Date(Y,M,D,h,m,s,ms){var length=arguments.length;if(this instanceof NativeDate){var date=length==1&&String(Y)===Y?new NativeDate(Date.parse(Y)):length>=7?new NativeDate(Y,M,D,h,m,s,ms):length>=6?new NativeDate(Y,M,D,h,m,s):length>=5?new NativeDate(Y,M,D,h,m):length>=4?new NativeDate(Y,M,D,h):length>=3?new NativeDate(Y,M,D):length>=2?new NativeDate(Y,M):length>=1?new NativeDate(Y):new NativeDate;date.constructor=Date;return date}return NativeDate.apply(this,arguments)}var isoDateExpression=new RegExp("^"+"(\\d{4}|[+-]\\d{6})"+"(?:-(\\d{2})"+"(?:-(\\d{2})"+"(?:"+"T(\\d{2})"+":(\\d{2})"+"(?:"+":(\\d{2})"+"(?:\\.(\\d{3}))?"+")?"+"("+"Z|"+"(?:"+"([-+])"+"(\\d{2})"+":(\\d{2})"+")"+")?)?)?)?"+"$");var months=[0,31,59,90,120,151,181,212,243,273,304,334,365];function dayFromMonth(year,month){var t=month>1?1:0;return months[month]+Math.floor((year-1969+t)/4)-Math.floor((year-1901+t)/100)+Math.floor((year-1601+t)/400)+365*(year-1970)}for(var key in NativeDate){Date[key]=NativeDate[key]}Date.now=NativeDate.now;Date.UTC=NativeDate.UTC;Date.prototype=NativeDate.prototype;Date.prototype.constructor=Date;Date.parse=function parse(string){var match=isoDateExpression.exec(string);if(match){var year=Number(match[1]),month=Number(match[2]||1)-1,day=Number(match[3]||1)-1,hour=Number(match[4]||0),minute=Number(match[5]||0),second=Number(match[6]||0),millisecond=Number(match[7]||0),offset=!match[4]||match[8]?0:Number(new NativeDate(1970,0)),signOffset=match[9]==="-"?1:-1,hourOffset=Number(match[10]||0),minuteOffset=Number(match[11]||0),result;if(hour<(minute>0||second>0||millisecond>0?24:25)&&minute<60&&second<60&&millisecond<1e3&&month>-1&&month<12&&hourOffset<24&&minuteOffset<60&&day>-1&&day0||-1)*Math.floor(Math.abs(n))}return n}function isPrimitive(input){var type=typeof input;return input===null||type==="undefined"||type==="boolean"||type==="number"||type==="string"}function toPrimitive(input){var val,valueOf,toString;if(isPrimitive(input)){return input}valueOf=input.valueOf;if(typeof valueOf==="function"){val=valueOf.call(input);if(isPrimitive(val)){return val}}toString=input.toString;if(typeof toString==="function"){val=toString.call(input);if(isPrimitive(val)){return val}}throw new TypeError}var toObject=function(o){if(o==null){throw new TypeError("can't convert "+o+" to object")}return Object(o)}});; /* file-end: js/lib/es5-shim.min.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/lib/json3.min.js */ /*! JSON v3.2.5 | http://bestiejs.github.io/json3 | Copyright 2012-2013, Kit Cambridge | http://kit.mit-license.org */ ;(function(){var o=!0,w=null; (function(B){function v(a){if("bug-string-char-index"==a)return"a"!="a"[0];var f,c="json"==a;if(c||"json-stringify"==a||"json-parse"==a){if("json-stringify"==a||c){var d=k.stringify,b="function"==typeof d&&l;if(b){(f=function(){return 1}).toJSON=f;try{b="0"===d(0)&&"0"===d(new Number)&&'""'==d(new String)&&d(m)===r&&d(r)===r&&d()===r&&"1"===d(f)&&"[1]"==d([f])&&"[null]"==d([r])&&"null"==d(w)&&"[null,null,null]"==d([r,m,w])&&'{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'==d({a:[f,o,!1,w,"\x00\u0008\n\u000c\r\t"]})&& "1"===d(w,f)&&"[\n 1,\n 2\n]"==d([1,2],w,1)&&'"-271821-04-20T00:00:00.000Z"'==d(new Date(-864E13))&&'"+275760-09-13T00:00:00.000Z"'==d(new Date(864E13))&&'"-000001-01-01T00:00:00.000Z"'==d(new Date(-621987552E5))&&'"1969-12-31T23:59:59.999Z"'==d(new Date(-1))}catch(n){b=!1}}if(!c)return b}if("json-parse"==a||c){a=k.parse;if("function"==typeof a)try{if(0===a("0")&&!a(!1)){f=a('{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}');var e=5==f.a.length&&1===f.a[0];if(e){try{e=!a('"\t"')}catch(g){}if(e)try{e= 1!==a("01")}catch(i){}}}}catch(O){e=!1}if(!c)return e}return b&&e}}var m={}.toString,p,C,r,D=typeof define==="function"&&define.amd,k="object"==typeof exports&&exports;k||D?"object"==typeof JSON&&JSON?k?(k.stringify=JSON.stringify,k.parse=JSON.parse):k=JSON:D&&(k=B.JSON={}):k=B.JSON||(B.JSON={});var l=new Date(-3509827334573292);try{l=-109252==l.getUTCFullYear()&&0===l.getUTCMonth()&&1===l.getUTCDate()&&10==l.getUTCHours()&&37==l.getUTCMinutes()&&6==l.getUTCSeconds()&&708==l.getUTCMilliseconds()}catch(P){}if(!v("json")){var s= v("bug-string-char-index");if(!l)var t=Math.floor,J=[0,31,59,90,120,151,181,212,243,273,304,334],z=function(a,f){return J[f]+365*(a-1970)+t((a-1969+(f=+(f>1)))/4)-t((a-1901+f)/100)+t((a-1601+f)/400)};if(!(p={}.hasOwnProperty))p=function(a){var f={},c;if((f.__proto__=w,f.__proto__={toString:1},f).toString!=m)p=function(a){var f=this.__proto__,a=a in(this.__proto__=w,this);this.__proto__=f;return a};else{c=f.constructor;p=function(a){var f=(this.constructor||c).prototype;return a in this&&!(a in f&& this[a]===f[a])}}f=w;return p.call(this,a)};var K={"boolean":1,number:1,string:1,undefined:1};C=function(a,f){var c=0,b,h,n;(b=function(){this.valueOf=0}).prototype.valueOf=0;h=new b;for(n in h)p.call(h,n)&&c++;b=h=w;if(c)c=c==2?function(a,f){var c={},b=m.call(a)=="[object Function]",d;for(d in a)!(b&&d=="prototype")&&!p.call(c,d)&&(c[d]=1)&&p.call(a,d)&&f(d)}:function(a,f){var c=m.call(a)=="[object Function]",b,d;for(b in a)!(c&&b=="prototype")&&p.call(a,b)&&!(d=b==="constructor")&&f(b);(d||p.call(a, b="constructor"))&&f(b)};else{h=["valueOf","toString","toLocaleString","propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];c=function(a,f){var c=m.call(a)=="[object Function]",b,d;if(d=!c)if(d=typeof a.constructor!="function"){d=typeof a.hasOwnProperty;d=d=="object"?!!a.hasOwnProperty:!K[d]}d=d?a.hasOwnProperty:p;for(b in a)!(c&&b=="prototype")&&d.call(a,b)&&f(b);for(c=h.length;b=h[--c];d.call(a,b)&&f(b));}}c(a,f)};if(!v("json-stringify")){var L={92:"\\\\",34:'\\"',8:"\\b",12:"\\f", 10:"\\n",13:"\\r",9:"\\t"},u=function(a,f){return("000000"+(f||0)).slice(-a)},G=function(a){var f='"',b=0,d=a.length,h=d>10&&s,n;for(h&&(n=a.split(""));b-1/0&&g<1/0){if(z){k=t(g/864E5);for(i=t(k/365.2425)+1970-1;z(i+1,0)<=k;i++);for(j=t((k-z(i,0))/30.42);z(i,j+1)<=k;j++);k=1+k-z(i,j);l=(g%864E5+864E5)%864E5;q=t(l/36E5)%24;s=t(l/6E4)%60;v=t(l/1E3)%60;l=l%1E3}else{i=g.getUTCFullYear();j=g.getUTCMonth();k=g.getUTCDate();q=g.getUTCHours();s=g.getUTCMinutes();v=g.getUTCSeconds();l=g.getUTCMilliseconds()}g=(i<=0||i>=1E4?(i<0?"-":"+")+u(6,i<0?-i:i):u(4,i))+"-"+u(2,j+1)+"-"+u(2,k)+"T"+u(2,q)+":"+u(2,s)+":"+u(2,v)+"."+u(3,l)+"Z"}else g= w;else if(typeof g.toJSON=="function"&&(i!="[object Number]"&&i!="[object String]"&&i!="[object Array]"||p.call(g,"toJSON")))g=g.toJSON(a)}c&&(g=c.call(b,a,g));if(g===w)return"null";i=m.call(g);if(i=="[object Boolean]")return""+g;if(i=="[object Number]")return g>-1/0&&g<1/0?""+g:"null";if(i=="[object String]")return G(""+g);if(typeof g=="object"){for(a=e.length;a--;)if(e[a]===g)throw TypeError();e.push(g);x=[];b=n;n=n+h;if(i=="[object Array]"){j=0;for(a=g.length;j0){d="";for(c>10&&(c=10);d.length=48&&e<=57||e>=97&&e<=102||e>=65&&e<=70||j()}c=c+M("0x"+a.slice(d,b));break;default:j()}}else{if(e==34)break;e=a.charCodeAt(b);for(d=b;e>=32&&e!=92&&e!=34;)e=a.charCodeAt(++b); c=c+a.slice(d,b)}}if(a.charCodeAt(b)==34){b++;return c}j();default:d=b;if(e==45){k=o;e=a.charCodeAt(++b)}if(e>=48&&e<=57){for(e==48&&(e=a.charCodeAt(b+1),e>=48&&e<=57)&&j();b=48&&e<=57);b++);if(a.charCodeAt(b)==46){for(h=++b;h=48&&e<=57);h++);h==b&&j();b=h}e=a.charCodeAt(b);if(e==101||e==69){e=a.charCodeAt(++b);(e==43||e==45)&&b++;for(h=b;h=48&&e<=57);h++);h==b&&j();b=h}return+a.slice(d,b)}k&&j();if(a.slice(b,b+4)=="true"){b= b+4;return o}if(a.slice(b,b+5)=="false"){b=b+5;return false}if(a.slice(b,b+4)=="null"){b=b+4;return w}j()}}return"$"},F=function(a){var b,c;a=="$"&&j();if(typeof a=="string"){if((s?a.charAt(0):a[0])=="@")return a.slice(1);if(a=="["){for(b=[];;c||(c=o)){a=q();if(a=="]")break;if(c)if(a==","){a=q();a=="]"&&j()}else j();a==","&&j();b.push(F(a))}return b}if(a=="{"){for(b={};;c||(c=o)){a=q();if(a=="}")break;if(c)if(a==","){a=q();a=="}"&&j()}else j();(a==","||typeof a!="string"||(s?a.charAt(0):a[0])!="@"|| q()!=":")&&j();b[a.slice(1)]=F(q())}return b}j()}return a},I=function(a,b,c){c=H(a,b,c);c===r?delete a[b]:a[b]=c},H=function(a,b,c){var d=a[b],h;if(typeof d=="object"&&d)if(m.call(d)=="[object Array]")for(h=d.length;h--;)I(d,h,c);else C(d,function(a){I(d,a,c)});return c.call(a,b,d)};k.parse=function(a,f){var c,d;b=0;A=""+a;c=F(q());q()!="$"&&j();b=A=w;return f&&m.call(f)=="[object Function]"?H((d={},d[""]=c,d),"",f):c}}}D&&define(function(){return k})})(this); }());; /* file-end: js/lib/json3.min.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/lib/jquery-1.8.3.min.js */ /*! jQuery v1.8.3 jquery.com | jquery.org/license */ (function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
t
",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
","
"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window);; /* file-end: js/lib/jquery-1.8.3.min.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/general.js */ /* --------------------------------------------------------------------------------- file-start: js/core/lj.js */ /*global Site */ ;(function() { /** * @namespace LJ LiveJournal utility objects */ var LJ = window.LJ = window.LJ || {}; /** * Define a namespace. * * @param {string} path The String with namespace to be created. * @param {Object=} top An optional object. If set then the namespace will be built relative to it. Defaults to the window. */ LJ.define = function(path, top) { var ns = path.split('.'), name; top = top || window; while (name = ns.shift()) { top[name] = top[name] || {}; top = top[name]; } }; /** * Insert script in the document asynchronously. * * @param {String} url Url of the script * @param {Object=} params Data to apply to the scipt node object, e.g. async, text. * @param {Node=} parent If exists, script tag will be inserted in this node or before the * first script tag otherwise. * * @return {jQuery.Deferred} jQuery deferred object that will be resolved when * script loaded. */ LJ.injectScript = function(url, params, parent) { var deferred = jQuery.Deferred(), defaults = { async: true }, script, prop; script = document.createElement('script'); script.src = url; if (params && jQuery.type(params) === 'object') { params = jQuery.extend({}, defaults, params); for (prop in params) { if ( params.hasOwnProperty(prop) ) { script[prop] = params[prop]; } } } if (script.readyState) { // IE script.onreadystatechange = function () { if ( script.readyState === 'loaded' || script.readyState === 'complete' ) { script.onreadystatechange = null; deferred.resolve(); } }; } else { // Others script.onload = function(){ deferred.resolve(); }; } if (parent) { parent.appendChild(script); } else { parent = document.getElementsByTagName('script')[0]; parent.parentNode.insertBefore(script, parent); } return deferred; }; /* * Inject stylesheet or plain css into page. * * @param {string} css Plain css or stylesheet filename to inject * @param {global} _window Window object */ LJ.injectStyle = function(css, _window) { var w = _window || window, head = w.document.getElementsByTagName('head')[0]; // transform relative paths to absolute css = css.replace(/url\(([^)]*)\)/g, function(_, match) { var prefix = ''; if (!/data\:/.test(match)) { prefix = LJ.get('statprefix'); if (match.charAt(0) !== '/') { prefix = prefix + '/'; } } return 'url(' + prefix + match + ')'; }); if (/\.css$/.test(css)) { var link = w.document.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = css; head.appendChild(link); return; } var style = w.document.createElement('style'); style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(w.document.createTextNode(css)); } head.appendChild(style); }; /** * Get variable that has been provided by server * * @method get * @param {String} name Variable name, e.g. 'colorpicker.color' * @return {*} Variable value */ LJ.get = function (name) { var local = get(Site.page, name); return (typeof local === 'undefined') ? get(Site, name) : local; }; /** * @deprecated * It is possibly used by partners comments and external scripts */ LJ.pageVar = LJ.get; /** * Get variable from an object * * @param {Object} obj Root object * @param {String} name Name of variable, e.g. 'hello.world' * @return {*} Page variable or `undefined` if not found * * @example * // retrieves window.Site.hello.world or undefined if not found * get(window.Site, 'hello.world'); */ function get(obj, name) { var namespaces = name.split('.'), current = namespaces.shift(), result = obj; if (typeof obj !== 'object') { throw new TypeError('You should provide object as a root.'); } while (typeof current !== 'undefined') { // exit if result is not an object if (typeof result !== 'object' || result === null ) { return; } // return if result has no property if ( !result.hasOwnProperty(current) ) { return; } result = result[current]; current = namespaces.shift(); } return result; } }()); ; /* file-end: js/core/lj.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/function.js */ ;(function () { 'use strict'; LJ.define('LJ.Function'); /* * Functional style getter. * * @example * [ { name: 'John' }, { name: 'Mary' } ].map(LJ.Function.get('name')); * // => ['John', 'Mary'] * * @param {String} prop Property * @return {Function} Getter function */ LJ.Function.get = function(prop) { return function(obj) { return obj[prop]; }; }; /* * Functional style setter. * * @param {String} prop Property * @param {*} Value to set * @return {Function} Setter function * * @example * var users = [ { name: 'John', age: 13 }, { name: 'Mary', age: 25 } ] * * users.forEach( LJ.Function.set('age', 30) ); * // users => [ { name: 'John', age: 30 }, { name: 'Mary', age: 30 } ] */ LJ.Function.set = function (prop, value) { return function (obj) { obj[prop] = value; return obj; }; }; /** * Create function that will call the target function * at most once per every delay seconds. The signature and tests * are taken from underscore project. * * @param {Function} func The function to call. * @param {Number} Delay between the calls in ms. */ LJ.Function.throttle = function(func, delay) { var ctx, args, timer, shouldBeCalled = false; return function() { ctx = this; args = arguments; var callFunc = function() { timer = null; if (!shouldBeCalled) { return; } shouldBeCalled = false; timer = setTimeout(callFunc, delay); var ret = func.apply(ctx, args); return ret; }; shouldBeCalled = true; if (timer) { return; } return callFunc(); }; }; /** * Returns a function, that, as long as it continues to be invoked, will not * be triggered. The function will be called after it stops being called for * N milliseconds. If `immediate` is passed, trigger the function on the * leading edge, instead of the trailing. * * Notice: signature and documentation has been taken from `underscore` project * * @param {Function} func Function to be called * @param {Number} wait Amount of milliseconds to wait before invocation * @param {Boolean} [immediate] Invocation edge * @return {Function} Debounced function `func` */ LJ.Function.debounce = function(func, wait, immediate) { var timeout, result; return function () { var context = this, args = arguments, later, callNow = immediate && !timeout; later = function() { timeout = null; if ( !immediate ) { result = func.apply(context, args); } }; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); } return result; }; }; /** * Create function that will call target function at most once * per every delay. Arguments are queued and when delay ends * function is called with last supplied arguments set. Optionally * arguments queue can be preserved on call, so all sheduled will be done. * * @param {Function} f The function to call. * @param {Number} delay Delay between the calls in ms. * @param {Boolean} preserve Run all queued sequentially */ LJ.Function.threshold = function(f, delay, preserve) { var queue = [], batchSize, batch, lock = false, callback = function () { var caller = this; if (lock || !queue.length) { return; } while (queue.length) { lock = true; if (preserve) { f.apply(caller, queue.shift()); } else { f.apply(caller, queue.pop()); queue = []; } if (batch && --batch) { lock = false; continue; } setTimeout(function () { lock = false; batch = batchSize; callback.call(caller); }, delay); break; } }, threshold = function () { queue.push([].slice.call(arguments)); callback.call(this); }; threshold.resetQueue = function () { queue = []; }; threshold.batch = function (size) { if (size !== undefined) { batchSize = size >>> 0; if (!lock) { batch = batchSize; } } }; return threshold; }; })(); ; /* file-end: js/core/function.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/console.js */ /** * IE console object dummy functions */ (function (window) { 'use strict'; var LJ = window.LJ = window.LJ || {}; var methods = ['log', 'dir', 'warn', 'error', 'assert', 'count', 'info', 'time', 'timeEnd', 'debug'], noop = function () {}, i, method; if (!window.console) { window.console = {}; } for (i = 0; i < methods.length; i++) { method = methods[i]; if (!console[method]) { console[method] = noop; } } if (typeof console !== 'undefined') { LJ.console = console; } }(this)); ; /* file-end: js/core/console.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/support.js */ /** * @namespace LJ.Support Feature detections and other support features */ (function ($) { 'use strict'; LJ.define('LJ.Support'); /** * Browser detection object * http://api.jquery.com/jQuery.browser/ */ LJ.Support.browser = (function() { /** * almost direct copy from jQuery 1.8.3, * expect 'jQuery.uaMatch' changed to 'uaMatch' */ /* copy start */ var matched, browser; // Use of jQuery.browser is frowned upon. // More details: http://api.jquery.com/jQuery.browser // jQuery.uaMatch maintained for back-compat var uaMatch = function( ua ) { ua = ua.toLowerCase(); var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || /(webkit)[ \/]([\w.]+)/.exec( ua ) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || /(msie) ([\w.]+)/.exec( ua ) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || []; return { browser: match[ 1 ] || "", version: match[ 2 ] || "0" }; }; matched = uaMatch( navigator.userAgent ); browser = {}; if ( matched.browser ) { browser[ matched.browser ] = true; browser.version = matched.version; } // Chrome is Webkit, but Webkit is also Safari. if ( browser.chrome ) { browser.webkit = true; } else if ( browser.webkit ) { browser.safari = true; } /* copy end */ return browser; }()); /** * Local storage support */ try { // Firefox fires exception when cookie storage options are set to 'always ask' LJ.Support.localStorage = !!window.localStorage; } catch (error) { LJ.Support.localStorage = false; } /** * CORS support */ LJ.Support.cors = window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest(); /* Geolocation */ LJ.Support.geoLocation = 'geolocation' in navigator; /* Incomplete implementation from modernizr */ LJ.Support.touch = Boolean(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch); /** * History API */ LJ.Support.history = !!window.history.pushState; LJ.Support.isMac = navigator.userAgent.indexOf('Mac') !== -1; /** * Check if site if browsed by mobile device * */ LJ.Support.isMobile = (function() { var agent = navigator.userAgent || navigator.vendor || window.opera, isMobile = /android.+(mobile|transformer)|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|opera tablet|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(agent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(agent.substr(0, 4)); return function () { return isMobile; }; })(); }(jQuery)); ; /* file-end: js/core/support.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/flags.js */ /** * @author Valeriy Vasin (valeriy.vasin@sup.com) * @description Enable / disable javascript features for the project * * @example * // do something if feature is enabled * if ( LJ.Flags.isEnabled('subscriptions') ) { * console.log('Subscription feature code goes here'); * } * * // exit if feature is disabled * if ( LJ.Flags.isDisabled('subscriptions') ) { * console.error('feature is under development'); * return; * } * * // get flag value for convinience and more flexibility * if ( LJ.Flags.value('subscriptions') === 'stage2' ) { * console.log('stage 2 goes here'); * } */ ;(function () { 'use strict'; var LJ = window.LJ = window.LJ || {}; // Feature states: // - true: feature is enabled // - false: feature is disabled // - other: feature state, e.g. 'stage2'. Feature is disabled. // // If feature hasn't been listed inside the object - it's enabled // Notice: when feature is ready you should remove checks everywhere // and remove flag from this object LJ.Flags = { // Perl: migrated_to_friends_and_subscriptions friendsAndSubscriptions: false }; // It's strongly recommended to access flags though this methods /** * Checks if feature is enabled * @param {String} name Feature name * @return {Boolean} Result of the check */ LJ.Flags.isEnabled = function (name) { var value = LJ.Flags[name]; return value === true || typeof value === 'undefined'; }; /** * Check if feature is diabled * @param {String} name Feature name * @return {Boolean} Result of the check */ LJ.Flags.isDisabled = function (name) { return !LJ.Flags.isEnabled(name); }; /** * Get current feature flag value * @param {String} name Feature name * @return {*} Feature value */ LJ.Flags.value = function (name) { return LJ.Flags[name]; }; }()); ; /* file-end: js/core/flags.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/log.js */ ;(function() { 'use strict'; window.LJ = window.LJ || {}; var logDomain = 'http://njs.services.livejournal.com/'; window.onerror = function(msg, url, line) { var errorObject = { 'msg' : msg, 'url' : url, 'line' : line, 'where' : String(window.location) }; if (msg) { return; } if (Site.remoteUser) { errorObject.user = Site.remoteUser; } var data = [], key, src, beacon; // Chrome doesn't support crossdomain error logging // http://blog.errorception.com/2012/12/catching-cross-domain-js-errors.html var useless = [ 'port object', 'extension', 'Script error' ].some(function(block) { return msg.indexOf(block) !== -1; }); if (useless || !errorObject.url) { return false; } for (key in errorObject) { data.push(key + '=' + encodeURIComponent(errorObject[key])); } src = logDomain + 'log?' + data.join('&'); beacon = new Image(); beacon.src = src; return false; }; // backwards compatibility, will be removed soon if (typeof LJ.console.log === 'function') { LJ.info = console.log.bind(console); LJ.warn = console.log.bind(console); LJ.error = console.log.bind(console); } else { // IE8 case, see 'callable object' LJ.info = console.log; LJ.warn = console.log; LJ.error = console.log; } })(); ; /* file-end: js/core/log.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/storage.js */ /*! * jQuery storage plugin. * @author dmitry.petrov@sup.com (Dmitry Petrov) * @author anazarov@sup.com (Alexander Nazarov) * * Plugin uses local storage if availible and falls back to IE userData mechanism. * * @TODO: add cookie storage provider * * Plugin supports IE5.5+, Firefox 3.5+, Opera 10.5+, Google Chrome, Apple Safari 4+ */ (function ($) { 'use strict'; function stringify(val) { return JSON.stringify(val); } function parse(val) { try { return JSON.parse(val); } catch (error) { return val; } } /** * @namespace LJ.Storage */ LJ.Storage = (function () { /** * Every provider should have the same interface and provide isSupported function to * test if it's applicable in current browser */ var userDataProvider = function () { var storageId = 'jQueryStorageProvider', storageName = '__jQueryStorage__', node; function _create () { node = $('') .attr('id', storageId) .css('display', 'none') .appendTo($('head')) .get(0); /* http://msdn.microsoft.com/en-us/library/ms533015%28v=vs.85%29.aspx */ node.addBehavior('#default#userdata'); node.load(storageName); } //LJSUP-11805: IE does not allow special symbols as attribute names function _normalize (name) { return name.replace(/[^0-9a-z_\-]/ig, '_'); } _create(); return { provider: 'data', /** * Set item in the storage * * @param {String} name * @param {String} val * @returns {Boolean} True if item was set */ setItem: function (name, val) { node.setAttribute(_normalize(name), stringify(val)); node.save(storageName); return true; }, /** * Get item from the storage. * * @param {String} Item name. * @return {Object|String} Item value or null it it does not exist. */ getItem: function (name) { return parse(node.getAttribute(_normalize(name))); }, /** * Remove item from the storage * * @param @{String} Item name. */ removeItem: function (name) { node.removeAttribute(name); node.save(storageName); }, /** * Clear storage */ clear: function () { var attrs = node.attributes, i, l; for (i = 0, l = attrs.length; i < l; i++) { if (attrs[i].toLowerCase() === 'id') { continue; } node.removeAttribute(attrs[i]); } node.save(storageName); } }; }; userDataProvider.isSupported = function() { return $.browser.msie && (+$.browser.version) > 5; }; var localStorageProvider = function() { function _create() { } _create(); return { provider: 'storage', setItem: function (name, val) { try { localStorage.setItem(name, stringify(val)); return true; } catch (error) { return false; } }, getItem: function (name) { return parse(localStorage.getItem(name)); }, removeItem: function (name) { localStorage.removeItem(name); }, clear: function () { localStorage.clear(); } }; }; localStorageProvider.isSupported = function() { return LJ.Support.localStorage; }; var simpleProvider = function() { var store; function _create() { store = {}; } _create(); return { provider: 'simple', setItem: function (name, val) { store.name = val; return true; }, getItem: function (name) { if (store.hasOwnProperty(name)) { return store.name; } else { return null; } }, removeItem: function (name) { delete store.name; }, clear: function () { store = {}; } }; }; simpleProvider.isSupported = function() { return true; }; //currently all transports should be implemented inside plugin. var providers = [localStorageProvider, userDataProvider, simpleProvider], i, l; for (i = 0, l = providers.length; i < l; ++i ) { if (providers[i].isSupported()) { return providers[i](); } } //We should never reach this point. }()); }(jQuery)); ; /* file-end: js/core/storage.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/event.js */ /** * Global PubSub system * * @author Valeriy Vasin (valeriy.vasin@sup.com) * * @example * // register handler for event * LJ.Event.on('myevent', fn); * * // trigger event with three arguments * LJ.Event.trigger('myevent', 1, 2, 3); */ ;(function (global) { 'use strict'; LJ.define('LJ.Event'); LJ.Event.on = on; LJ.Event.once = once; LJ.Event.trigger = trigger; LJ.Event.off = off; /** * Hooks storage */ var hooks = {}; /** * Register hook handler * * @param {String} hook Hook name * @param {Function} func Hook function to register * @param {Object} [context] Function invocation context */ function on(hook, func, context) { if (typeof hook !== 'string' || typeof func !== 'function') { throw new Error('Provide correct hook name or handler.'); } if ( !hooks.hasOwnProperty(hook) ) { hooks[hook] = []; } hooks[hook].push({ fn: func, context: context }); } /** * Register hook that will be removed after execution * * @param {String} hook Hook name * @param {Function} func Hook function to register * @param {Object} [context] Function invocation context */ function once(hook, func, context) { var fn = function () { off(hook, fn); return func.apply(this, arguments); }; on(hook, fn, context); } /** * Run registered hooks * @param {String} hook Hook name */ function trigger(hook /**, args*/) { var hookFuncs = hooks[hook], args = null, result = null; // nothing has been registered for this hook if ( !Array.isArray( hookFuncs ) || hookFuncs.length === 0 ) { return; } // arguments to pass for the hook args = Array.prototype.slice.call(arguments, 1); hookFuncs.forEach(function (hook) { var context = hook.context; result = hook.fn.apply(typeof context === 'undefined' ? global : context, args); }); return result; } /** * Remove hook functionality * @param {String} hook Hook name * @param {Function} [func] Hook function to remove */ function off(hook, func) { if (typeof hook !== 'string') { throw new Error('Hook name should be provided.'); } // if no hooks has been registered yet if ( !hooks.hasOwnProperty(hook) ) { return; } if (typeof func === 'function') { hooks[hook] = hooks[hook].filter(function (hook) { return hook.fn !== func; }); } else { hooks[hook] = []; } } }(this)); ; /* file-end: js/core/event.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/lj.api.js */ (function ($) { 'use strict'; /** * TODO: * * If this api will go outside of livejournal.com it should get rid of all dependencies * from jquery.js and basic.js and should require only a few libs from LJ namespace through LJ.require * to handle everything. */ /** * @namespace LJ.Api * @requires basic.js, jquery.js, livejournal.js, jquery/jquery.xdomainrequest.js, lj.postmessage.js * @description Api provides an unified method to handle communications with the server. * @author dmitry.petrov@sup.com (Dmitry Petrov), anazarov@sup.com (Alexander Nazarov) */ LJ.define('LJ.Api'); var origin = location.protocol + '//' + location.host, siteroot = window.Site? Site.siteroot : origin, url = '/__api/', cdn = { endpoint: (window.Site && location.protocol === 'http:')? (Site.jsonrpcprefix || Site.statprefix) : null, time: (window.Site? Site.server_time * 1000 : +new Date()), methods: {} }, context = { options: {}, endpoint: siteroot, sameDomain: siteroot === origin, batchTimeout: 125 }, batchQueue = [], batchTimeout, corsParameters = $.extend({ url: context.endpoint + url, type: 'POST', dataType: 'json', contentType: 'text/plain' }, context.sameDomain? {} : { xhrFields: { withCredentials: true } }), inactivityInterval; cdn.time -= cdn.time % 9E+5; function createRequestBody(name, params) { return { jsonrpc: '2.0', method: name, params: $.extend({}, params, { auth_token: context.options.auth_token }), id: Unique.id() }; } function handleAnswer (name, params, callback, answer) { if (answer.result) { if (!answer.result.auth_token) { LJ.console.warn('Server did not return the new auth_token, further request may fail'); } else { context.options.auth_token = answer.result.auth_token; delete answer.result.auth_token; } if (callback) { callback(answer.result); } } else if (answer.error) { if (callback) { callback({ error: answer.error }); } } else { LJ.warn('Server did not return error or result in response for method ' + name); if (callback) { callback({ error: { message: 'Invalid response', code: 2 } }); } } } function handleError (name, params, callback) { LJ.warn('An internal error has occured while calling the method ', name); if (callback) { callback({ error: { message: 'Internal error', code: 1 } }); } } function defer (request, params, callback) { var promise = new $.Deferred(); batchQueue.push({ data: request, params: params, callback: callback, promise: promise }); if (!batchTimeout) { batchTimeout = setTimeout(function () { var query = batchQueue.splice(0, batchQueue.length); $.ajax($.extend(corsParameters, { data: JSON.stringify(query.map(function (request) { return request.data; })) })).success(function (data) { var i, j, l, k, response, request; for (i = 0, l = data.length; i < l; i++) { response = data[i]; for (j = 0, k = query.length; j < k; j++) { request = query[j]; if (request.data.id === response.id) { if (request.promise.state() === 'pending') { /* Return result */ handleAnswer(request.data.method, request.params, request.callback, response); request.promise.resolve(); } } } } /* Some requests left unresolved */ for (j = 0, k = query.length; j < k; j++) { request = query[j]; if (request.promise.state() === 'pending') { handleError(request.data.method, request.params, request.callback); request.promise.resolve(); } } }).error(function () { var i, l, request; for (i = 0, l = query.length; i < l; i++) { request = query[i]; if (request.promise.state() === 'pending') { /* Return error */ handleError(request.data.method, request.params, request.callback); request.promise.resolve(); } } }); batchTimeout = null; }, context.batchTimeout); } return promise; } /** * Init LJ functionality. * * @param {Object} options Options for init object. auth_token field is required for further actions. */ LJ.Api.init = function(options) { options = options || {}; if (context._initFired) { LJ.console.warn('LJ.Api.init was already called before'); } context._initFired = true; context.options = $.extend({}, options); if (!context.options.auth_token) { LJ.console.warn('Auth token has not been specified, request may fail'); } if (cdn.endpoint) { if (Site.rpc && Array.isArray(Site.rpc.public)) { Site.rpc.public.forEach(function (method) { cdn.methods[method] = true; }); } } LJ.UI.bootstrap('lj-api'); }; /** * Call api method on the server. * * @param {string} name Method name. * @param {Object=} params A hash with parameters to send to the server. * @param {Function=} callback Callback will be fired with results from the server. */ LJ.Api.call = function (name, params, callback) { var request = createRequestBody(name, params), publicMethod = !!cdn.methods.hasOwnProperty(name), endpoint = publicMethod? cdn.endpoint : context.endpoint, ajax, reqstr; // see LJ.Api.setInactivityInterval if (LJ.Activity.isInactiveMoreThan(inactivityInterval)) { LJ.Track.event('Site', 'Inactivity', 'API call aborted'); console.log('Request is aborted due to inactivity'); return; } if (!publicMethod && (LJ.Support.cors || context.sameDomain)) { /* CORS support detected or is not needed */ return defer(request, params, callback); } /* Fall back to JSONP */ if (publicMethod) { delete request.params.auth_token; request.id = cdn.time; } reqstr = JSON.stringify(request); ajax = $.ajax($.extend({ url: endpoint + url, dataType: 'jsonp', data: { request: reqstr } }, publicMethod? { cache: true, /* * Name is added to handle the case with several requests, * which complete not in order. Otherwise request will * fail because jQuery deletes callback after the response */ jsonpCallback: 'jQuery' + cdn.time + name.split('.').join('__') } : {})); ajax .success(handleAnswer.bind(null, name, params, callback)) .error(handleError.bind(null, name, params, callback)); return ajax.promise(); }; /* * Disable API calls when page is not active. * Tracking code is in core/track.js. * * @param {Number} interval Interval in ms */ LJ.Api.setInactivityInterval = function(interval) { if (!LJ.Activity.hasInterval(interval)) { throw new Error('Wrong interval parameter'); } inactivityInterval = interval; }; }(jQuery)); ; /* file-end: js/lj.api.js ----------------------------------------------------------------------------------*/ ;(function ($) { 'use strict'; var LJ = window.LJ = window.LJ || {}; /* Cookie plugin. Copyright (c) 2006 Klaus Hartl (stilbuero.de) */ function Cookie(name, value, options) { if (value !== undefined) { // name and value given, set/delete cookie options = options || {}; if (value === null) { value = ''; options.expires = -1; } var expires = ''; if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { var date; if (typeof options.expires == 'number') { date = new Date; date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); } else { date = options.expires; } expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE } // CAUTION: Needed to parenthesize options.path and options.domain // in the following expressions, otherwise they evaluate to undefined // in the packed version for some reason... var path = options.path ? '; path=' + (options.path) : '', domain = options.domain ? '; domain=' + (options.domain) : '', secure = options.secure ? '; secure' : '', cookieValue = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); document.cookie = cookieValue; return cookieValue; } else { // only name given, get cookie var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = cookies[i].trim(); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } } window.Cookie = Cookie; /**/ LJ.Cookie = { set: function (name, value, options) { return Cookie(name, value, options); }, get: function (name) { return Cookie(name); } }; }(jQuery)); ; /* file-end: js/core/general.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.lj.basicWidget.js */ /* --------------------------------------------------------------------------------- file-start: js/lib/jquery-ui/jquery.ui.core.min.js */ /*! jQuery UI - v1.8.24 - 2012-09-28 * https://github.com/jquery/jquery-ui * Includes: jquery.ui.core.js * Copyright (c) 2012 AUTHORS.txt; Licensed MIT, GPL */ (function(a,b){function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;return!b.href||!g||f.nodeName.toLowerCase()!=="map"?!1:(h=a("img[usemap=#"+g+"]")[0],!!h&&d(h))}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}a.ui=a.ui||{};if(a.ui.version)return;a.extend(a.ui,{version:"1.8.24",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;return a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0),/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a("").outerWidth(1).jquery||a.each(["Width","Height"],function(c,d){function h(b,c,d,f){return a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)}),c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){return c===b?g["inner"+d].call(this):this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){return typeof b!="number"?g["outer"+d].call(this,b):this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:a.expr.createPseudo?a.expr.createPseudo(function(b){return function(c){return!!a.data(c,b)}}):function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.curCSS||(a.curCSS=a.css),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!d||!a.element[0].parentNode)return;for(var e=0;e0?!0:(b[d]=1,e=b[d]>0,b[d]=0,e)},isOverAxis:function(a,b,c){return a>b&&a * Basic widget adds pub/sub system to the widget hierarchy. By convention widgets add prefix equal * to the widget name of the most parent element who fires it. E.g. if someWidget and subSomeWidget * that extends someWidget do fire open event, it should be prefixed with someWidget - someWidget/open. * */ (function($) { 'use strict'; var __callbacks = {}, //these events we set once and for all widget instances globalEvents = { documentClick: false }; /** @lends $.lj.basicWidget.prototype */ $.widget( 'lj.basicWidget', { /** * Default options for widgets. * @type Object * @private */ options: { /** * Object contains strings with class names that are used within widget. */ classNames: {}, /** * Object contains strings with selectors that are used to find nodes within widget. */ selectors: {}, /** * Object contains translation strings for a widget. Widget should not contain hardcoded strings. */ ml: {}, /** * Object contains strings with templates, that are used to build content within widget. */ tmpl: {} }, _create: function() { /** * Contains all events that should not trigger events on next fire for this widget. * @type Object */ this.__suppressedEvents = {}; this.__modules = {}; this._locked = false; }, /** * Bind common events for the widget */ _bindControls: function() { var widget = this; /** * documentClick */ if( !globalEvents.documentClick ) { $( document ).click( function( ev ) { widget._fire( 'documentClick', [], true ); } ); globalEvents.documentClick = true; } }, _setOption: function(name, val) { switch (name) { case 'selectors': case 'classNames': case 'tmpl': case 'ml': case 'templates': this.options[name] = $.extend(this.options[name], val); return; } $.Widget.prototype._setOption.apply(this, arguments); }, /** * Subscribe to the event with the callback. * * @param {String} type Event type. * @param {Function} callback Function that should be fired on the event. */ _on: function( type, callback ) { if (!__callbacks.hasOwnProperty(type)) { __callbacks[ type ] = []; } __callbacks[ type ].push( { fn: callback, owner: this, once: false } ); }, /** * Subscribe to one selected event with the callback. * * @param {String} type Event type. * @param {Function} callback Function that should be fired on the event. */ _one: function( type, callback ) { this._on( type, callback ); __callbacks[ type ][ __callbacks[ type ].length - 1 ].once = true; }, /** * Remove subscription on the event. * * @param {String} type Event type. * @param {Function=} callback Callback function. If parameter is omitted, function will remove all * callbacks of this instance from the subscription on this type of event. */ _off: function( type, callback ) { if (!__callbacks.hasOwnProperty(type)) { return; } var cbs = __callbacks[ type ]; for (var i = 0; i < cbs.length; ++i) { if ((cbs[i].fn === callback) || (!callback && cbs[i].owner === this)) { cbs.splice(i--, 1); } } }, /** * Dispatch event. * * @param {String} type Event type. * @param {Array|[]} args array with arguments that will be passed to the callback functions. * @param {Boolean|False} includeOwner If false the message is not recieved by * the object that dispatched it. */ _fire: function( type, args, includeOwner ) { args = args || []; includeOwner = includeOwner || false; if( type in __callbacks ) { var cbs = __callbacks[ type ], i = -1; while( cbs[ ++i ] ) { if( !includeOwner && cbs[ i ].owner === this ) { continue; } if( type in cbs[ i ].owner.__suppressedEvents ) { continue; } cbs[ i ].fn.apply( null, args ); } //we delete supressed event flag only after firing event because //widget can subscribe more than one callback while(cbs[ --i ]) { if( type in cbs[ i ].owner.__suppressedEvents ) { delete cbs[ i ].owner.__suppressedEvents[ type ]; } //delete callbacks that should be fired only once if( cbs[ i ].once ) { cbs.splice(i, 1); } } } }, /** * Prevent event from being trigger on this widget instance on next fire. * An event after next will be processed as normal */ _suppressNextEvent: function( eventName ) { this.__suppressedEvents[ eventName ] = true; }, /** * Remove all subscriptions on widget distruction. If overriden, this method should be * also caled. */ _destroy: function() { var cbs, type, i; for (type in __callbacks) { if (__callbacks.hasOwnProperty(type)) { cbs = __callbacks[type]; for (i = 0; i < cbs.length; ++i) { if (cbs[i].owner === this) { cbs.splice(i--, 1); } } } } }, /** * Find element inside the widget and return it. Note, that function caches the elements * and assigns them ti the widget object with the name _{name} * * @param {string} name Name of the selector to search in this.options.selectors. * @param {jQuery=} ctx Optionally we can say, where to find the node. */ _el: function(name, ctx) { var method = '_' + name; ctx = ctx || this.element; if (!this[method]) { this[method] = ctx.find(this.options.selectors[name]); } return this[method]; }, /** * Fetch the class name from the options. * * @param {string} name Name of the class name to search in this.options.classNames. */ _cl: function(name) { return this.options.classNames[name]; }, /** * Fetch the selector from the options. * * @param {string} name Name of the selector to search in this.options.selectors */ _s: function(name) { return this.options.selectors[name]; }, /** * Apply template specified by name with data. * * @param {string} name The key name of the template in this.options.templates. * @param {Object} data The data object which should be applied to the template. * * @return {jQuery} jQuery object with generated markup. */ _tmpl: function(name, data) { return LJ.UI.template(this.options.templates[name], data); }, /** * Fetch ml variable from the options and apply LJ.ml function to it * @param {String} name Options key for the ml variable * @return {String} ml-variable from server */ _ml: function (name) { if (this.options.ml && this.options.ml.hasOwnProperty(name)) { return LJ.ml( this.options.ml[name] ); } else { LJ.console.log("Widget text variable ["+ name +"] hasn't been defined"); return "["+ name +"]"; } }, /** * Use a mixin with the widget instance. * * @param {string} name Mixin name. A Mixin should be registered with LJ.UI.mixin. * @param {Object=} options Options to pass to the mixin. */ _use: function(name, options) { var module = LJ.UI.mixin(name); if (module) { if (this.__modules.hasOwnProperty(name)) { LJ.console.log('Warn: Module ', name, ' has already been registered for ', this.widgetName); return; } this.__modules[name] = module.call(this, jQuery, options); } else { LJ.console.log('Warn: Module ', name, ' has not been loaded yet'); } }, /** * Return mixin object. Object should contain public api provided with this mixin. * * @param {string} name Mixin name. */ _: function(name) { if (this.__modules.hasOwnProperty(name)) { return this.__modules[name]; } else { return null; } }, /** * Lock the widget. The method should be used to block widget UI during long operations, e.g. ajax requests. */ _lock: function() { this._locked = true; }, /** * Unlock the widget. */ _unlock: function() { this._locked = false; }, /** * Check whether widget is locked now. * * @return {boolean} The lock state */ locked: function() { return this._locked; } } ); }(jQuery)); ; /* file-end: js/jquery/jquery.lj.basicWidget.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/basic.js */ document.documentElement.id = 'js'; //core.js /** * Utility method. * @param x any Any JavaScript value, including undefined. * @return boolean true if the value is not null and is not undefined. */ finite = function(x){ return isFinite(x) ? x : 0; }; finiteInt = function(x, base){ return finite(parseInt(x, base)); }; finiteFloat = function(x){ return finite(parseFloat(x)); }; /* unique id generator */ Unique = { length: 0, id: function(){ return ++this.length; } }; /* event methods */ var Event = Event||{}; Event.stop = function(e){ // this set in Event.prep e = e || window.event || this; Event.stopPropagation(e); Event.preventDefault(e); return false; }; Event.stopPropagation = function(e){ if(e && e.stopPropagation) e.stopPropagation(); else window.event.cancelBubble = true; }; Event.preventDefault = function(e){ e = e || window.event; if(e.preventDefault) e.preventDefault(); e.returnValue = false; }; Event.prep = function(e){ e = e || window.event; if(e.stop === undefined) e.stop = this.stop; if(e.target === undefined) e.target = e.srcElement; if(e.relatedTarget === undefined) e.relatedTarget = e.toElement; return e; }; /** * Mark the namespace as a dependency. The function does nothing now. * * @param {string} path Namespace name. */ LJ.require = function(path) { //fillme }; /** * @class Class allows to call a function with some delay and also prevent * its execution if needed. * @constructor * * @param {Function} func Function to call. * @param {number} wait Time in ms to wait before function will be called. * @param {boolean=false} resetOnCall it true, the function will be executed only after last call + delay time */ LJ.DelayedCall = function(func, wait, resetOnCall) { this._func = func; this._wait = wait; this._resetOnCall = !!resetOnCall; this._timer = null; this._args = null; }; LJ.DelayedCall.prototype._timerCallback = function() { this._timer = null; this._func.apply(null, this._args); }; /** * Run function. All arguments that will be passed to this function will be * passed to the function called. */ LJ.DelayedCall.prototype.run = function(/* arguments */) { this._args = [].slice.call(arguments, 0); if (this._timer) { if (this._resetOnCall) { clearTimeout(this._timer); this._timer = null; } else { return; } } this._timer = setTimeout(this._timerCallback.bind(this), this._wait); }; /** * Prevent function execution. */ LJ.DelayedCall.prototype.stop = function() { clearTimeout(this._timer); this._timer = null; }; /** * Format number according to locale. E.g. 1000000 becomes 1,000,000. * * @param {number} num Number to format. */ LJ.commafy = function(num) { num = "" + num; if (/^\d+$/.test(num)) { var delim = LiveJournal.getLocalizedStr('number.punctuation'); if (delim === '[number.punctuation]') { delim = ','; } var hasMatches = true; while (hasMatches) { hasMatches = false; num = num.replace(/(\d)(\d{3})(?!\d)/g, function(str, first, group) { hasMatches = true; return first + delim + group; }) } } return num; }; LJ._const = {}; /** * Define a constant. * * @param {string} name name of the constant. All spaces will be replaced with underline. * if constant was already defined, the function will throw the exception. * @param {*} value A value of the constant. */ LJ.defineConst = function(name, value) { name = name.toUpperCase().replace(/\s+/g, '_'); if (LJ._const.hasOwnProperty(name)) { throw new Error('constant was already defined'); } else { LJ._const[name] = value; } }; /** * Get the value of the constant. * * @param {string} name The name of the constant. * @return {*} The value of the constant or undefined if constant was not defined. */ LJ.getConst = function(name) { name = name.toUpperCase().replace(/\s+/g, '_'); return (LJ._const.hasOwnProperty(name) ? LJ._const[name] : void 0); }; /** * @namespace LJ.Util.Journal Utility functions connected with journal */ LJ.define('LJ.Util.Journal'); (function() { var base = (LJ.get('siteroot') || 'http://www.livejournal.com') .replace('http://www', ''), journalReg = new RegExp('^http:\\/\\/([\\w-]+)' + base.replace(/\./, '\\.') + '(?:\\/(?:([\\w-]+)\\/)?(?:(\\d+)\\.html)?)?$'); /** * Parse journal link to retrieve information from it * * @param {string} url The string to parse. * @return {Object} Return object will contain fields journal and ditemid(if availible) or null if the link cannot be parsed. */ LJ.Util.Journal.parseLink = function(url) { if (!url) { return null; } if (!url.match(/(\.html|\/)$/)) { url += '/'; } var regRes = journalReg.exec(url), result = {}; if (!regRes || !regRes[1]) { return null; } if (!regRes[1].match(/^(?:users|community)$/)) { result.journal = regRes[1]; } else { if (!regRes[2]) { return null; } result.journal = regRes[2]; } result.journal = result.journal.replace(/-/g, '_'); if (regRes[3]) { result.ditemid = parseInt(regRes[3], 10); } return result; }; /** * Render journal link according to the standard scheme. * * @param {string} journal Journal name. * @param {string|number} ditemid Id of the post in the journal. * @param {boolean} iscomm Whether to treat the journal as community. * * @return {string|null} Result is a link to the journal page or null if no journal was specified. */ LJ.Util.Journal.renderLink = function(journal, ditemid, iscomm) { if (!journal) { return null; } var url = 'http://'; if (iscomm) { url += 'community' + base + '/' + journal; } else if (journal.match(/^_|_$/)) { url += 'users' + base + '/' + journal; } else { url += journal.replace(/_/g, '-') + base; } url += '/'; if (ditemid) { url += ditemid + '.html'; } return url; }; }()); /** * @namespace LJ.Util.Date The namespace contains utility functions connected with date. */ LJ.define('LJ.Util.Date'); (function() { var months = [ 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december' ], month_ml = 'date.month.{month}.long'; function normalizeFormat(format) { if (!format || format === 'short') { format = LiveJournal.getLocalizedStr('date.format.short'); } else if (format === 'long') { format = LiveJournal.getLocalizedStr('date.format.long'); } return format; } function getMonth(idx) { var month = months[ idx % 12 ]; return LiveJournal.getLocalizedStr(month_ml.supplant({month: month})); } /** * Parse date from string. * * @param {string} datestr The string containing the date. * @param {string} format Required date string format. */ LJ.Util.Date.parse = function(datestr, format) { format = normalizeFormat(format); //don't touch it if you can't use it if (!datestr) { return datestr; } var testStr = normalizeFormat(format), positions = [ null ], pos = 0, token, regs = { '%Y' : '(\\d{4})', '%M' : '(\\d{2})', '%D' : '(\\d{2})' }; while( ( pos = testStr.indexOf( '%', pos ) ) !== -1 ) { token = testStr.substr( pos, 2 ); if( token in regs ) { testStr = testStr.replace( token, regs[ token ] ); positions.push( token ); } else { pos += 2; //skip this token positions.push( null ); } } var r = new RegExp( testStr ), arr = r.exec( datestr ); if( !arr ) { return null; } else { var d = new Date(); for( var i = 1; i < arr.length; ++i ) { if( positions[ i ] ) { switch( positions[ i ] ) { case '%D': d.setDate( arr[ i ] ); break; case '%M': d.setMonth( parseInt( arr[ i ], 10 ) - 1 ); break; case '%Y': d.setFullYear( arr[ i ] ); break; } } } return d; } }; /** * Create string representation of object according to the format. * * @param {Date} date The date object to work with. * @param {string=} format String format. Possible default formats are 'short' and 'long'. */ LJ.Util.Date.format = function(date, format) { format = normalizeFormat(format); return format.replace( /%([a-zA-Z]{1})/g, function(str, letter) { switch (letter) { case 'M' : return ('' + (date.getMonth() + 1)).pad(2, '0'); case 'B' : //full month return getMonth(date.getMonth()); case 'D' : return ('' + date.getDate()).pad(2, '0'); case 'Y' : return date.getFullYear(); case 'R' : return ('' + date.getHours()).pad(2, '0') + ':' + ('' + date.getMinutes()).pad(2, '0'); case 'T' : return [ ('' + date.getHours()).pad(2, '0'), ('' + date.getMinutes()).pad(2, '0'), ('' + date.getSeconds()).pad(2, '0') ].join(':'); default: return str; } }); }; /** * Get timezone from the date object in the canonical way. * * @return {string} A string representation of timezone, eg +0400 */ LJ.Util.Date.timezone = function() { var offset = (-(new Date()).getTimezoneOffset() / 0.6), str = ''; if (offset > 0) { str += '+'; } else if (offset < 0) { str += '-'; offset = -offset; } str += ('' + offset).pad(4, '0'); return str; }; }()); LJ.DOM = LJ.DOM || {}; /** * Get field's selection * @param {jQuery/DOM} node jQuery or DOM node * @return {Object} Object, contains { start, end } coordinates of selection */ LJ.DOM.getSelection = function (node) { var start = 0, end = 0, range, dup, regexp = null; if (!node.nodeName) { node = node.get(0); } if ( 'selectionStart' in node ) { return { start: node.selectionStart, end: node.selectionEnd }; } if ( 'createTextRange' in node ) { range = document.selection.createRange(); if ( range.parentElement() == node ) { dup = range.duplicate(); if ( node.type === 'text' ) { node.focus(); start = -dup.moveStart('character', -node.value.length); end = start + range.text.length; } else { // textarea regexp = /\r/g; dup.moveToElementText(node); dup.setEndPoint('EndToStart', range); start = dup.text.replace(regexp, '').length; dup.setEndPoint('EndToEnd', range); end = dup.text.replace(regexp, '').length; dup = document.selection.createRange(); dup.moveToElementText(node); dup.moveStart('character', start); while (dup.move('character', -dup.compareEndPoints('StartToStart', range))) { start += 1; } dup.moveStart('character', end - start); while (dup.move('character', -dup.compareEndPoints('StartToEnd', range))) { end += 1; } } } } return { start: start, end: end }; }; /** * Set selection for node * @param {jQuery/DOM} node jQuery or native DOM node * @param {number} start Selection start position * @param {number} end Selection end position */ LJ.DOM.setSelection = function (node, start, end) { var range; if (!node.nodeName) { node = node.get(0); } // see https://bugzilla.mozilla.org/show_bug.cgi?id=265159 node.focus(); if( node.setSelectionRange ){ node.setSelectionRange(start, end); } // IE, "else" for opera 10 else if (document.selection && document.selection.createRange){ range = node.createTextRange(); range.collapse(true); range.moveEnd('character', end); range.moveStart('character', start); range.select(); } }; /** * Set cursor position inside of input/textarea element * @param {jQuery/DOM} node jQuery or DOM node * @param {[type]} position Cursor position */ LJ.DOM.setCursor = function (node, position) { var text, length, absPosition; if (!node.nodeName) { node = node.get(0); } text = ( 'value' in node ? node.value : node.text ).replace(/\r/, ''); length = text.length; // convenient positions if (position === 'end') { return LJ.DOM.setSelection(node, length, length); } if (position === 'start') { return LJ.DOM.setSelection(node, 0, 0); } // calculation of correct caret position if (position > 0) { if (position > length) { position = length; } } else if (position !== 0) { absPosition = Math.abs(position); position = absPosition > length ? 0 : length - absPosition; } LJ.DOM.setSelection(node, position, position); }; /** * @namespace LJ.UI Namespace should contain utility functions that are connected with widgets. */ LJ.UI = LJ.UI || {}; LJ.UI._mixins = {}; /** * Register a mixin to allow to use it later in the jQuery UI widgets. * * @param {string} name Name of the widget. * @param {Function} module The function that will bootsrap widget. The Function will be applied * to the widget instance and the return object will represent the public api for the mixin. */ LJ.UI.mixin = function(name, module) { if (arguments.length === 1) { if (LJ.UI._mixins.hasOwnProperty(name)) { return LJ.UI._mixins[name]; } else { LJ.console.log('Warn: Mixin ', name, ' was called but is not defined yet.'); } } else { LJ.UI._mixins[name] = module; } }; (function() { var locale = (LJ.get('locale') || 'en_LJ').substr(0, 2), //All handlers were directly copied from LJ::Lang code handlers = { be: plural_form_ru, en: plural_form_en, fr: plural_form_fr, hu: plural_form_singular, is: plural_form_is, ja: plural_form_singular, lt: plural_form_lt, lv: plural_form_lv, pl: plural_form_pl, pt: plural_form_fr, ru: plural_form_ru, tr: plural_form_singular, uk: plural_form_ru }; // English, Danish, German, Norwegian, Swedish, Estonian, Finnish, Greek, // Hebrew, Italian, Spanish, Esperanto function plural_form_en(count) { if (count == 1) { return 0; } return 1; } // French, Portugese, Brazilian Portuguese function plural_form_fr(count) { if (count > 1) { return 1; } return 0; } // Croatian, Czech, Russian, Slovak, Ukrainian, Belarusian function plural_form_ru(count) { if (typeof count === 'undefined') { return 0; } if (count % 10 == 1 && count % 100 != 11) { return 0; } if ((count % 10 >= 2 && count % 10 <= 4) && (count % 100 < 10 || count % 100 >= 20)) { return 1; } return 2; } // Polish function plural_form_pl(count) { if (count === 1) { return 0; } if ((count % 10 >= 2 && count % 10 <= 4) && (count % 100 < 10 || count % 100 >= 20)) { return 1; } return 2; } // Lithuanian function plural_form_lt(count) { if (count % 10 == 1 && count % 100 != 11) { return 0; } if ((count % 10 >= 2) && (count % 100 < 10 || count % 100 >= 20)) { return 1; } return 2; } // Hungarian, Japanese, Korean (not supported), Turkish function plural_form_singular(count) { return 0; } // Latvian function plural_form_lv(count) { if (count % 10 === 1 && count % 100 !== 11) { return 0; } if (count != 0) { return 1; } return 2; } // Icelandic function plural_form_is(count) { if (count % 10 === 1 && count % 100 !== 11) { return 0; } return 1; } function pluralize(num, forms) { var handler = handlers.hasOwnProperty(locale) ? handlers[locale] : handlers['en'], form = handler(num); return forms[form] ? forms[form] : ''; } /** * Get localized string. * * @param {string} key A key to search. * @param {Object} dict A hash to search values for substitution. * @param {string=} def A default value to return if the string was not returned from the server. * * @return {string} Localized value for string. */ LJ.ml = function(key, dict, def) { var str = '', tmpl; dict = dict || {}; if (Site.ml_text.hasOwnProperty(key)) { str = Site.ml_text[key]; str = str.replace( /\[\[\?([\w-]+)\|(.*?)\]\]/g, function(str, numstr, forms) { if (!dict.hasOwnProperty(numstr)) { return str; } var num = parseInt(dict[numstr], 10); return pluralize(num, forms.split('|')); }); for (tmpl in dict) { if (dict.hasOwnProperty(tmpl)) { str = str.replace('%' + tmpl + '%', dict[tmpl]); str = str.replace('[[' + tmpl + ']]', dict[tmpl]); } } } else { str = def || '[' + key + ']'; LJ.console.log("Text variable ["+ key +"] hasn't been defined."); } return str; }; /** * LJ.ml alias for templates */ LJ.mltext = function (key) { var dict = {}, args = Array.prototype.slice.call(arguments, 1), i, l; for (i = 0, l = args.length; i < l; i += 2) { dict[args[i]] = args[i + 1] || ''; } return LJ.ml(key, dict); }; }()); /* object extensions */ if (!Object.extend) Object.extend = function (d, s){ if(d) for(var p in s) if(!d[p]) d[p] = s[p]; return d; }; if (!Object.override) Object.override = function (d, s){ if(d) for(var p in s) d[p] = s[p]; return d; }; /* function extensions */ /** * Returns an array of all own enumerable properties found upon a given object, * in the same order as that provided by a for-in loop. * * @param {Object} The object whose enumerable own properties are to be returned. * * @return {Array} Array with properties names. */ Object.extend(Function.prototype, { bindEventListener: function(object) { var method = this; // Use double closure to work around IE 6 memory leak. return function(e) { e = Event.prep(e); return method.call(object, e); }; } }); Object.extend(Function, { defer: function(func, args/*, more than one*/) { args = Array.prototype.slice.call(arguments, 1); setTimeout(function() { func.apply(null, args); }, 0); }, /** * Create a function that will call a function func with arguments * through setTimeout set to zero. * @param {Function} func The function to wrap. * @param {Object} args Any arguments to attach to function call. * * @return {Function} Return newly created delayed function. */ defered: function(func, args) { args = args || []; return function() { var args2 = args.concat([].slice.call(arguments, 0)); Function.defer(func, args2); }; } }); /* class helpers */ indirectObjects = []; Class = function(superClass){ // Set the constructor: var constructor = function(){ if(arguments.length) this.init.apply(this, arguments); }; // -- Accomplish static-inheritance: Object.override(constructor, Class); // inherit static methods from Class superClass = superClass || function(){ }; superClassFunc = function(){ }; Object.extend(superClassFunc.prototype, superClass.prototype); Object.extend(superClassFunc.prototype, { init: function(){ }, destroy: function(){ } }); Object.override(constructor, superClass); // inherit static methods from the superClass constructor.superClass = superClassFunc.prototype; // Set the constructor's prototype (accomplish object-inheritance): constructor.prototype = new superClass(); constructor.prototype.constructor = constructor; // rev. 0.7 // -- extend prototype with Class instance methods Object.extend(constructor.prototype, Class.prototype); // -- override prototype with interface methods for(var i = 1; i < arguments.length; i++) Object.override(constructor.prototype, arguments[i]); return constructor; }; Class.prototype = { destroy: function(){ try{ if(this.indirectIndex) indirectObjects[ this.indirectIndex ] = undefined; delete this.indirectIndex; } catch(e){ } for(var property in this){ try{ delete this[ property ]; } catch(e){ } } } }; /* string extensions */ Object.extend(String, { escapeJSChar: function( c ) { // try simple escaping switch( c ) { case "\\": return "\\\\"; case "\"": return "\\\""; case "'": return "\\'"; case "\b": return "\\b"; case "\f": return "\\f"; case "\n": return "\\n"; case "\r": return "\\r"; case "\t": return "\\t"; } // return raw bytes now ... should be UTF-8 if( c >= " " ) return c; // try \uXXXX escaping, but shouldn't make it for case 1, 2 c = c.charCodeAt( 0 ).toString( 16 ); switch( c.length ) { case 1: return "\\u000" + c; case 2: return "\\u00" + c; case 3: return "\\u0" + c; case 4: return "\\u" + c; } // should never make it here return ""; }, encodeEntity: function( c ) { switch( c ) { case "<": return "<"; case ">": return ">"; case "&": return "&"; case '"': return """; case "'": return "'"; } return c; }, decodeEntity: function( c ) { switch( c ) { case "amp": return "&"; case "quot": return '"'; case "apos": return "'"; case "gt": return ">"; case "lt": return "<"; } var m = c.match( /^#(\d+)$/ ); if( m && defined( m[ 1 ] ) ) return String.fromCharCode( m[ 1 ] ); m = c.match( /^#x([0-9a-f]+)$/i ); if( m && defined( m[ 1 ] ) ) return String.fromCharCode( parseInt( hex, m[ 1 ] ) ); return c; } }); Object.extend(String.prototype, { escapeJS: function() { return this.replace( /([^ -!#-\[\]-~])/g, function( m, c ) { return String.escapeJSChar( c ); } ) }, /** * Encode a string to allow a secure insertion in html code. */ encodeHTML: function() { return this.replace( /([<>&\"\'])/g, function( m, c ) { return String.encodeEntity( c ) } ); /* fix syntax highlight: " */ }, decodeHTML: function() { return this.replace( /&(.*?);/g, function( m, c ) { return String.decodeEntity( c ) } ); }, /** * Add chars in front of string until it gets the length required. * * @param {Number} length Required string length. * @param {String} padChar A char to add in front of string. * * @return {String} A padded string. */ pad: function(length, padChar) { return ((new Array(length + 1)) .join(padChar) + this ).slice(-length); }, supplant: function(o) { return this.replace(/{([^{}]*)}/g, function (a, b) { var r = o[b]; return typeof r === 'string' || typeof r === 'number' ? r : a; }); } }); // will be shimmed using es6-shim later if (typeof String.prototype.startsWith !== 'function') { String.prototype.startsWith = function(start) { return this.slice(0, String(start).length) === start; } } /* extend array object */ Object.extend(Array.prototype, { /** * Check if index fits in current array size and fix it otherwise. * * @param {Number} fromIndex Index to check. * @param {Number} defaultIndex This value will be taken if fromIndex is not defined. * * @return {Number} Fixed index value. */ fitIndex: function(fromIndex, defaultIndex) { if (fromIndex !== undefined || fromIndex == null) { fromIndex = defaultIndex; } else if (fromIndex < 0) { fromIndex = this.length + fromIndex; if (fromIndex < 0) { fromIndex = 0; } } else if (fromIndex >= this.length) { fromIndex = this.length - 1; } return fromIndex; }, /** * The function takes its arguments and add the ones that are not already inside to the end. * * @return {Number} New length of the array. */ add: function(/* a1, a2, ... */) { for (var j, a = arguments, i = 0; i < a.length; i++ ) { j = this.indexOf(a[i]); if (j < 0) { this.push(arguments[i]); } } return this.length; }, /* * The function takes its arguments and removes them from the array, if they are inside * * @return {Number} New length of the array. */ remove: function(/* a1, a2, ... */) { for (var j, a = arguments, i = 0; i < a.length; i++ ) { j = this.indexOf(a[i]); if (j >= 0) { this.splice(j, 1); } } return this.length; } }); /* ajax */ var XMLHttpRequest = XMLHttpRequest || window.ActiveXObject && function(){ return new ActiveXObject('Msxml2.XMLHTTP'); }; //dom.js /* DOM class */ DOM = { getElement: function(e){ return (typeof e == "string" || typeof e == "number") ? document.getElementById(e) : e; }, addEventListener: function(e, eventName, func, useCapture){ if(e.addEventListener) e.addEventListener(eventName, func, useCapture); else if(e.attachEvent) e.attachEvent('on' + eventName, func); else e['on' + eventName] = func; }, removeEventListener: function(e, eventName, func, useCapture){ if(e.removeEventListener) e.removeEventListener(eventName, func, useCapture); else if(e.detachEvent) e.detachEvent('on' + eventName, func); else e['on' + eventName] = undefined; }, /* style */ getComputedStyle: function(node){ if(node.currentStyle){ return node.currentStyle; } var defaultView = node.ownerDocument.defaultView; if(defaultView && defaultView.getComputedStyle){ return defaultView.getComputedStyle(node, null); } }, // given a window (or defaulting to current window), returns // object with .x and .y of client's usable area getClientDimensions: function(w){ if(!w) w = window; var d = {}; // most browsers if(w.innerHeight){ d.x = w.innerWidth; d.y = w.innerHeight; return d; } // IE6, strict var de = w.document.documentElement; if(de && de.clientHeight){ d.x = de.clientWidth; d.y = de.clientHeight; return d; } // IE, misc if(document.body){ d.x = document.body.clientWidth; d.y = document.body.clientHeight; return d; } return undefined; }, getDimensions: function(e){ if(!e) return undefined; var style = DOM.getComputedStyle(e); return { offsetLeft: e.offsetLeft, offsetTop: e.offsetTop, offsetWidth: e.offsetWidth, offsetHeight: e.offsetHeight, clientWidth: e.clientWidth, clientHeight: e.clientHeight, offsetRight: e.offsetLeft + e.offsetWidth, offsetBottom: e.offsetTop + e.offsetHeight, clientLeft: finiteInt(style.borderLeftWidth) + finiteInt(style.paddingLeft), clientTop: finiteInt(style.borderTopWidth) + finiteInt(style.paddingTop), clientRight: e.clientLeft + e.clientWidth, clientBottom: e.clientTop + e.clientHeight }; }, getAbsoluteDimensions: function(e){ var d = DOM.getDimensions(e); if(!d) return d; d.absoluteLeft = d.offsetLeft; d.absoluteTop = d.offsetTop; d.absoluteRight = d.offsetRight; d.absoluteBottom = d.offsetBottom; var bork = 0; while(e){ try{ // IE 6 sometimes gives an unwarranted error ("htmlfile: Unspecified error"). e = e.offsetParent; } catch (err){ if(++bork > 25) return null; } if(!e) return d; d.absoluteLeft += e.offsetLeft; d.absoluteTop += e.offsetTop; d.absoluteRight += e.offsetLeft; d.absoluteBottom += e.offsetTop; } return d; }, setLeft: function(e, v){ e.style.left = finiteInt(v) + "px"; }, setTop: function(e, v){ e.style.top = finiteInt(v) + "px"; }, setWidth: function(e, v){ e.style.width = Math.max(0, finiteInt(v)) + "px"; }, setHeight: function(e, v){ e.style.height = Math.max(0, finiteInt(v)) + "px"; }, getWindowScroll: function(w){ var s = { left: 0, top: 0 }; if(!w) w = window; var d = w.document; var de = d.documentElement; // most browsers if(w.pageXOffset !== undefined){ s.left = w.pageXOffset; s.top = w.pageYOffset; } // ie else if(de && de.scrollLeft !== undefined){ s.left = de.scrollLeft; s.top = de.scrollTop; } // safari else if(w.scrollX !== undefined){ s.left = w.scrollX; s.top = w.scrollY; } // opera else if(d.body && d.body.scrollLeft !== undefined){ s.left = d.body.scrollLeft; s.top = d.body.scrollTop; } return s; }, getAbsoluteCursorPosition: function(event){ event = event || window.event; var s = DOM.getWindowScroll(window); return { x: s.left + event.clientX, y: s.top + event.clientY }; }, /* dom methods */ filterElementsByClassName: function(es, className){ var filtered = []; for(var i = 0; i < es.length; i++){ var e = es[ i ]; if(DOM.hasClassName(e, className)) filtered[ filtered.length ] = e; } return filtered; }, filterElementsByAttribute: function(es, attr){ if(!es) return []; if(!attr) return es; var filtered = []; for(var i = 0; i < es.length; i++){ var element = es[ i ]; if(!element) continue; if(element.getAttribute && ( element.getAttribute(attr) )) filtered[ filtered.length ] = element; } return filtered; }, filterElementsByTagName: function(es, tagName){ if(tagName == "*") return es; var filtered = []; tagName = tagName.toLowerCase(); for(var i = 0; i < es.length; i++){ var e = es[ i ]; if(e.tagName && e.tagName.toLowerCase() == tagName) filtered[ filtered.length ] = e; } return filtered; }, // private getElementsByTagAndAttribute: function(root, tagName, attr){ if(!root) root = document; var es = root.getElementsByTagName(tagName); return DOM.filterElementsByAttribute(es, attr); }, getElementsByAttributeAndValue: function(root, attr, value){ var es = DOM.getElementsByTagAndAttribute(root, "*", attr); var filtered = []; for(var i = 0; i < es.length; i++) if(es[ i ].getAttribute(attr) == value) filtered.push(es[ i ]); return filtered; }, getElementsByTagAndClassName: function(root, tagName, className){ if(!root) root = document; var elements = root.getElementsByTagName(tagName); return DOM.filterElementsByClassName(elements, className); }, getElementsByClassName: function(root, className){ return DOM.getElementsByTagAndClassName(root, "*", className); }, getAncestors: function(n, includeSelf){ if(!n) return []; var as = includeSelf ? [ n ] : []; n = n.parentNode; while(n){ as.push(n); n = n.parentNode; } return as; }, getAncestorsByClassName: function(n, className, includeSelf){ var es = DOM.getAncestors(n, includeSelf); return DOM.filterElementsByClassName(es, className); }, getFirstAncestorByClassName: function(n, className, includeSelf){ return DOM.getAncestorsByClassName(n, className, includeSelf)[ 0 ]; }, hasClassName: function(e, className){ if(!e || !e.className) return false; var cs = e.className.split(/\s+/g); for(var i = 0; i < cs.length; i++){ if(cs[ i ] == className) return true; } return false; }, addClassName: function(e, className){ if(!e || !className) return false; var cs = e.className.split(/\s+/g); for(var i = 0; i < cs.length; i++){ if(cs[ i ] == className) return true; } cs.push(className); e.className = cs.join(" "); return false; }, removeClassName: function(e, className){ var r = false; if(!e || !e.className || !className) return r; var cs = (e.className && e.className.length) ? e.className.split(/\s+/g) : []; var ncs = []; for(var i = 0; i < cs.length; i++){ if(cs[ i ] == className){ r = true; continue; } ncs.push(cs[ i ]); } if(r) e.className = ncs.join(" "); return r; }, // deprecated: use LJ.DOM.* instead getSelectedRange: LJ.DOM.getSelection, setSelectedRange: LJ.DOM.setSelection }; //httpreq.js // opts: // url, onError, onData, method (GET or POST), data // url: where to get/post to // onError: callback on error // onData: callback on data received // method: HTTP method, GET by default // data: what to send to the server (urlencoded) HTTPReq = { getJSON: function(opts){ var req = new XMLHttpRequest(); var state_callback = function(){ if(req.readyState != 4) return; if(req.status != 200){ if(opts.onError) opts.onError(req.status ? "status: " + req.status : "no data"); return; } var resObj; var e; try{ eval("resObj = " + req.responseText + ";"); } catch (e){ } if(e || ! resObj){ if(opts.onError) opts.onError("Error parsing response: \"" + req.responseText + "\""); return; } if(opts.onData) opts.onData(resObj); }; req.onreadystatechange = state_callback; var method = opts.method || "GET"; var data = opts.data || null; var url = opts.url; if(opts.method == "GET" && opts.data){ url += url.match(/\?/) ? "&" : "?"; url += opts.data } url += url.match(/\?/) ? "&" : "?"; url += "_rand=" + Math.random(); req.open(method, url, true); // we should send null unless we're in a POST var to_send = null; if(method.toUpperCase() == "POST"){ req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); to_send = data; } req.send(to_send); }, formEncoded: function(vars){ var enc = []; var e; for(var key in vars){ enc.push(encodeURIComponent(key) + "=" + encodeURIComponent(vars[key])); } return enc.join("&"); } }; /** * Object responsible for statistic integration * @param {jQuery} $ jQuery * @return {Object} Methods for statistic interation */ LJ.Stat = (function ($) { var selector = '#hello-world', // block for statistic addition el = null; // cached jquery element /** * Adds counter via inserting image on the page * @param {String} img Image url */ function addCounter( url ) { var img = $('', { src: url, alt: 'lj-counter' }); // cache selector el = el || $(selector); el.append(img); } return { addCounter: addCounter }; }(jQuery)); LJ.siteMessage = (function ($) { 'use strict'; var scheme = LJ.get('scheme'), messageSelector = '.appwidget-sitemessages', selectors = { lanzelot: { selector: '#main_body', method: 'before' }, horizon: { selector: '#big-content-wrapper', method: 'prepend' }, lynx: { selector: 'body', method: 'prepend' }, // for journal pages journal: { selector: '#lj_controlstrip_new', method: 'after' } }, // placeholder for methods to return methods = null; // we should run code only when document is ready and only for user // that is not currently logged in $(function () { if (!Site.remoteUser) { // wait for API initialization (inside of livejournal.js) setTimeout(methods.get.bind(methods), 0); } }); methods = { /** * Retrieve message from server and show it */ get: function () { var that = this; LJ.Api.call('sitemessage.get_message', { locale: Site.locale, country: Site.country, username: LJ.get('current_journal.username') }, function (data) { if (!data.error) { that.show(data.message); } }); }, /** * Show content as message * @param {String} content Html representation of the message */ show: function (content) { var type = selectors[ scheme ? scheme : 'journal' ]; // we should do nothing for this scheme yet if (scheme === 'schemius') { return; } // remove existed messages $(messageSelector).remove(); // add message on the page $(type.selector)[type.method](content); } }; return methods; }(jQuery)); ; /* file-end: js/basic.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/jquery_fn.js */ /* --------------------------------------------------------------------------------- file-start: js/hourglass.js */ /** * @author Valeriy Vasin (valeriy.vasin@sup.com) * @description Create a little animated hourglass. */ ;(function ($) { 'use strict'; /** * @class Hourglass * @constructor */ function Hourglass() { this.element = $('', { css: { position: 'absolute', display: 'none', zIndex: 5000 }, width: 17, height: 17, src: (Site && Site.imgprefix) ? Site.imgprefix + '/hourglass.gif?v=1674' : '/img/hourglass.gif?v=1674' }); this.element.appendTo(document.body); // name is used for backward compatibility with old widgets this.ele = this.element.get(0); if (arguments.length) { this.init.apply(this, arguments); } } /** * Initialize hourglass. Backward compatibility method. * @param {HTMLElement} container Dom element to show hourglass in * @param {String} className Additional classname for the hourglass */ Hourglass.prototype.init = function (container, className) { if (typeof className === 'string') { this.element.addClass(className); } if (typeof container !== 'undefined') { this.setContainer( container ); this.show(); } return this; }; /** * Set position of for the hourglass * @param {Number} x x-coordinate * @param {Number} y y-coordinate */ Hourglass.prototype.setPosition = function (x, y) { this.element.css({ left: x - 8, top: y - 8 }); return this; }; /** * Set parent element for hourglass * @param {HTMLElement} container Container in the center of which hourglass * will be showed */ Hourglass.prototype.setContainer = function (container) { var $container = $(container), offset = $container.offset(), x = offset.left + $container.width() / 2, y = offset.top + $container.height() / 2; this.setPosition(x, y); return this; }; /** * Set event according to which hourglass will be positioned * @param {jQuery.Event} e jQuery event */ Hourglass.prototype.setEvent = function (e) { if (e.pageX && e.pageY) { this.setPosition(e.pageX, e.pageY); } else { this.setContainer(e.target); } return this; }; /** * Show hourglass element */ Hourglass.prototype.show = function () { this.element.show(); return this; }; /** * Hide hourglass element */ Hourglass.prototype.hide = function () { this.element.hide(); // backward compatibility this.remove(); return this; }; /** * Remove hourglass element */ Hourglass.prototype.remove = function () { this.element.remove(); return this; }; /** * Place hourglass in the center of the element * @param {HTMLElement} container Container in the center of which hourglass * will be showed */ Hourglass.prototype.hourglass_at_widget = function (container) { this.setContainer(container); this.show(); return this; }; /** * Set position of hourglass and show it. Backward compatibility method. * @param {Number} x x-coordinate * @param {Number} y y-coordinate */ Hourglass.prototype.hourglass_at = function (x, y) { this.setPosition(x, y); this.show(); return this; }; /** * Add class to hourglass element. Backward compatibility method. * Notice: Use instance.element.addClass('my-class') instead * @param {String} className Class name */ Hourglass.prototype.add_class_name = function (className) { this.element.addClass(className); return this; }; // export to global window.Hourglass = Hourglass; }(jQuery)); ; /* file-end: js/hourglass.js ----------------------------------------------------------------------------------*/ /*global Hourglass */ jQuery.ajaxSetup({ cache: false }); /** * jQuery plugin that works with caret (it uses LJ.DOM.* methods and added for convenience only) * - if two arguments have been provided: setting selection from startPos to endPos * - if one argument: set cursor to startPos * - if no arguments: get selection of field * * @param {number} startPos Start caret position * @param {number} endPos End caret position. */ jQuery.fn.caret = function (startPos, endPos) { var $el = this.length > 1 ? this.first() : this, length; if (startPos === 'start') { length = $el.val().length; LJ.DOM.setSelection($el, 0, 0); return this; } if (startPos === 'end') { length = $el.val().length; LJ.DOM.setSelection($el, length, length); return this; } if (typeof startPos === 'number') { if (typeof endPos !== 'number') { LJ.DOM.setCursor($el, startPos); } else { LJ.DOM.setSelection($el, startPos, endPos); } return this; } else { return LJ.DOM.getSelection($el); } }; jQuery.fn.isCollapsed = function() { var selection = LJ.DOM.getSelection(this.get(0)); return selection.start === selection.end; }; /** * @deprecated Use hourglass.setEvent instead */ jQuery.fn.hourglass = function (xhr){ var hourglasses = []; this.each(function () { var e, hourglass; // is complete or was aborted if (xhr && (xhr.readyState === 0 || xhr.readyState === 4)) { return; } if( !this.nodeType ) { // position from event e = jQuery.event.fix(this); hourglass = new Hourglass() .setEvent(e) .show(); } hourglasses.push(hourglass); if (xhr) { hourglass.element.on('ajaxComplete', function (event, request){ if (request === xhr){ hourglass.remove(); } }); } }); return hourglasses; }; // not work for password jQuery.fn.placeholder = (function() { var check_focus = function() { if (this.value === this.getAttribute("placeholder")) { jQuery(this) .val("") .removeClass("placeholder"); } }, check_blur = function() { if (!this.value) { jQuery(this) .val(this.getAttribute("placeholder")) .addClass("placeholder"); } }, support; return function() { if (support === undefined) { support = "placeholder" in document.createElement("input"); } if (support === true) { return this; } else { return this.each(function() { if (this.getAttribute("placeholder")) { var $this = jQuery(this); if (!$this.data('jQuery-has-placeholder')) { $this.focus(check_focus).blur(check_blur); jQuery(this.form) .submit(function() { $this.hasClass("placeholder") && $this.removeClass("placeholder").val(""); }); } this.value === this.getAttribute("placeholder") || !this.value ? $this.val(this.getAttribute("placeholder")).addClass("placeholder") : $this.removeClass("placeholder"); $this.data('jQuery-has-placeholder', true) } }); } } })(); //this one is fields type agnostic but creates additional label elements, which need to be styled jQuery.fn.labeledPlaceholder = function(){ function focus_action(input, label){ label.hide(); } function blur_action(input, label){ if (input.val().length === 0) { label.show(); } } return this.each(function(){ if('placeholder' in document.createElement('input') && this.tagName.toLowerCase() === "input"){ return; } if('placeholder' in document.createElement('textarea') && this.tagName.toLowerCase() === "textarea"){ return; } var $this = jQuery(this), placeholder = $this.attr('placeholder'); $this.wrap(''); if(!placeholder || placeholder.length === 0){ return; } var label = jQuery("").addClass('placeholder-label').mousedown(function(ev){ setTimeout(function(){ focus_action($this, label); $this.focus(); }, 0); }).html(placeholder).insertBefore($this); $this.focus(function(){ focus_action($this, label) }).blur(function(){ blur_action($this, label) }); blur_action($this, label); }); }; jQuery.fn.input = function(fn){ return fn ? this.each(function(){ var last_value = this.value; jQuery(this).bind("input keyup paste", function(e){ // e.originalEvent use from trigger if(!e.originalEvent || this.value !== last_value){ last_value = this.value; fn.apply(this, arguments); } }) }) : this.trigger("input"); }; // ctrl+enter send form jQuery.fn.disableEnterSubmit = function() { this.bind("keypress", function(e) { // keyCode == 10 in IE with ctrlKey if ((e.which === 13 || e.which === 10) && e.target && e.target.form) { if (e.ctrlKey && !jQuery(":submit", e.target.form).attr("disabled") && (e.target.tagName === "TEXTAREA" || e.target.tagName === "INPUT") ) { e.target.form.submit(); } if (e.target.tagName === "INPUT") { e.preventDefault(); } } }); return this; }; /* function based on markup: tab links: ul>li>a current tab: ul>li.current tab container: ul>li tab container current: ul>li.current */ (function ($) { var supportHistoryAPI = !!window.history.pushState; var dataHistory = {}; function changeTab(containers, links, index) { links .parent() .removeClass('current') .eq(index) .addClass('current'); containers.removeClass('current') .eq(index) .addClass('current'); LiveJournal.run_hook('change_tab', index); } function onClick(evt) { var item = $(this).parent(), index = item.index(), data = evt.data; if (data.containers[index]) { changeTab(data.containers, data.links, index); if (supportHistoryAPI) { window.history.pushState(null, '', this.href); } evt.preventDefault(); } } if (supportHistoryAPI) { $(window).bind('popstate', function () { var data = dataHistory[location.href]; if (data && data.length) { var length = data.length; while (length) { var itemData = data[--length]; changeTab(itemData.containers, itemData.links, itemData.index); } } }); } $.fn.tabsChanger = function(container) { var links = this.children('li').children('a'); if (container) { container = $(container); } else { // next sibling of links container = links.parent().parent().next(); } container = container.children('li'); if (supportHistoryAPI) { links.each(function (index) { var urlData = dataHistory[this.href]; if (!urlData) { urlData = dataHistory[this.href] = []; } urlData.push({ index: index, links: links, containers: container }); }); } links.bind('click', { containers: container, links: links }, onClick); return this; }; })(jQuery); /** jQuery overlay plugin * After creation overlay visibility can be toggled with * $( '#selector' ).overlay( 'show' ) and $( '#selector' ).overlay( 'hide' ) */ jQuery.fn.overlay = function(opts){ var options = { hideOnInit: true, hideOnClick: true }; function Overlay(layer, options){ this.layer = jQuery(layer); this.options = options; this.updateState(this.options.hideOnInit); this.bindEvents(); } Overlay.prototype.bindEvents = function(){ var overlay = this; if(this.options.hideOnClick){ overlay.layer.mousedown(function(ev){ ev.stopPropagation(); }); jQuery(document).mousedown(function(ev){ overlay.updateState(true); ev.stopPropagation(); }); } }; Overlay.prototype.updateState = function(hide){ this.layerVisible = !hide; if(this.layerVisible){ this.layer.show(); } else { this.layer.hide(); } }; Overlay.prototype.proccessCommand = function (cmd){ switch(cmd){ case 'show' : this.updateState(false); break; case 'hide' : this.updateState(true); break; } }; var cmd; if(typeof opts === "string"){ cmd = opts; } return this.each(function(){ if(!this.overlay){ var o = jQuery.extend({}, options, opts || {}); this.overlay = new Overlay(this, o); } if(cmd.length > 0){ this.overlay.proccessCommand(opts) } }); }; /** * Function assures that callback will run not faster then minDelay. * * @param {Function} callback A callback to run. * @param {Number} minDelay Minimum delay in ms. * * @return {Function} Callback wrapper to use as a collback in your code. */ jQuery.delayedCallback = function(callback, minDelay) { var callCount = 2, results, checkFinish = function() { callCount--; if (callCount === 0) { callback.apply(null, results); } } setTimeout(checkFinish, minDelay); return function() { results = [].slice.apply(arguments); checkFinish(); }; }; /** * Fix behavior of select box: trigger change event on keyup */ jQuery.fn.selectFix = function () { 'use strict'; return this.filter('select').on('keyup', function (e) { var code = e.which; if (code >= 37 && code <= 40) { jQuery(this).trigger('change'); } }); }; /** * Provide ability to check if element is on the screen * @author Valeriy Vasin (valeriy.vasin@sup.com) */ ;(function ($) { 'use strict'; // cache window object var $win = $(window); $.expr[':'].screenable = function (element) { var win = {}, el = {}, $el = $(element); // window coordinates win.width = $win.width(), win.height = $win.height(), win.top = $win.scrollTop(), win.bottom = win.top + win.height, win.left = $win.scrollLeft(), win.right = win.left + win.width, // element coordinates el.width = $el.width(); el.height = $el.height(); el.top = $el.offset().top; el.bottom = el.top + el.height; el.left = $el.offset().left; el.right = el.left + el.width; return (el.bottom > win.top && el.top < win.bottom) && (el.right > win.left && el.left < win.right); }; }(jQuery));; /* file-end: js/jquery_fn.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/livejournal.js */ /* --------------------------------------------------------------------------------- file-start: js/core/template.js */ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.tmpl.min.js */ /* * jQuery Templates Plugin 1.0.0pre * http://github.com/jquery/jquery-tmpl * Requires jQuery 1.4.2 * * Copyright 2011, Software Freedom Conservancy, Inc. * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license */ (function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i").join(">").split('"').join(""").split("'").join("'")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;$value={};with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery); ; /* file-end: js/jquery/jquery.tmpl.min.js ----------------------------------------------------------------------------------*/ (function ($, window) { 'use strict'; /* On partner sites LJ and LJ.UI are not defined */ var LJ = window.LJ = window.LJ || {}; LJ.UI = LJ.UI || {}; /** * Private namespace to hold information about templates. */ LJ.UI._templates = {}; /** * Asynchronously load template * * @param {string} name The name of the template. * @param {callback} callback Callback is executed when loading done or error occured */ LJ.UI.loadTemplate = function (name, callback) { var url = '', timestamp = Site.server_time || String(Date.now()).replace(/\d{3}$/, ''); callback = callback || $.noop; timestamp = Math.floor(timestamp / Site.templates_update_time); if (LJ.UI._templates[name]) { callback(undefined, name); return; } url += Site.statprefix + '/tmpl??'; url += name.replace(/^templates-/, '').replace(/-/g, '/') + '.tmpl?'; url += 'tm=' + timestamp; url += ';uselang=' + Site.locale; url += ';v=' + Site.version; $.ajax({ url: url, cache: true, dataType: 'script' }).success(function () { if (LJ.UI._templates[name]) { callback(undefined, name); } else { callback(new Error('Template or server error'), name); console.log('Failed to setup template ' + name); } }).error(function () { callback(new Error('Network error'), name); console.log('Failed to load template ' + name); }); }; /** * Register new template in system. * * @param {string} name The name of the template. * @param {string} id Id of the script tag containing the templates or the template text. * @param {string=jQuery} type Type of the template. Default is jquery templates. */ LJ.UI.registerTemplate = function (name, data, type) { var node, template; type = type || 'JQuery'; switch (type) { case 'JQuery': node = $('#' + data); if (node.length) { $.template(name, node.html()); } else { console.log('Template node #' + data + ' was not found'); return; } break; case 'JQuery.stat': $.template(name, data); type = 'JQuery'; break; } LJ.UI._templates[name] = { type: type, data: data }; }; /** * Render the template with the data. Current version returns jQuery object * but surely should be able to return rendered strings. * * @param {string} name The name of the template. Template should be registered. * @param {Object} data Data object to inset into template * * @return {jQuery} jQuery object containing new markup. */ LJ.UI.template = function(name, data) { var template = LJ.UI._templates[name], message, html; if (!template) { message = 'Warn: template ' + name + ' was called but is not defined yet.'; console.log(message); return $(); } html = $.tmpl(name, data); return html; }; }(jQuery, this)); ; /* file-end: js/core/template.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/track.js */ /* * Methods to track stuff using Google Analytics */ (function() { 'use strict'; LJ.define('LJ.Track'); var trackedTiming = {}; function trackAnalytics(type) { var _gaqDefined = typeof window._gaq === 'object'; if (!_gaqDefined) { console.warn('Google Analytics is not ready'); return false; } var args = Array.prototype.slice.call(arguments), stats = args.filter(Boolean); if (!LJ.get('is_dev_server')) { window._gaq.push(stats); } else { console.info(stats); } return true; } /* * Both functions take arguments as documented here: * https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide * https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTiming * * @example * LJ.Track.event('Category', 'Subcategory', 'Value', some_optional_number); * LJ.Track.timing('Category', 'Subcategory', time_in_ms); */ LJ.Track.event = trackAnalytics.bind(this, '_trackEvent' ); LJ.Track.timing = trackAnalytics.bind(this, '_trackTiming'); /* * Same as LJ.Track.timing, but records timing only once */ LJ.Track.timingOnce = function() { // key should not include timing value var key = JSON.stringify(Array.prototype.slice.call(arguments, 0, 2)); if (!trackedTiming[key]) { LJ.Track.timing.apply(this, arguments); trackedTiming[key] = true; } else { if (Site.is_dev_server) { console.warn('Timing was already tracked'); } } }; })(); /* * Following code sets _noActivity to true * when page is not active for given interval. */ (function($) { var MINUTE = 60 * 1000; var _noActivity = {}; LJ.define('LJ.Activity'); LJ.Activity.isInactiveMoreThan = function(interval) { if (!interval) { return false; } return _noActivity['interval' + interval]; }; LJ.Activity.hasInterval = function(interval) { return _noActivity.hasOwnProperty('interval' + interval); }; /* * @param {Number} interval Inactivity interval in ms to track */ function trackInactive(interval) { var timeout; /* * Setter for _noActivity */ function noActivity(state) { var key = 'interval' + interval; if (_noActivity[key] === state) { return; } _noActivity[key] = state; if (state && LJ.Track) { LJ.Track.event('Site', 'Inactivity', 'Interval ' + Math.floor(interval / MINUTE)); } } function makePageActive() { noActivity(false); clearTimeout(timeout); timeout = setTimeout(function() { noActivity(true); }, interval); } $(document).on( 'click mousemove keypress scroll focus', LJ.Function.throttle(makePageActive, 500) ); makePageActive(); } [5, 10, 15, 20, 25, 30, 35, 40].forEach(function(interval) { trackInactive(interval * MINUTE); }); })(jQuery); ; /* file-end: js/core/track.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/widget.js */ (function ($, window) { 'use strict'; var widgets = {}, unique = 0, baseClass = 'lj-widget', selector = '.' + baseClass; LJ.UI._widgets = widgets; /** * Init widget node * * @param {jQuery} node Node * @param {String} widget Widget name * @param {String} entryPoint Leave empty to init when page is ready */ LJ.UI.initWidgetNode = function (node, widget, entryPoint) { if (node.hasClass(baseClass)) { console.log('Node already has class ' + baseClass); return; } node.addClass(baseClass); node.attr('data-widget', widget); if (entryPoint) { node.attr('data-bootstrap', entryPoint); } }; /** * Init widget on node * * @param {jQuery} node Node */ LJ.UI.initWidget = function (node, force) { var widget = node.data('widget'), options = node.data('widget-options'), bootstrap = node.data('bootstrap') || null, message; if (node.attr('data-widget-id')) { /* Widget already has unique id */ return; } switch (typeof options) { case 'object': /* jQuery parsing was successfull */ break; case 'string': /* Sometimes detection fails (when options string has line breaks) */ try { options = JSON.parse(options || '{}'); } catch (error) { message = 'Invalid options string: ' + options + ' for widget ' + widget; console.log(message); options = {}; } break; } if (force) { if (typeof $.fn[widget] === 'function') { $.fn[widget].apply(node, [options]); } else { message = 'Widget ' + widget + ' was not loaded'; console.log(message); return; } } widgets[++unique] = { ready: !!force, entryPoint: bootstrap, options: options, name: widget, node: node }; node .attr('data-widget-id', unique) .addClass(baseClass) .addClass(baseClass + '-' + unique); }; /** * Cleanup widget by node * * @param {jQuery} node Node */ LJ.UI.removeWidget = function (node) { var id = node.data('widget-id'); if (!node.is(baseClass)) { console.log('Widget was not found on node'); return; } if (widgets.hasOwnProperty(id)) { console.log('Widget ' + id + ' was removed already or never created'); return; } delete widgets[id]; }; /** * Init widgets with specific entry point or all remaining * * @param {String} entryPoint Entry point name */ LJ.UI.bootstrap = function (entryPoint) { var widget, unique, fn, message; $(selector).each(function () { LJ.UI.initWidget($(this)); }); for (unique in widgets) { if (widgets.hasOwnProperty(unique)) { widget = widgets[unique]; if (widget.ready) { continue; } if (!entryPoint || widget.entryPoint === entryPoint) { fn = $.fn[widget.name]; if (typeof fn === 'function') { fn.apply(widget.node, [widget.options]); widget.ready = true; } else { message = 'Widget ' + widget.name + ' was not loaded'; console.log(message); continue; } } } } }; }(jQuery, this)); ; /* file-end: js/core/widget.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.lj.share.js */ /* --------------------------------------------------------------------------------- file-start: js/core/object.js */ ;(function() { 'use strict'; LJ.define('LJ.Object'); /** * Return a copy of the object only containing the whitelisted properties. * @param {Object} obj Object source * @param {String} keys* Keys which should be picked from source object * @return {Object} Copy of source object that contains only whitelisted keys */ LJ.Object.pick = function(obj) { var copy = {}, keys = Array.prototype.concat.apply( [], Array.prototype.slice.call(arguments, 1) ); keys.forEach(function (key) { if (key in obj) { copy[key] = obj[key]; } }); return copy; }; })();; /* file-end: js/core/object.js ----------------------------------------------------------------------------------*/ LJ.injectStyle('.ljshare-container {\n position: absolute;\n border: 1px solid #555;\n -moz-border-radius: 4px;\n background-color: #fff;\n padding: 0.1em;\n line-height: 1.3em;\n}\n\n.ljshare-service-list li {\n border: 1px solid #fff;\n padding: 0.1em;\n}\n\n.ljshare-service-list li:hover {\n background-color: #eee;\n border: 1px solid #bbb;\n -moz-border-radius: 2px;\n cursor: pointer;\n}\n'); LJ.UI.registerTemplate('templates-Widgets-share', "", 'JQuery.stat'); /** * @author Valeriy Vasin (valeriy.vasin@sup.com) * @fileOverview Plugin is responsible for sharing functionality * @requires jquery.lj.bubble.js */ ;(function ($) { 'use strict'; /** * @todo Remove service defaults from JavaScript. It should come from server */ // services defaults that will be used if server doesn't provide `services` option var SERVICES = { livejournal: { title: 'LiveJournal', bindLink: 'http://livejournal.com/update.bml?repost_type=c&repost={url}', openInTab: true }, facebook: { title: 'Facebook', bindLink: 'http://www.facebook.com/sharer.php?u={url}' }, twitter: { title: 'Twitter', bindLink: 'http://twitter.com/share?url={url}&text={title}&hashtags={hashtags}' }, vkontakte: { title: 'Vkontakte', bindLink: 'http://vkontakte.ru/share.php?url={url}' }, moimir: { title: 'Moi Mir', bindLink: 'http://connect.mail.ru/share?url={url}' }, stumbleupon: { title: 'Stumbleupon', bindLink: 'http://www.stumbleupon.com/submit?url={url}', openInTab: true }, digg: { title: 'Digg', bindLink: 'http://digg.com/submit?url={url}', openInTab: true }, email: { title: 'E-mail', bindLink: 'http://api.addthis.com/oexchange/0.8/forward/email/offer?username=internal&url={url}&title={title}', height: 600 }, tumblr: { title: 'Tumblr', bindLink: 'http://www.tumblr.com/share?v=3&u={url}&description={text}' }, odnoklassniki: { title: 'Odnoklassniki', bindLink: 'http://www.odnoklassniki.ru/dk?st.cmd=addShare&st.s=1&st._surl={url}' } }; $.widget('lj.share', $.lj.basicWidget, { options: { selectors: { // button that activate bubble button: '.js-lj-share', item: '.b-sharethis-item', entry: '.js-lj-share-entry' }, templates: { share: 'templates-Widgets-share' }, ml: { title: 'sharing.popup.title' }, // should come from server or initialize with defaults above services: null, // services to show links: null, bubble: true }, _create: function () { $.lj.basicWidget.prototype._create.call(this); // bubble container if (this.options.bubble) { this._container = $('
').appendTo( this.element ); } // currently active share button (needed to allow toggle bubble state) this._button = null; // services option hasn't been initialized explicitly if ( !this.options.services ) { // initialize from server params if (LJ.get('LJShareParams.services')) { this.options.services = LJ.get('LJShareParams.services'); } else { // use defaults this.options.services = SERVICES; } } // links opition hasn't been initialized explicitly if ( !this.options.links ) { // initialize from server options if (LJ.get('LJShareParams.links')) { this.options.links = LJ.get('LJShareParams.links'); } else { // use defaults this.options.links = this.options.services ? Object.keys(this.options.services) : []; } } if (this.options.bubble) { this._bindControls(); } }, _bindControls: function () { var that = this; $.lj.basicWidget.prototype._bindControls.call(this); // init bubble this._container.bubble(); // click on sharing item inside sharing bubble this._container.on('click', this._s('item'), function (e) { that._share(e, this); }); // click on sharing button this.element.on('click', this._s('button'), function (e) { that.shareButtonClick(e, this); }); // click on share entry button this.element.on('click', this._s('entry'), function (e) { var service, params, link; e.preventDefault(); service = $(this).data('service'); params = that.getParams(this); link = that.createSharingLink(service, params); that.shareLink(link, service); }); // handler for all layouts where we could not change html-code // and provide needed data-attributes and classname this.element.on('click', 'a', function (e) { var $this = $(this); // only sharing button click handler should work if ( $this.is( that._s('button') ) ) { return; } // only entry click hangler should work if ( $this.is( that._s('entry') ) ) { return; } // only item click handler should work if ( $this.is( that._s('item') ) ) { return; } that.shareButtonClick(e, this, true); }); }, /** * Parse params from target node * @param {HTMLElement} target Share button node * @return {Object} Params needed for sharing (double encoded) */ getParams: function (target) { var data = $(target).data(), params = LJ.Object.pick(data, 'url', 'title', 'hashtags', 'text'), href, args, matches; // try to parse from link href and query string if ( !params.url ) { href = target.href; args = LiveJournal.parseGetArgs( href ); if (typeof args.title !== 'undefined') { params.title = args.title; } if (typeof args.hashtags !== 'undefined') { params.hashtags = args.hashtags; } if (typeof args.text !== 'undefined') { params.text = args.text; } matches = href.match(/(.*\.html)/); if (matches && matches[1]) { // encode url because other params are escaped and server needs double escaping params.url = encodeURIComponent(matches[1]); } // we should have title or hashtags inside the query string if ( typeof params.title === 'undefined' && typeof params.hashtags === 'undefined' ) { return null; } } // double escape needed params, because server unescapes them during redirect // also set default value for params that not provided params.url = encodeURIComponent(params.url); params.title = encodeURIComponent(params.title || ''); params.text = encodeURIComponent(params.text || ''); params.hashtags = params.hashtags || ''; return params; }, /** * Handler for Share button click * @param {jQuery.Event} e jQuery event object * @param {HTMLElement} target Share button node */ shareButtonClick: function (e, target) { var $target = $(target), isCurrentButtonPressed = this._button === target, params = this.getParams(target); // prevent default action only for links sharing could be applied for if ( !params ) { return; } e.preventDefault(); // just hide bubble if it's showed and we click on same share button again if (this._container.bubble('visible') && isCurrentButtonPressed) { this._container.bubble('hide'); return; } // update bubble target and content if (this._button !== target) { this._setContentFor(params); this._container.bubble('option', 'target', $target); this._button = target; } // show bubble this._container .bubble('block', true) // prevent hiding bubble when click event bubbles to the document .bubble('show'); return this; }, /** * Share link handler * @param {jQuery.Event} e jQuery event object * @param {HTMLElement} target Share item link node */ _share: function (e, target) { var $target = $(target), service = $target.data('service'), serviceObj = this.options.services[service]; if ( !serviceObj ) { console.error('Service is not defined.'); return; } // if we are trying to open in tab and browser supports it (IE > 8) // we should not prevent default action if ( !serviceObj.openInTab || ($.browser.msie && $.browser.version < 9) ) { e.preventDefault(); } this._container.bubble('hide'); this.shareLink(target.href, service); }, /** * Share link for service */ shareLink: function (url, service) { var serviceObj = this.options.services[service], width, height; if ( !serviceObj ) { console.error('Service is not defined.'); return; } if (serviceObj.openInTab) { /** * Notice: Internet Explorer version less than 9 doesn't support * opening links with target='_blank' in new tab and open * link in new window by default (depends on settings) * That's why we simulate this behavior through new window with * correct width and height params */ if ($.browser.msie && $.browser.version < 9) { width = $(window).width(); height = $(window).height(); window.open(url, null, 'toolbar=yes,menubar=yes,status=1,location=yes,scrollbars=yes,resizable=yes,width=' + width + ',height=' + height); } /** * all other browsers support target='_blank' * and we should do nothing for opening in new tab */ } else { width = serviceObj.width || 640; height = serviceObj.height || 480; window.open(url, 'sharer', 'toolbar=0,status=0,width=' + width + ',height=' + height + ',scrollbars=yes,resizable=yes'); } }, /** * Create sharing link for exact service * @param {String} service Service for which url should be generated * @param {String} params Params for url creation (title, url, etc) * @return {String} Sharing link for provided service */ createSharingLink: function (service, params) { var serviceObj = this.options.services[service]; if ( !serviceObj || !serviceObj.bindLink ) { console.error('Service parameters error. URL cant be generated.'); return; } return serviceObj.bindLink.supplant( params ); }, /** * Update sharing bubble content * @param {Object} params Object for sharing links construction * @param {String} params.url Url to share * @param {String} [params.title] Title for sharing url (for some services: FB, Twitter, email) * @param {String} [params.hashtags] Hashtags for twitter * @param {String} [params.text] Entry text */ _setContentFor: function (params) { var content, that = this; // update content should always be applied when bubble is hidden if ( this._container.bubble('visible') ) { this._container.bubble('hide'); } // update bubble content content = this._tmpl('share', { title: this._ml('title'), items: this.options.links.map(function (serviceName) { var service = that.options.services[serviceName], shareURL = service.bindLink.supplant(params); return { service: serviceName, url: shareURL, title: service.title }; }) }); this._container.html(content); }, /** * Sharing items inside the bubble */ items: function () { return this ._container .find( this._s('item') ); }, /** * Hide sharing bubble */ hide: function () { this._container.bubble('hide'); }, _setOption: function (option, value) { if (typeof value === 'undefined') { return; } switch (option) { case 'services': this.options.services = $.extend(true, {}, this.options.services || {}, value); break; case 'links': this.options.links = value; break; // no defaults } } }); }(jQuery)); ; /* file-end: js/jquery/jquery.lj.share.js ----------------------------------------------------------------------------------*/ // This file contains general-purpose LJ code var LiveJournal = {}; /** * @deprecated Deprecated methods (for backward compatibility only) */ LiveJournal.register_hook = LJ.Event.on; LiveJournal.remove_hook = LJ.Event.off; LiveJournal.run_hook = LJ.Event.trigger; (function($) { LiveJournal.initPage = function () { //LJRU-3137: The code relies on the Site global variable //so it appears on all livejournal pages. If it's //not there than we are on the external site. if (!window.Site) { return; } // when page loads, set up contextual popups $(ContextualPopup.setupLive); if (LJ.Api) { LJ.Api.init({ auth_token: LJ.get('auth_token') }); } LJ.UI.bootstrap(); //register system hooks LJ.Event.on('update_wallet_balance', LiveJournal.updateWalletBalance); LJ.Event.on('xdr/message', LiveJournal.processXdr); LiveJournal.initSpoilers(); LiveJournal.initResizeHelper(); //ljuniq cookie is checked here now instead of PageStats/Omniture.pm LiveJournal.checkLjUniq(); // run other hooks LJ.Event.trigger('page_load'); // Lazy like buttons loader $(document.body).ljLikes(); if (LJ.get('LJShareParams')) { var s1 = LJ.get('comments'), feed = LJ.get('entryUniqs'); $(document.body).share( /* * On s1 entries Share controller is used to * display the bubble, check entry/main.js. */ (s1 || feed) ? { bubble: false } : {} ); } /* * Remove repost */ $('.js-delete-repost').on('click', function(event) { event.preventDefault(); LJ.Event.trigger('repost.requestRemove', this, $(this).attr('href')); }); LiveJournal.initBanner(); LiveJournal.initMobileLink(); }; LiveJournal.initMobileLink = function() { $(document.body).on('click', '.b-message-mobile-close', function(event) { var oneWeek = new Date(); event.preventDefault(); oneWeek.setDate(oneWeek.getDate() + 7); LJ.Cookie.set('hide_mobile_link', 1, { expires: oneWeek, domain: window.location.host.replace('www', '') }); $(document.body).addClass('p-mobile-msg-off'); }); }; })(jQuery); /** * Special helper class is added to the body if browser doesn't support media queries and * screen width is less then 1000px. */ LiveJournal.initResizeHelper = function() { var $window = jQuery(window), $body = jQuery('body'), hasClass = false, resizeFunc = LJ.Function.throttle(function() { if ($window.width() <= 1000) { if (!hasClass) { $body.addClass('l-width1000'); hasClass = true; } } else if (hasClass) { $body.removeClass('l-width1000'); hasClass = false; } }, 500); //Only older ies need thes (caniuse.com) if (jQuery.browser.msie && Number(jQuery.browser.version) <= 8) { $window.on('resize', resizeFunc); resizeFunc(); } }; /** * Spoilers functionality - expand hidden text in posts when user clicks on corresponding link */ LiveJournal.initSpoilers = function() { jQuery(document).delegate('.lj-spoiler > .lj-spoiler-head a', 'click', function (evt) { evt.preventDefault(); jQuery(this).closest('.lj-spoiler').toggleClass('lj-spoiler-opened'); }); }; /** * Translate message from xdreceiver. The function will eventually be run * from xdreceiver.html helper frame to send messages between different domains. * * @param {Object} message Object with the message. Object should always contain type field with event name */ LiveJournal.processXdr = function(message) { if (message.type) { var type = decodeURIComponent(message.type); } else { return; } var messageCopy = {}; for (var name in message) { if (message.hasOwnProperty(name) && name !== 'type') { messageCopy[name] = decodeURIComponent(message[name]); } } LiveJournal.run_hook(type, messageCopy); }; //refresh number of tokens in the header LiveJournal.updateWalletBalance = function () { jQuery.get(LiveJournal.getAjaxUrl('get_balance'), function(resp) { if (! resp || resp.status != 'OK') { return; } var newBalance = resp.balance ? parseInt(resp.balance, 10) : 0; var balance = $('LJ_Wallet_Balance'); if (balance) { if (resp.balance) { balance.innerHTML = balance.innerHTML.replace(/\d+/, newBalance); } else { balance.innerHTML = ''; } } else { balance = $('LJ_Wallet_Balance_Controlstrip'); if (balance) { balance.innerHTML = newBalance; } } LiveJournal.run_hook('balance_updated', resp.balance); }, 'json'); }; // handy utilities to create elements with just text in them function _textSpan() { return _textElements('span', arguments); } function _textDiv() { return _textElements('div', arguments); } function _textElements(eleType, txts) { var ele = []; for (var i = 0; i < txts.length; i++) { var node = document.createElement(eleType); node.innerHTML = txts[i]; ele.push(node); } return ele.length == 1 ? ele[0] : ele; } LiveJournal.pollAnswerClick = function(e, data) { if (!data.pollid || !data.pollqid) { return false; } var xhr = jQuery.post(LiveJournal.getAjaxUrl('poll'), { pollid : data.pollid, pollqid : data.pollqid, page : data.page, pagesize : data.pagesize, action : 'get_answers' }, function(data, status) { status == 'success' ? LiveJournal.pollAnswersReceived(data) : LiveJournal.ajaxError(data); }, 'json'); jQuery(e).hourglass(xhr); return false; }; LiveJournal.pollAnswersReceived = function(answers) { if (!answers || !answers.pollid || !answers.pollqid) { return; } if (answers.error) { return LiveJournal.ajaxError(answers.error); } var id = '#LJ_Poll_' + answers.pollid + '_' + answers.pollqid, to_remove = '.LJ_PollAnswerLink, .lj_pollanswer, .lj_pollanswer_paging', html = '
' + (answers.answer_html || '(No answers)') + '
'; answers.paging_html && (html += '
' + answers.paging_html + '
'); jQuery(id) .find(to_remove) .remove() .end() .prepend(html) .find('.lj_pollanswer'); }; // gets a url for doing ajax requests LiveJournal.getAjaxUrl = function(action, params) { // if we are on a journal subdomain then our url will be // /journalname/__rpc_action instead of /__rpc_action var uselang = LiveJournal.parseGetArgs(location.search).uselang; if (uselang) { action += '?uselang=' + uselang; } if (params) { action += (uselang ? '&' : '?') + jQuery.param(params); } return LJ.get('currentJournal') ? '/' + LJ.get('currentJournal') + '/__rpc_' + action : '/__rpc_' + action; }; // generic handler for ajax errors LiveJournal.ajaxError = function (err) { if (LJ_IPPU) { LJ_IPPU.showNote('Error: ' + err); } else { alert('Error: ' + err); } }; // given a URL, parse out the GET args and return them in a hash LiveJournal.parseGetArgs = function (url) { url = url || window.location.href; url = url.replace(/#.*$/, ''); var getArgsHash = {}; var urlParts = url.split('?'); if (!urlParts[1]) { return getArgsHash; } var getArgs = urlParts[1].split('&'); for (var arg = 0; arg < getArgs.length; arg++) { var pair = getArgs[arg].split('='); getArgsHash[pair[0]] = pair[1]; } return getArgsHash; }; /** * Construct an url from base string and params object. * * @param {String} base Base string. * @param {Object} args Object with arguments, that have to be passed with the url. * @return {String} */ LiveJournal.constructUrl = function(base, args, escapeArgs) { base = base.replace(/(\&|\?)+$/g, ''); var queryStr = base, queryArr = []; if (args) { queryStr += ( base.indexOf('?') === -1 ? '?' : '&' ); for (var i in args) { queryArr.push(i + '=' + ( ( escapeArgs ) ? encodeURIComponent(args[i]) : args[i] )); } } return queryStr + queryArr.join('&'); }; /** * Generate a string for ljuniq cookie * * @return {String} */ LiveJournal.generateLjUniq = function() { var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', result = '', i; var len = 15; for (i = 0; i < len; ++i) { result += alpha.charAt(Math.floor(Math.random() * ( alpha.length - 1 ))); } result += ':' + Math.floor((new Date()) / 1000); result += ':pgstats' + ( ( Math.random() < 0.05 ) ? '1' : '0' ); return result; }; LiveJournal.checkLjUniq = function() { if (!Cookie('ljuniq')) { Cookie('ljuniq', LiveJournal.generateLjUniq(), { domain: LJ.get('siteroot').replace(/^https?:\/\/www\./, ''), expires: 5000, path: '/' }); } }; LiveJournal.closeSiteMessage = function(node, e, id) { jQuery.post(LiveJournal.getAjaxUrl('close_site_message'), { messageid: id }, function(data, status) { if (status === 'success') { jQuery(node.parentNode.parentNode.parentNode).replaceWith(data.substitude); } else { LiveJournal.ajaxError(data); } }, 'json'); }; LiveJournal.getLocalizedStr = LJ.ml; LiveJournal.JSON = JSON; LiveJournal.initBanner = function() { var slot = jQuery('.common-banner'); if (!slot.length || LJ.Cookie.get('common_banner_close') || !LJ.get('remoteUser')) { return; } // add close handler slot.find('.common-banner-close').show().on('click', function () { var expires = new Date(); // release cookie time: 00:00:01 of tomorrow expires.setDate( expires.getDate() + 1 ); expires.setHours(0); expires.setMinutes(0); expires.setSeconds(1); slot.remove(); LJ.Cookie.set('common_banner_close', '1', { expires: expires, domain: LJ.get('siteroot').replace(/^https?:\/\/www\./, ''), path: '/' }); }); }; ; /* file-end: js/livejournal.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.lj.bubble.js */ LJ.UI.registerTemplate('templates-Widgets-bubble', "
{{if !($data.modal)}} {{/if}}
", 'JQuery.stat'); /** * @name $.lj.bubble * @author sergey.zhirkov@sup.com (Sergey Zhirkov) * @author dmitry.petrov@sup.com (Dmitry Petrov) * @author artem.tyurin@sup.com (Artem Tyurin) * @author anazarov@sup.com (Alexander Nazarov) * @author valeriy.vasin@sup.com (Valeriy Vasin) * * @requires $.ui.core, $.ui.widget, $.lj.basicWidget * @class Wraps some content with pop-up "bubble", positioned relative to target or absolute (like modal window) * @extends $.lj.basicWidget */ /* * Usage: * * */ /** * @example * // bubble will be always at the left * $node.bubble({ * target: $('div.target'), * showOn: 'click', * forcePosition: 'left' * }); * * // bubble will be always positioned at right side and under the target * $node.bubble({ * target: $('div.target'), * showOn: 'click', * forcePosition: { * right: true, * bottom: true * } * }); * * // Obsolete option `alwaysShowUnderTarget` is also supported and could be mixed * // with `forcePosition` option. * // Notice: to mix this options you should set `forcePosition` via hash, not string * * // bubble will be always positioned at right side and under the target * $node.bubble({ * target: $('div.target'), * showOn: 'click', * alwaysShowUnderTarget: true, * forcePosition: { * right: true * } * }); */ (function ($, window) { $.widget('lj.bubble', $.lj.basicWidget, { options: { target: null, currentTarget: null, hoverTimer: null, hoverDelay: 600, showDelay: 0, position: { x: 0, y: 0 }, /** * offset object can contain directly fields x and y or fields l,r,t,b,tl,tr,bl,br * that contain offset object for the bubble in the exact position. * Priority order: x,y -> tl,bl,tr,br -> t,b -> l,r */ offset: {}, // horizontal align relative to target elem // TODO "right" align align: 'center', // left || center || side // always show under target elem (even if bubble node does not fit screen height) alwaysShowUnderTarget: false, /** * Set bubble position directly (without screen position restrictions) * bubble wherever we want forcely: e.g. set top left corner * It could contain four fields: { top, left, bottom, right } * If top and left are set to true, right and bottom are not important * * @type {Object|Boolean|String} */ forcePosition: false, closeControl: true, closeOnContentClick: false, closeOnDocumentClick: true, closeOnEscape: true, // show on special event triggered by target (no action by default - "false") showOn: false, // 'click' || ('hover' || 'mouseover') || 'focus' || false showEffect: '', //can be fade preventDefaultTargetClick: true, modal: false, classNames: { containerAddClass: '', //if this value is set it will add this class to the top node positionPrefix: 'i-popup-arr', arrowDefault: 'i-popup-arr', withCloseControl: 'b-popup-withclosecontrol', noCloseControl: 'b-popup-noclosecontrol' }, selectors: { bubbleNode: 'div.bubble-node', bubbleArrow: 'i.i-popup-arr', bubbleInner: 'div.b-popup-inner', closeControl: 'i.i-popup-close', fader: '.b-fader' }, templates: { fader: '', node: 'templates-Widgets-bubble' } }, // private methods _create: function () { var ljBubble = this, options = ljBubble.options, selectors = options.selectors; $.lj.basicWidget.prototype._create.apply(this); $.lj.basicWidget.prototype._bindControls.apply(this); // workaround for previous `alwaysShowUnderTarget` option if (options.alwaysShowUnderTarget) { if (typeof options.forcePosition === 'string') { this._setOption('forcePosition', options.forcePosition); } options.forcePosition = options.forcePosition || {}; options.forcePosition.bottom = true; } //this flag is needed because we cannot simply top propogation //on content click - user won't be able to open links. this.blockDocumentClick = false; // wrap bubble content with bubble outer html this._base = ljBubble._makeNode(); this._on('documentClick', function() { if (options.closeOnDocumentClick && !ljBubble.blockDocumentClick) { ljBubble.hide(); } else { ljBubble.blockDocumentClick = false; } }); this._window = $(window); this._body = $('body'); /* * If set to true will prevent bubble from hiding. */ this._preventHide = false; // set default options ljBubble._setOptions(options); }, _setOption: function (option, value) { var ljBubble = this, options = ljBubble.options, classNames = options.classNames, eventNamespace = '.' + ljBubble.widgetName + '-' + option, currentShowOn = options.showOn, newValue; switch (option) { case 'forcePosition': // support string value (one side restriction) if (typeof value === 'string' && /^left|right|top|bottom$/.test(value) ) { options.forcePosition = {}; options.forcePosition[value] = true; } else if (typeof value === 'object' && value !== null) { // prevent change option outside of widget options.forcePosition = $.extend({}, value); } // no need in option set return; case 'target': newValue = $(value); if(options.target && options.target[0] === newValue[0]) { break; } //if target changes we should rebind all events from the old one. //we don't if the old one is a string or an ordinary node, because //it can happen only on init if (options.target && typeof options.target !== 'string' && ('length' in options.target)) { this._setOption('showOn', false); options.target = newValue; this._setOption('showOn', currentShowOn); } else { options.target = $(value); } // no need in option set return; case 'closeControl': if (value) { ljBubble.bubbleNode .delegate(options.selectors.closeControl, 'click' + eventNamespace, function (event) { ljBubble.hide(); }) .removeClass(classNames.noCloseControl) .addClass(classNames.withCloseControl); } else { ljBubble.bubbleNode .undelegate(options.selectors.closeControl, 'click' + eventNamespace) .removeClass(classNames.withCloseControl) .addClass(classNames.noCloseControl); } break; case 'position': ljBubble.bubbleNode.css({ left: value.x, top: value.y }); break; case 'showOn': value = (value === 'mouseover') ? 'hover' : value; if (value === 'click') { options.target.bind('click' + eventNamespace, function (event) { var target = $(this); event.preventDefault(); ljBubble.blockDocumentClick = true; if (ljBubble._visible) { ljBubble.hide(); } else { ljBubble.show(target); } }); } else { options.target.unbind('click' + eventNamespace); } if (value === 'hover') { options.target .add(ljBubble.bubbleNode) .bind('touchstart' + eventNamespace + ' mouseenter' + eventNamespace, function () { var target = this; clearTimeout(options.hoverTimer); options.hoverTimer = setTimeout(function () { ljBubble.show(target); }, options.showDelay); }) .bind('mouseleave' + eventNamespace, function () { clearTimeout(options.hoverTimer); options.hoverTimer = setTimeout(function () { ljBubble.hide(); }, options.hoverDelay); }); } else { options.target .add(ljBubble.bubbleNode) .unbind('touchstart' + eventNamespace) .unbind('mouseenter' + eventNamespace) .unbind('mouseleave' + eventNamespace); } if (value === 'focus') { options.target .bind('focus' + eventNamespace, function (event) { var target = $(this); ljBubble.blockDocumentClick = true; event.preventDefault(); event.stopPropagation(); ljBubble.show(target); }); // @BUG: this was commented out because click on the bubble // content triggers blur event. // .bind('blur' + eventNamespace, function (event) { // ljBubble.hide(); // }); } else { options.target .unbind('focus' + eventNamespace) .unbind('blur' + eventNamespace); } break; case 'preventDefaultTargetClick': if (value) { options.target.bind('click' + eventNamespace, function (event) { event.preventDefault(); }); } else { options.target.unbind('click' + eventNamespace); } break; case 'closeOnEscape': if (value) { $(document).bind('keydown' + eventNamespace, function (event) { // escape if (event.keyCode === 27) { if (ljBubble._visible) { ljBubble.hide(); //we're doing preventDefault, because Firefox drops ALL internet connection //on esc key, event xhr, sorry. event.preventDefault(); } } }); } else { $(document).unbind('keydown' + eventNamespace); } break; case 'closeOnContentClick': if (!value) { ljBubble.bubbleNode.bind('mousedown' + eventNamespace + ' click' + eventNamespace, function (event) { ljBubble.blockDocumentClick = true; }); } else { ljBubble.bubbleNode.unbind('mousedown' + eventNamespace + ' click' + eventNamespace); } break; } options[option] = value; }, _makeNode: function () { var bubbleNode = this.options.outerHtml? $(this.options.outerHtml) : this._tmpl('node', this.options), bubbleArrow = bubbleNode.find(this.options.selectors.bubbleArrow), bubbleInner = bubbleNode.find(this.options.selectors.bubbleInner), body = $('body'); // this.element - with bubble content this.element .css('display', 'block') .prependTo(bubbleInner); if (this.options.modal) { this._el('fader', body); if (!this._fader.length) { this._fader = $(this.options.templates.fader).prependTo(body); } } this.bubbleNode = bubbleNode.prependTo(body); this.bubbleArrow = bubbleArrow; // store arrow elem position bubbleNode.css({ visibility: 'hidden', display: 'block' }); var containerAddClass = this.options.classNames.containerAddClass, position; //additional class is needed to customize look and behavior of bubble if needed if (containerAddClass && containerAddClass.length > 0) { bubbleNode.addClass(containerAddClass); } position = bubbleArrow.position() || {}; bubbleArrow.data({ 'left': position.left, 'top': position.top }); bubbleNode.css({ visibility: 'visible', display: 'none' }); return bubbleNode; }, _getPosition: function (targetControl, offset) { var targetImg; targetControl = targetControl || this.options.currentTarget; targetImg = targetControl.find('img').first(); // if there is image in target (like this: ) - bubble will be positioned relative to image if (targetImg.length) { targetControl = targetImg; } if (this.options.modal) { return { position: { x: '50%', y: '50%' } }; } var ljBubble = this, viewport = this._window, body = this._body, options = ljBubble.options, align = options.align, alwaysShowUnderTarget = options.alwaysShowUnderTarget, viewportWidth = viewport.width(), viewportHeight = viewport.height(), viewportScrollLeft = body.prop('scrollLeft'), elem = ljBubble.bubbleNode, elemWidth = elem.width(), elemHeight = elem.height(), popupArrow = ljBubble.bubbleArrow, popupArrowLeft = popupArrow.data('left'), popupArrowTop = popupArrow.data('top'), popupArrowWidth = 13, // popup arrow drawn with borders (6px at left and right side) targetOffset = targetControl.offset(), targetLeft = Math.round(targetOffset.left), targetTop = Math.round(targetOffset.top), targetWidth = targetControl.width(), outerWidth = targetControl.outerWidth(), targetHeight = targetControl.height(), scrollOffset = viewport.scrollTop(), leftPositionX, rightPositionX, topPositionY, bottomPositionY, arrowPositionType, arrowPositionTypes, position, checkAngle, arrowClass; switch (align) { case 'center': topPositionY = targetTop - popupArrowTop + targetHeight; leftPositionX = Math.floor( targetLeft + (targetWidth / 2) - popupArrowLeft - (popupArrowWidth / 2) ); break; case 'left': leftPositionX = targetLeft; topPositionY = targetTop - popupArrowTop + targetHeight; break; case 'side': leftPositionX = targetLeft + outerWidth - popupArrowTop; topPositionY = Math.round(targetTop - (targetHeight / 2)); break; } rightPositionX = targetLeft + Math.floor( (targetWidth / 2) - (elemWidth - popupArrowLeft - popupArrowWidth / 2) ); bottomPositionY = targetTop + popupArrowTop - elemHeight; arrowPositionType = { x: 'l', // left y: 't' // top }; arrowPositionTypes = { 'lt': { x: leftPositionX, y: topPositionY }, 'tl': { x: leftPositionX, y: topPositionY }, 'tr': { x: rightPositionX, y: topPositionY }, 'bl': { x: leftPositionX, y: bottomPositionY }, 'br': { x: rightPositionX, y: bottomPositionY } }; checkAngle = { x: leftPositionX + elemWidth, y: topPositionY + elemHeight }; // Check bubble position relative to the viewport and fix it if needed (function () { var isUnder, isRighter; function isRighterThanViewport() { if (typeof isRighter === 'undefined') { isRighter = checkAngle.x > viewportWidth + viewportScrollLeft; } return isRighter; } function isUnderViewport() { if (typeof isUnder === 'undefined') { isUnder = checkAngle.y > viewportHeight + viewport.scrollTop() && bottomPositionY > 0; } return isUnder; } if (options.forcePosition) { if (options.forcePosition.left) { arrowPositionType.x = 'r'; } else if (options.forcePosition.right) { arrowPositionType.x = 'l'; } else { // left is by default if ( isRighterThanViewport() ) { arrowPositionType.x = 'r'; // right } } /** * Notice: * Top and bottom sides are changed for bubble position * 't' - bubble is under the target * 'b' - bubble is above the target */ if (options.forcePosition.top) { arrowPositionType.y = 'b'; } else if (options.forcePosition.bottom) { arrowPositionType.y = 't'; } else { // 't' is by default if ( isUnderViewport() ) { arrowPositionType.y = 'b'; // bottom } } } else { if ( isRighterThanViewport() ) { arrowPositionType.x = 'r'; // right } if ( isUnderViewport() ) { arrowPositionType.y = 'b'; // bottom } } }()); if (align === 'side') { arrowPositionType = arrowPositionType.x + arrowPositionType.y; } else { arrowPositionType = arrowPositionType.y + arrowPositionType.x; } arrowClass = options.classNames.positionPrefix + arrowPositionType; if (arrowClass !== this._arrowClass) { this._arrowClass = arrowClass; popupArrow .removeClass() .addClass(options.classNames.arrowDefault) .addClass(arrowClass); } position = arrowPositionTypes[arrowPositionType]; if (this.tempOffset) { position.x += this.tempOffset.x; position.y += this.tempOffset.y; delete this.tempOffset; } else { position = this._applyOffset( position, arrowPositionType ); } return { position: position, bubblePosition: arrowPositionType }; }, _updatePosition: function () { var newPosition = this._getPosition(); this.option('position', newPosition.position); return newPosition; }, _applyOffset: function( position, bubblePosition ) { var offset = this.options.offset, offsetObj; if( 'x' in offset ) { offsetObj = offset; } else { offsetObj = offset[ bubblePosition ] || offset[ bubblePosition.charAt( 0 ) ] || offset[ bubblePosition.charAt( 1 ) ]; } if( offsetObj ) { position.x += offsetObj.x; position.y += offsetObj.y; } return position; }, /* * Show bubble * @param {jQuery} target Bubble target * @param {object} tempOffset Temporary offset */ show: function (target, tempOffset) { var ljBubble = this, node = this.bubbleNode, options = ljBubble.options, position; this.tempOffset = tempOffset; //prevent delayed mouseout event clearTimeout(this.options.hoverTimer); target = (target) ? $(target) : options.target; $(':lj-bubble') .not(ljBubble.element) .bubble('hide'); if (!this._visible) { this._visible = true; this.option('currentTarget', target); position = this._updatePosition(); if (this.options.modal) { this._fader.css({ display: 'block' }); node.css({ 'margin-left': -node.width() / 2, 'margin-top': -node.height() / 2, position: 'fixed' }); } if (this.options.showEffect === 'fade') { node.fadeIn(200); } else { node.show(); } } this._trigger('show', null, [{ position: position }]); return this; }, /** * Hide bubble */ hide: function () { if ( this._preventHide ) { return this; } //prevent delayed mouseout event clearTimeout(this.options.hoverTimer); if (!this._visible) { //do not fire events if bubble is already hidden return; } else { this._visible = false; } if (this.options.modal) { this._fader.css({ display: 'none' }); } this.bubbleNode.hide(); this._trigger('hide'); return this; }, /** * Reposition bubble on the page. The method is needed to reposition bubble * in case when it's content is changed and it remains visible at the same time. */ updatePosition: function() { if (this._visible) { this._updatePosition(); } }, absolute: function(_x, _y) { this.option('position', {x: _x, y: _y}); }, move: function(_x, _y) { var p = this._getPosition(); this.option('position', {x: _x, y: _y}); }, block: function(block) { this.blockDocumentClick = block; }, base: function() { return this._base; }, /** * Determines whether bubble is currently visible * @return {boolean} true if currently visible */ visible: function() { return this.bubbleNode.is(':visible'); }, /** * Setter for _preventHide property * @param {boolean} if set to true, will not hide bubble */ setPreventHide: function( val ) { this._preventHide = !!val; }, /** * Getter for _preventHide property */ isHidePrevented: function() { return this._preventHide; } }); })(jQuery, this); ; /* file-end: js/jquery/jquery.lj.bubble.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/journal.js */ /* --------------------------------------------------------------------------------- file-start: js/entry/likes.js */ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.vkloader.js */ /*! * LiveJournal loader for vkontakte like buttons. * * Copyright 2011, dmitry.petrov@sup.com * * VK script is often loaded with notable delay, so * plugin just loads it after the page rendering and * allows to display page faster. * */ (function ($) { 'use strict'; if ($.VK) { return; } $.VK = {}; var onloads = [], buttons = [], onloadPassed = false, scriptLoaded = false, scriptLoading = false; /** * Public API * * @namespase $.VK */ $.VK = { /** * Init VK object after the script load. * Function passes all option to the VK.init * @param {Object} options */ init: function( options ) { onloads.push(function() { VK.init( options ); }); }, /** * Add button to init after script load. * If this method was called after the page load, and script wasn't downloaded yet, * it will trigger downloading. */ addButton: function( elementId, options ) { buttons.push( { id: elementId, options: options } ); if( onloadPassed && !scriptLoading ) { if( scriptLoaded ) { initButtons(); } else { loadScript( initButtons ); } } } }; function initButtons() { for( var i = 0; i < buttons.length; ++i ) { VK.Widgets.Like( buttons[ i ].id, buttons[ i ].options ); } buttons = []; } function loadScript( onload ) { onload = onload || $.noop; scriptLoading = true; $.getScript( 'http://userapi.com/js/api/openapi.js?31', function() { scriptLoading = false; scriptLoaded = true; for( var i = 0; i < onloads.length; ++i ) { onloads[ i ](); } onloads = []; onload(); } ); } LiveJournal.register_hook('page_load', function() { //Do not download the script if the widgets were not added yet. if (buttons.length) { //Do not load the script directly after the page load. //We don't want to delay other onload functions somehow. setTimeout(function () { loadScript(initButtons); }, 500); } onloadPassed = true; }); }(jQuery)); ; /* file-end: js/jquery/jquery.vkloader.js ----------------------------------------------------------------------------------*/ LJ.define('LJ.Likes'); if (jQuery.VK) { jQuery.VK.init({ apiId: LJ.get('vk_api_id'), onlyWidgets: true }); } LJ.Likes.parse = (function ($) { 'use strict'; var selectors = { facebook: '.lj-like-item-facebook', google: '.lj-like-item-google', twitter: '.lj-like-item-twitter', tumblr: '.lj-like-item-tumblr', surfingbird: '.lj-like-item-surfinbird', repost: '.lj-like-item-repost' }; /** * Parse lj-like buttons * @param {Object} $node jQuery .lj-like node */ function parse($node) { /** * Notice: tumblr button works through entry sharing */ parseFacebook($node); parseGoogle($node); parseTwitter($node); parseSurfingbird($node); parseRepost($node); parseVK($node); } /** * Create iframe node with default params and ability to redefine them (iframe factory) * @param {Object} params Params to substitute for iframe {src, width, height...} * @return {Element} Created iframe node */ function createIframe(params) { var iframe = document.createElement('iframe'), param; // defaults iframe.frameBorder = 0; iframe.scrolling = 'no'; iframe.allowTransparency = 'true'; iframe.width = 110; iframe.height = 20; // reassign params if (params) { for (param in params) { if (params.hasOwnProperty(param)) { iframe[param] = params[param]; } } } return iframe; } /** * Parse facebook likes * Documentation: http://developers.facebook.com/docs/reference/javascript/FB.XFBML.parse/ * @param {jQuery} $node jQuery collection */ function parseFacebook($node) { var item = $node.find( selectors.facebook ); if (item.length === 0) { return; } try { window.FB.XFBML.parse( item.get(0) ); } catch (e) { console.warn(e.message); } } /** * Parse google +1 button * Documentation: https://developers.google.com/+/plugins/+1button/#jsapi * @param {jQuery} $node jQuery node with likes in which we will search for google +1 button for parsing */ function parseGoogle($node) { var $button = $node.find( selectors.google ).children().first(), // jquery node button = null; // raw DOM node if ($button.length === 0) { return; } button = $button.get(0); // gapi could throw errors try { window.gapi.plusone.render( button, { size: $button.attr('size'), href: $button.attr('href') } ); } catch (e) { console.warn(e.message); } } /** * Parse and replace twitter button * @param {jQuery} $node jQuery node with .lj-like class */ function parseTwitter($node) { var params = null, iframe = null, // link to replace with iframe link = null, item = $node.find( selectors.twitter ); if (item.length === 0) { return; } link = item.children().eq(0); params = { url: link.data('url'), text: link.data('text') || '', count: link.data('count'), lang: link.data('lang') || 'en', hashtags: link.data('hashtags') || '' }; iframe = createIframe({ src: LiveJournal.constructUrl('http://platform.twitter.com/widgets/tweet_button.html', params) }); link.replaceWith(iframe); } /** * Parse surfingbird share button * @param {jQuery} $node jQuery .lj-like node */ function parseSurfingbird($node) { var item = $node.find( selectors.surfingbird ), link = null, iframe = null, params = null; if (item.length === 0) { return; } link = item.find('.surfinbird__like_button'); params = { url: link.data('url'), caption: link.data('text'), layout: 'common' }; iframe = createIframe({ src: LiveJournal.constructUrl('http://surfingbird.ru/button', params) }); link.replaceWith(iframe); } /** * Parse repost button * @param {jQuery} $node jQuery .lj-like node */ function parseRepost($node) { var item = $node.find( selectors.repost ), link = null, url; if (item.length === 0) { return; } link = $node.find('.lj-like-item-repost').find('a'); url = link.data('url'); LJ.Api.call('repost.get_status', { url: url }, function (data) { link.replaceWith(LJ.Likes.renderRepostButton(url, data)); }); } function parseVK($node) { var vk = $node.find('.lj-like-item-vkontakte'), id = vk.attr('id'); if (typeof $.VK === 'object') { $.VK.addButton(id, vk.data('vk-options')); } } return parse; }(jQuery)); LJ.Likes.renderRepostButton = function (url, data) { data = data || {}; var meta = { paid: !!data.paid, url: url, cost: data.cost, budget: data.budget, count: Number(data.count || 0), reposted: !!data.reposted }, template = 'templates-CleanHtml-Repost', options = {}; if (meta.paid) { template = 'templates-CleanHtml-PaidRepost'; meta.owner = meta.cost === '0'; options.classNames = { active: 'paidrepost-button-active', inactive: 'paidrepost-button-inactive' }; } // see jquery.lj.repostbutton.js return LJ.UI.template(template, meta).repostbutton(jQuery.extend(options, meta)); }; /** * @author Valeriy Vasin (valeriy.vasin@sup.com) * @description Parse lj-likes plugin * It parses all elements with class 'lj-like', uncomment their content * and parse with LJ.Likes.parse() * @todo Move plugin to separate file */ ;(function ($) { 'use strict'; var /** * Empty collection that will contain not parsed lj-like elements * that are currently on the page */ _likes = $(); /** * Remove comments inside node and parse likes * @param {Object} node jQuery node * @return {Object} jQuery node */ function parse(node) { var html = node.html(), // regexp for removing _tmplitem attribute tmplRegexp = /_tmplitem=['"]\d+['"]/mig; // uncomment like buttons html = $.trim( html.replace(//mig, '$1') ); /** * Clean _tmplitem attributes * * It's a quirk for jquery templates possible bug with commented nodes * and double applying jquery templates. * _tmplitem attributes are not removed after compilation. * Fix for #LJSUP-14149 */ if ( tmplRegexp.test(html) ) { html = html.replace(tmplRegexp, ''); } LJ.Likes.parse( node.html(html) ); return node; } /** * handler for scroll event for lazy loading of likes */ function lazyLoad() { var screenableLikes = null; if ( _likes.length === 0 ) { return; } // find likes that are on the screen screenableLikes = _likes.filter(':screenable'); if ( !screenableLikes.length ) { return; } screenableLikes.each(function () { var node = $(this); // move parsing to the end of the event loop setTimeout(function () { parse( node ); }, 0); }); // remove handled likes from the queue _likes = _likes.not(screenableLikes); } // after document ready, cuz LiveJournal namespace is not defined yet $(function () { /** * Handle scroll event. * Notice: for mobile devices we don't threshold lazyLoad * because it fires only at the end of scrolling (iOS) */ $(window).on('scroll', LJ.Support.touch ? lazyLoad : LJ.Function.threshold(lazyLoad, 1000)); }); $.fn.ljLikes = function (opts) { var likes = null; if ( this.length === 0 ) { return this; } opts = $.extend({}, $.fn.ljLikes.defaults, opts || {}); // find elements with lj-likes class likes = this.find('.lj-like') .add( this.filter('.lj-like') ) // filter previously unused items only and mark them as used .filter(function () { if (this.used) { return false; } this.used = true; return true; }); if (likes.length === 0) { return this; } if ( !opts.lazy ) { // not lazy: immediately parsing likes.each(function () { var node = $(this); // parse should be deferred setTimeout(function () { parse( node ); }, 0); }); } else { // add likes for further lazy loading _likes = _likes.add( likes ); // parse all added screenable elements lazyLoad(); } return this; }; // default plugin options $.fn.ljLikes.defaults = { /** * Lazy loading of likes - will be parsed when becomes screenable * if false - we will parse likes at the moment */ lazy: true }; }(jQuery)); ;(function ($) { 'use strict'; LJ.Event.on('repost.requestRemove', function(node, url) { $(node).confirmbubble({ confirmText: LJ.ml('repost.confirm.delete'), confirm: function() { LJ.Api.call('repost.delete', { url: url }, function(answer) { if (answer.error) { LiveJournal.ajaxError(answer.error.message); } else { location.reload(); } }); } }); }); })(jQuery); ; /* file-end: js/entry/likes.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/pagescroller.js */ jQuery(function() { var entries = jQuery(".entry"); function getCurrentEntry() { var scrollTop = jQuery(window).scrollTop(); for (var i=0; i' + ml_message + '').bubble({ target: node }); jQuery(node).data('buyMoreCachedBubble', bubble); } bubble.bubble('show'); if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } return false; }, donate: function( link, url_data, event ) { var width = 639, height = 230, url = link.href, popupUrl, h; LJ.rpc.bind(function(ev) { if ( ev.origin && ev.origin !== Site.siteroot ) { return; } if ( ev.data && ev.data.message === 'updateWallet' ) { LiveJournal.run_hook( 'update_wallet_balance' ); jQuery.getJSON( LiveJournal.getAjaxUrl('give_tokens') + '?' + url_data + '&mode=js', function (result) { var $node; if ( result.html ) { $node = jQuery( link ).closest( '.lj-button' ); $node.replaceWith( result.html ); } } ); } }); popupUrl = url + ( url.indexOf( '?' ) === -1 ? '?' : '&' ) + 'usescheme=nonavigation'; h = window.open( 'about:blank', 'donate' , 'toolbar=0,status=0,width=' + width + ',height=' + height + ',scrollbars=yes,resizable=yes'); h.name = location.href.replace( /#.*$/, '' ); setTimeout(function() { LJ.rpc.initRecipient( h, popupUrl, location.href.replace( /#.*$/, '' ) ); }, 0); if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; } return false; } }; (function () { var storage = { init: function() { this._store = LJ.Storage.getItem('placeholders') || {}; }, inStorage: function(link) { return this._store.hasOwnProperty(link); }, addUrl: function(link) { if ( !this.inStorage(link) ) { this._store[link] = true; LJ.Storage.setItem('placeholders', this._store); } } }; storage.init(); var placeholders = { image: { selector: '.b-mediaplaceholder-photo', loading: 'b-mediaplaceholder-processing', init: function() { var self = this; doc.on('click', this.selector, function(ev) { self.handler(this, ev); }); }, handler: function(el, html) { var im = new Image(); im.onload = im.onerror = jQuery.delayedCallback(this.imgLoaded.bind(this, el, im), 500); im.src = el.href; el.className += ' ' + this.loading; storage.addUrl(el.href); }, imgLoaded: function(el, image) { var img = jQuery('').attr('src', image.src), $el = jQuery(el), href = $el.data('href'), imw = $el.data('width'), imh = $el.data('height'); if (imw) { img.width(imw); } if (imh) { img.height(imh); } if (href && href.length > 0) { img = jQuery('', { href: href }).append(img); $el.next('.b-mediaplaceholder-external').remove(); } $el.replaceWith(img); } }, video: { handler: function(link, html) { link.parentNode.replaceChild(jQuery(unescape(html))[0], link); } } }; // use replaceChild for no blink scroll effect // Placeholder onclick event LiveJournal.placeholderClick = function(el, html) { var type = (html === 'image') ? html : 'video'; placeholders[type].handler(el, html); return false; }; LiveJournal.register_hook('page_load', function() { jQuery('.b-mediaplaceholder').each(function() { if (storage.inStorage(this.href)) { this.onclick.apply(this); } }); }); })(); /** * Embed gists from GitHub * * Parses the page for: * '' */ (function($) { 'use strict'; var gistBase = '://gist.github.com/', gistCss = { 'clear': 'both' }; function showGist(link) { var href = link.attr('href'), head = $('head'), match = href && href.match(/gist.github.com(.*)\/([a-zA-Z0-9]+)/), id = match && match.pop(); if (!id) { console.error('Bad GitHub id'); return; } link .html('Loading the gist...'); $.ajax({ url: 'https' + gistBase + id + '.json', dataType: 'jsonp', timeout: 10000 }).done(function(result) { if (!result.div || !result.stylesheet) { console.error('Data error', result); } head.append( '' ); var div = $(result.div); div.find('a').attr('target', '_blank'); div.css(gistCss); link.replaceWith(div); }) .fail(function(error) { link.html('Gist loading error'); }); } function convertGists(node, isLjCut) { // Convert all gist links in node node = node || $('body'); var gists = $('a[href*="' + gistBase + '"]', node); gists.each(function(_, element) { var link = $(element), isFeed, expandLink, needAutoExpand; link.attr('target', '_blank'); // Insert original content from github if 'data-expand' is defined if ( link.attr('data-expand') ) { isFeed = /feed|friends/.test(window.location.pathname); needAutoExpand = isFeed ? isLjCut : (link.attr('data-expand') === 'true'); // Add either gist or collapsed gist if (needAutoExpand) { // Add full gist content showGist(link); } else { // Add collapsed gist // Wrap link in span to display braces around it var span = document.createElement('span'); link.after(span); $(span).append(link) .toggleClass('b-replaceable-link', true); link.on('click', function(e) { if (event.ctrlKey || (event.metaKey && LJ.Support.isMac)) { return; } e.preventDefault(); $(span).after(link) .remove(); showGist(link); }); } } }); } $(function() { var body = $('body'); convertGists( body ); body.on('ljcutshow', function(event, ui) { convertGists($(event.target).next(), true ); }); }); }(jQuery)); ; /* file-end: js/journal.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/livejournal-local.js */ $ = DOM.getElement; (function($) { // do not init on m.livejournal.com if (LJ.get('is_mobile_version')) { return; } $(function() { LiveJournal.initPage(); // popup window in page header // to login using external provider var popupShow = $('.i-loginpopup-show'); if (popupShow.length) { $('.b-loginpopup').bubble({ target: popupShow, closeControl: false, showOn: 'click' }); } }); })(jQuery); ; /* file-end: js/livejournal-local.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/contextualhover.js */ /* --------------------------------------------------------------------------------- file-start: js/relations/relations.js */ /** * @author Valeriy Vasin (valeriy.vasin@sup.com) * @description Manage user relations */ ;(function () { 'use strict'; var actions = [ 'addFriend', 'removeFriend', 'subscribe', 'unsubscribe', 'join', 'leave', 'setBan', 'setUnban', 'banEverywhere', 'unbanEverywhere' ]; /** * Change relations between users / communities * * @param {Object} eventData Relations change object * @param {String} eventData.username Username of user change relations for * @param {String} eventData.action Action to perform (restricted to actions listed in array above) * @param {Function} [eventData.callback] Callback function to call after */ function changeRelation(eventData) { var username, action; if (typeof eventData !== 'object' || eventData === null) { throw new TypeError('Data should be an object.'); } username = eventData.username; action = eventData.action; if ( actions.indexOf(action) === -1 ) { console.error('Action ' + action + ' is not allowed.'); return; } LJ.Api.call( 'relations.' + action.toLowerCase(), { target: username }, function (data) { LJ.Event.trigger('relations.changed', { action: action, username: username, data: data }); if (typeof eventData.callback === 'function') { eventData.callback(data); } } ); } // bind listeners for relation actions if ( LJ.Flags.isEnabled('friendsAndSubscriptions') ) { LJ.Event.on('relations.change', changeRelation); } }()); ; /* file-end: js/relations/relations.js ----------------------------------------------------------------------------------*/ LJ.injectStyle('/* Contextual hover \n------------------------------------------------------------*/\n.b-popup-contextual .i-popup-arrtl,\n.b-popup-contextual .i-popup-arrbl {\n left: 11px;\n }\n.b-popup-contextual .i-popup-arrtr,\n.b-popup-contextual .i-popup-arrbr {\n right: 11px;\n }\n.b-contextualhover {\n width: 250px;\n min-height: 50px;\n margin-left: -3px;\n text-align: left;\n font-family: \'Arial\', sans-serif;\n }\n.b-contextualhover:before,\n.b-contextualhover:after {\n content: \"\";\n display: table;\n }\n.b-contextualhover:after {\n clear: both;\n }\n .b-contextualhover,\n .b-contextualhover DIV,\n .b-contextualhover P,\n .b-contextualhover UL,\n .b-contextualhover OL,\n .b-contextualhover LI,\n .b-contextualhover LABEL,\n .b-contextualhover IMG,\n .b-contextualhover SPAN,\n .b-contextualhover H3,\n .b-contextualhover INPUT {\n padding: 0;\n margin: 0;\n color: #000;\n }\n .b-contextualhover IMG {\n border: none;\n }\n .b-contextualhover A:link,\n .b-contextualhover A:visited {\n background: #FFF;\n border-bottom: 0 !important;\n text-decoration: none !important;\n color: #00C !important;\n }\n .b-contextualhover A:hover,\n .b-contextualhover A:active,\n .b-contextualhover A:focus {\n border-bottom: 0 !important;\n text-decoration: underline !important;\n color: #00C !important;\n }\n .s-lanzelot .b-contextualhover A:link,\n .s-lanzelot .b-contextualhover A:visited {\n border-bottom: 0 !important;\n text-decoration: none !important;\n color: #3F5F9E !important;\n }\n .s-lanzelot .b-contextualhover A:hover,\n .s-lanzelot .b-contextualhover A:active,\n .s-lanzelot .b-contextualhover A:focus {\n border-bottom: 0 !important;\n text-decoration: underline !important;\n color: #3F5F9E !important;\n }\n .index-page .b-contextualhover A:link,\n .index-page .b-contextualhover A:visited,\n .index-page .b-contextualhover A:hover,\n .index-page .b-contextualhover A:active,\n .index-page .b-contextualhover A:focus {\n color: #3F5F9E !important;\n }\n .b-contextualhover .alias-unavailable A:link,\n .b-contextualhover .alias-unavailable A:visited {\n color: #999 !important;\n }\n .b-contextualhover .alias-unavailable A:hover,\n .b-contextualhover .alias-unavailable A:active,\n .b-contextualhover .alias-unavailable A:focus {\n color: #999 !important;\n }\n .b-contextualhover P {\n margin-bottom: 3px;\n line-height: 16px;\n font-size: 12px;\n }\n .b-contextualhover .input-checkbox {\n margin-right: 2px;\n vertical-align: middle;\n }\n .b-contextualhover .b-contextualhover-section {\n overflow: hidden;\n padding: 0 15px 0 3px;\n }\n .b-contextualhover .b-contextualhover-side {\n float: right;\n width: 60px;\n }\n .b-contextualhover .b-contextualhover-userpic {\n float: right;\n width: 60px;\n height: 60px;\n text-align: right;\n }\n .b-contextualhover .b-contextualhover-userpic A,\n .b-contextualhover .b-contextualhover-userpic A:hover {\n border: none !important;\n }\n .b-contextualhover .b-contextualhover-userpic IMG {\n max-width: 60px;\n max-height: 60px;\n border: none;\n }\n .b-contextualhover .b-contextualhover-title {\n padding-bottom: 5px;\n }\n .b-contextualhover .b-contextualhover-title H3 {\n margin-bottom: 3px;\n font-weight: normal;\n font-style: normal;\n line-height: 16px;\n font-size: 12px;\n }\n .b-contextualhover .b-contextualhover-options {\n margin: 0;\n padding: 5px 0 2px 0;\n border-top: 1px dotted #D3D3D3;\n list-style: none;\n }\n .b-contextualhover .b-contextualhover-options LI {\n margin-bottom: 3px;\n line-height: 16px;\n font-size: 12px;\n }\n .b-contextualhover .b-contextualhover-options LI A:hover {\n text-decoration: underline !important;\n }\n .b-contextualhover .b-contextualhover-param {\n line-height: 18px;\n margin:0 0 6px;\n }\n .b-contextualhover .b-contextualhover-param-item {\n list-style: none;\n }\n .b-contextualhover-param-item .b-icon-scapital {\n margin:0 2px 0 0;\n }\n\n\n'); LJ.UI.registerTemplate('templates-Widgets-contextualhover', "{{if userpic }}
\"\"
{{/if}}

{{html title.title}}

{{each headLinks}}

{{if $value.url}}${$value.text} {{else}}{{html $value}}{{/if}}

{{/each}}
{{if socialCap.value}}
  • {{if socialCap.first}} {{else}} {{/if}} ${socialCap.value}
{{/if}} {{if !partner}} {{each(i, group) linkGroups}} {{if group.length }}
    {{each group}}
  • {{if $value.url}}${$value.text} {{else}}{{html $value}}{{/if}}
  • {{/each}}
{{/if}} {{/each}} {{if showBanOptions }}
    {{if reportBot}}
  • ${reportBot.text}
  • {{/if}}
  • ${banUsersLink.text}:

    {{if banCheckboxes}}
    {{each banCheckboxes}}

    {{/each}}
    {{/if}}
{{/if}} {{/if}}
", 'JQuery.stat'); /*global ContextualPopup, Hourglass */ /** * Contextual popup is displayed on mouse hover near * every userpic and userhead */ /** * Widget shows the dialog to edit current user note. */ /* * Load ljwidget_ippu.js asynchronously and * create window.LJWidgetIPPU_AddAlias. This is * useful to move all IPPU stuff out of core * and load it on demand. * * @param {function} callback */ var loadIPPU = (function() { var files = ['ljwidget_ippu.js'], // all dependencies are listed via require loaded = false; return function(callback) { if (loaded) { return callback.call(this); } LJ.injectScript(LJ.get('statprefix') + '/js/??' + files.join(',')).then(function() { createAlias(); loaded = true; callback.call(this); }); }; function createAlias() { window.LJWidgetIPPU_AddAlias = new Class(LJWidgetIPPU, { init: function (opts, params) { opts.widgetClass = "IPPU::AddAlias"; this.width = opts.width; // Use for resizing later this.height = opts.height; // Use for resizing later this.alias = opts.alias; LJWidgetIPPU_AddAlias.superClass.init.apply(this, arguments); }, changeAlias: function (evt, form) { this.doPost({ alias: form['Widget[IPPU_AddAlias]_alias'].value + '', foruser: form['Widget[IPPU_AddAlias]_foruser'].value + '' }); evt.preventDefault(); }, onData: function (data) { if (!data.res || !data.res.success) { return; } this.close(); //Changing button. Only on profile page var edit_node = jQuery('.profile_addalias'); if (edit_node.length) { if (data.res.alias) { edit_node[0].style.display = 'none'; edit_node[1].style.display = 'block'; edit_node[1].firstChild.alias = data.res.alias; } else { edit_node[0].style.display = 'block'; edit_node[1].style.display = 'none'; } } var username = data.res.username, alias = data.res.alias; if (ContextualPopup.cachedResults[username]) { ContextualPopup.cachedResults[username].alias_title = alias ? 'Edit Note' : 'Add Note'; ContextualPopup.cachedResults[username].alias = alias; } if (ContextualPopup.currentId === username) { ContextualPopup.renderPopup(ContextualPopup.currentId); } }, onError: function (msg) { LJ_IPPU.showErrorNote('Error: ' + msg); }, onRefresh: function () { var form = jQuery('#addalias_form').get(0), input = jQuery(form['Widget[IPPU_AddAlias]_alias']), delete_btn = jQuery(form['Widget[IPPU_AddAlias]_aliasdelete']), widget = this; input.focus(); if (delete_btn.length) { delete_btn.click(function(){ input.val(''); }); input.input(function() { // save button disabled form['Widget[IPPU_AddAlias]_aliaschange'].disabled = !this.value; }); } jQuery(form).submit(function(e) { widget.changeAlias(e, form); }); }, cancel: function () { this.close(); } }); } })(); //this object contains only authToken Aliases = {}; function addAlias(target, ptitle, ljusername, oldalias, callback) { var widget; if ( !ptitle ) { return true; } widget = new LJWidgetIPPU_AddAlias({ title: ptitle, width: 440, height: 180, authToken: Aliases.authToken, callback: callback }, { alias: target.alias||oldalias, foruser: ljusername }); return false; } (function($) { 'use strict'; var rex_userpic = /(userpic\..+\/\d+\/\d+)|(\/userpic\/\d+\/\d+)/; /** * Object contains methods to build and display user popup. */ var popup = { popupDelay: 500, popupTimer: null, adriverImages : { anonymous: 'http://ad.adriver.ru/cgi-bin/rle.cgi?sid=1&ad=186396&bt=21&pid=482107&bid=893162&bn=893162&rnd={random}', guest: 'http://ad.adriver.ru/cgi-bin/rle.cgi?sid=1&ad=186396&bt=21&pid=482107&bid=893165&bn=893165&rnd={random}', self: 'http://ad.adriver.ru/cgi-bin/rle.cgi?sid=1&ad=186396&bt=21&pid=482107&bid=893167&bn=893167&rnd={random}' }, classNames: { popup: 'b-popup-contextual' }, selectors: { wrapper: '.b-contextualhover', bubble: '.b-popup', popup: '.contextualPopup' }, templates: { wrapper: '
', content: 'templates-Widgets-contextualhover', loading: 'Loading...' }, init: function() { var wrapper = jQuery(this.templates.wrapper), self = this; this._visible = false; this.element = jQuery(wrapper).bubble({ alwaysShowUnderTarget: true, closeControl: false, show: function() { ContextualPopup._visible = true; }, hide: function() { ContextualPopup.hideHourglass(); ContextualPopup._visible = false; }, classNames: { containerAddClass: this.classNames.popup } }); this.bindShowHideEvents(this.element.closest(this.selectors.bubble)); }, bindShowHideEvents: function(el) { var self = this; el = jQuery(el); el.bind('mouseenter', function(ev) { self.show(); }); el.bind('mouseleave', function(ev) { self.hide(); }); }, show: function(force) { this.setVisibile(true, force); }, hide: function(force) { this.setVisibile(false, force); }, setVisibile: function(isVisible, force) { var action = isVisible ? 'show' : 'hide', self = this; force = force || false; clearTimeout(this.popupTimer); if (force) { this.element.bubble(action); } else { this.popupTimer = setTimeout(function() { self.element.bubble(action); }, this.popupDelay); } }, /** * Constructs object, passes it to the template, * inserts it in the bubble and binds events. * * @param {Object} data Object returned from the endpoint. * @param {String} ctxPopupId The id of the user. */ render: function(data, ctxPopupId) { if (!data) { this.element.empty().append(this.templates.loading); return; } else if (!data.username || !data.success || data.noshow) { this.hide(true); return; } var buildObject = { headLinks: [], linkGroups: [] }; if (data.url_userpic && data.url_userpic !== ctxPopupId) { buildObject.userpic = { allpics: data.url_allpics, pic: data.url_userpic }; } buildObject.title = { title: data.ctxpopup_status }; // aliases if (!data.is_requester && data.is_logged_in) { if (data.alias_enable) { if (data.alias) { buildObject.headLinks.push('' + data.alias.encodeHTML() + ''); } buildObject.headLinks.push({ url: Site.siteroot + '/manage/notes.bml', click: function(e) { var that = this; e.preventDefault(); LJ.Track.event('Site', 'ContextualHover', 'Edit note'); loadIPPU(function() { addAlias(that, data.alias_title, data.username, data.alias || ''); }); }, text: data.alias_title }); } else { buildObject.headLinks.push( ''+ ''+ ''+ ' '+ ''+data.alias_title+''+ ''); } } if (data.is_logged_in && !data.is_requester) { // add/remove friend link (function () { if ( LJ.Flags.isEnabled('friendsAndSubscriptions') ) { // do not show 'add friend / watch community' links. if (!data.is_person && !data.is_identity) { return; } // if invite has been sent - links for add/remove friend should not be on the page if (data.is_invite_sent) { buildObject.headLinks.push(data.ml_invite_sent); return; } } buildObject.headLinks.push({ selector: 'a[href="{url}"]:first', url: data.url_addfriend, click: function (e) { e.preventDefault(); e.stopPropagation(); ContextualPopup.changeRelation(data, ctxPopupId, data.is_friend ? 'removeFriend' : 'addFriend', e); }, text: (function() { if (data.is_comm) { return data.is_friend ? data.ml_stop_community : data.ml_watch_community; } else if (data.is_syndicated) { return data.is_friend ? data.ml_unsubscribe_feed : data.ml_subscribe_feed; } else { return data.is_friend ? data.ml_remove_friend : data.ml_add_friend; } }()) }); }()); // subscribe/unsubscribe if ( LJ.Flags.isEnabled('friendsAndSubscriptions') && !data.is_identity ) { buildObject.headLinks.push({ selector: 'a[href=#subscription]', url: '#subscription', click: function (e) { ContextualPopup.changeRelation( data, ctxPopupId, data.is_subscribedon ? 'unsubscribe' : 'subscribe', e ); e.preventDefault(); e.stopPropagation(); }, text: data.is_subscribedon ? data.ml_unsubscribe : data.ml_subscribe }); } // manage friend if (data.is_friend && !data.is_identity) { buildObject.headLinks.push({ url: data.url_addfriend, text: data.ml_edit_friend_tags }); } } var linkGroup = []; // community member if (data.is_logged_in && data.is_comm) { // invite has been sent to community maintainer if (data.is_invite_sent) { linkGroup.push(data.ml_invite_sent); } else { linkGroup.push({ selector: 'a[href="{url}"]', url: data.is_member ? data.url_leavecomm : data.url_joincomm, text: data.is_member ? data.ml_leave : data.ml_join_community, click: function(e) { e.preventDefault(); ContextualPopup.changeRelation(data, ctxPopupId, data.is_member ? 'leave' : 'join', e); } }); } } //filter community if( ( !data.is_comm && Site.current_journal && ( 'is_comm' in Site.current_journal ) && Site.current_journal.is_comm === '1' ) || data.posted_in ) { linkGroup.push({ url: ( ( data.posted_in ) ? data.posted_in : Site.current_journal.url_journal ) + '/?poster=' + data.username, text: ( Site.remoteUser === data.username && !data.posted_in ) ? ( data.ml_filter_by_poster_me || 'Filter community by me' ) : ( data.ml_filter_by_poster || 'Filter community by poster' ) }); } buildObject.linkGroups.push(linkGroup); linkGroup = []; // send message if (data.is_logged_in && data.is_person && ! data.is_requester && data.url_message) { linkGroup.push({ url: data.url_message, text: data.ml_send_message }); } // vgift if ((data.is_person || data.is_comm) && !data.is_requester && data.can_receive_vgifts) { linkGroup.push({ url: Site.siteroot + '/shop/vgift.bml?to=' + data.username, text: data.ml_send_gift }); } // wishlist // commented according to task LJSUP-11396 //if ((data.is_person || data.is_comm) && !data.is_requester && data.wishlist_url) { // linkGroup.push({ // url: data.wishlist_url, // text: data.ml_view_wishlist // }); //} // buy the same userhead if (data.is_logged_in && data.is_person && ! data.is_requester && data.is_custom_userhead) { linkGroup.push((data.is_app_userhead) ? { url: data.url_userhead_install, text: data.ml_userhead_install } : { url: data.url_buy_userhead, text: data.ml_buy_same_userhead } ); } // identity if (data.is_identity && data.is_requester) { linkGroup.push({ url: Site.siteroot + '/identity/convert.bml', text: data.ml_upgrade_account }); } // add site-specific content here var extraContent = this.extraInfo(data); if (extraContent) { linkGroup.push(extraContent); } buildObject.linkGroups.push(linkGroup); if (data.is_logged_in && !data.is_requester && !data.is_comm && !data.is_syndicated) { buildObject.showBanOptions = true; buildObject.banUsersLink = { url: Site.siteroot + '/manage/banusers.bml', text: data.ml_ban }; // ban/unban buildObject.banCheckboxes = []; buildObject.banCheckboxes.push({ selector: '.ban_user', className: 'ban_user', label: data.ml_ban_in_my, checked: data.is_banned, change: function(e) { e.preventDefault(); ContextualPopup.changeRelation(data, ctxPopupId, data.is_banned ? 'setUnban' : 'setBan', e); } }); // report a bot if (!Site.remote_is_suspended) { buildObject.reportBot = { url: Site.siteroot + '/abuse/bots.bml?user=' + data.username, text: data.ml_report }; } // ban user from all maintained communities if (!data.is_requester && !data.is_comm && !data.is_syndicated && data.have_communities) { buildObject.banCheckboxes.push({ selector: '.ban_everywhere', className: 'ban_everywhere', label: data.ban_everywhere_title, checked: data.is_banned_everywhere, change: function(e) { e.preventDefault(); var action = data.is_banned_everywhere ? 'unbanEverywhere' : 'banEverywhere'; ContextualPopup.changeRelation(data, ctxPopupId, action, e); } }); } } var userType = 'guest'; if (!data.is_logged_in) { // anonymous userType = 'anonymous'; } else if (data.is_requester) { // self userType = 'self'; } new Image().src = this.adriverImages[userType].supplant({ random: Math.random()}); buildObject.socialCap = { first: !!data.first }; buildObject.partner = !!data.partner; if (data.value) { buildObject.socialCap.value = data.value; } this.element .empty() .append(LJ.UI.template(this.templates.content, buildObject)); if (this.element.is(':visible')) { //show method forces bubble to reposition with respect to the new content this.element.bubble('updatePosition'); } this.setPopupEvents(buildObject); }, extraInfo: function(userdata) { var content = ''; if (userdata.is_person) { if (userdata.is_online !== null) { content = '' + userdata.ml_ljtalk + ''; if (userdata.is_online) { content += " " + userdata.ml_online; } else if (userdata.is_online == '0') { content += " " + userdata.ml_offline; } } } return content; }, /** * Go through all build objects and find all callbacks that should be bound * to the node events. * * @param {Object} buildObject Template object. */ setPopupEvents: function(buildObject) { var element = this.element; element.undelegate(); function walkObject(obj) { $.each(obj, function(key, value) { var selector; if (value.click) { //default handler is by url selector = value.selector || '[href="' + value.url + '"]'; selector = selector.supplant(value); element.delegate(selector, 'click', value.click); } if (value.change) { //for checkboxes selector should present anyway selector = value.selector; selector = selector.supplant(value); element.delegate(selector, 'change', value.change); } //maybe this object has children with events to be set if (typeof value === 'object') { walkObject(value); } }); } walkObject(buildObject); } }; window.ContextualPopup = { cachedResults : {}, currentRequests: {}, currentId : null, currentElement : null, hourglass : null, /* * Init live handler for contextual popups */ setupLive: function() { popup.init(); $(document.body) // remove standart listeners from setup .off('mouseover', ContextualPopup.mouseover) .off('click', ContextualPopup.touchStart) // use live listener .on('mouseover ' + (LJ.Support.touch ? 'click' : ''), '.ljuser, img', function(event) { // handle with link to userpic if (this.tagName.toLowerCase() === 'img' && !$(this).attr('src').match(rex_userpic)) { return; } ContextualPopup.activate(event, true); }); }, setup: function() { /* this method is no longed needed, because of ContextualPopup.setupLive */ return this; }, /** * Search child nodes and bind hover events on them if needed. */ searchAndAdd: function(node) { if (!Site.ctx_popup) { return; } // attach to all ljuser head icons var rex_userid = /\?userid=(\d+)/, class_nopopup = 'noctxpopup', ljusers = jQuery('span.ljuser:not(.' + class_nopopup + ')>a>img', node), i = -1, userid, ljuser, parent; // use while for speed while (ljusers[++i]) { ljuser = ljusers[i]; parent = ljuser.parentNode; userid = parent.href.match(rex_userid); if (parent.href && userid) { ljuser.userid = userid[1]; } else if (parent.parentNode.getAttribute('lj:user')) { ljuser.username = parent.parentNode.getAttribute('lj:user'); } else { continue; } ljuser.posted_in = parent.parentNode.getAttribute('data-journal'); ljuser.className += ' ContextualPopup'; } ljusers = node.getElementsByTagName('img'); i = -1; while (ljusers[++i]) { ljuser = ljusers[i]; if (ljuser.src.match(rex_userpic) && ljuser.className.indexOf(class_nopopup) < 0) { ljuser.up_url = ljuser.src; if (ljuser.parentNode.getAttribute('data-journal')) { ljuser.posted_in = ljuser.parentNode.getAttribute('data-journal'); } ljuser.className += ' ContextualPopup'; } } }, activate: function(e, useLive) { if (useLive && !(e.target.username || e.target.userid || e.target.up_url)) { ContextualPopup.searchAndAdd($(e.currentTarget).parent().get(0)); } var target = e.target, ctxPopupId = target.username || target.userid || target.up_url, t = ContextualPopup; if (target.tagName === 'IMG' && ctxPopupId) { // if we don't have cached data background request it if (!t.cachedResults[ctxPopupId]) { t.getInfo(target, ctxPopupId); } // doesn't display alt as tooltip if (jQuery.browser.msie && target.title !== undefined) { target.title = ''; } // show other popup if (t.currentElement !== target) { t.showPopup(ctxPopupId, target); } else { popup.show(); } return true; } return false; }, mouseOver: function(e) { ContextualPopup.activate(e); }, touchStart: function(e) { var current = ContextualPopup.currentElement; //if popup is activated then currentElement property is rewriten somewhere inside the activate //function and this condition works; if (ContextualPopup.activate(e) && (!ContextualPopup._visible || current !== ContextualPopup.currentElement)) { e.preventDefault(); e.stopPropagation(); } }, showPopup: function(ctxPopupId, ele) { var showNow = popup.element.is(':visible'); jQuery(this.currentElement) .unbind('mouseenter mouseleave'); this.currentId = ctxPopupId; var data = this.cachedResults[ctxPopupId]; if (data && data.noshow) { return; } if (this.currentElement && this.currentElement !== ele) { popup.hide(true); } if (data && data.error) { popup.hide(true); ContextualPopup.showNote(data.error, ele); return; } popup.render(data, ctxPopupId); popup.element.bubble('option', 'target', jQuery(ele)); popup.bindShowHideEvents(ele); popup.show(showNow); this.currentElement = ele; }, /** * Hide currently opened popup */ hide: function () { popup.hide(true); return this; }, renderPopup: function(ctxPopupId) { popup.render(this.cachedResults[ctxPopupId], ctxPopupId); }, // ajax request to change relation changeRelation: function (info, ctxPopupId, action, e) { function changedRelation(data) { if (data.error) { return ContextualPopup.showNote(data.error.message); } if (ContextualPopup.cachedResults[ctxPopupId]) { jQuery.extend(ContextualPopup.cachedResults[ctxPopupId], data); } // if the popup is up, reload it ContextualPopup.renderPopup(ctxPopupId); } LJ.Api.call( 'relations.' + action.toLowerCase(), { target: info.username }, function (data) { ContextualPopup.hourglass.hide(); ContextualPopup.hourglass = null; changedRelation(data); } ); ContextualPopup.hideHourglass(); ContextualPopup.hourglass = jQuery(e).hourglass()[0]; //entering mouse on the hourglass should no close popup jQuery(ContextualPopup.hourglass.ele).bind('mouseenter', function () { popup.element.trigger('mouseenter'); }); // so mousing over hourglass doesn't make ctxpopup think mouse is outside ContextualPopup.hourglass.element.addClass('lj_hourglass'); return false; }, // create a little popup to notify the user of something showNote: function (note, ele) { ele = ele || popup.element[0]; loadIPPU(function() { LJ_IPPU.showNote(note, ele); }); }, cleanCache: function(keys) { var self = this; keys = keys || []; if (typeof keys === 'string') { keys = [ keys ]; } keys.forEach(function(key) { if (self.cachedResults[key]) { delete self.cachedResults[key]; } }); }, // do ajax request of user info getInfo: function(target, popup_id) { var t = this; if (t.currentRequests[popup_id]) { return; } t.currentRequests[popup_id] = 1; var reqParams = { user: target.username || '' }; jQuery.ajax({ url: LiveJournal.getAjaxUrl('ctxpopup'), data: Object.extend( reqParams, { userid: target.userid || 0, userpic_url: target.up_url || '', mode: 'getinfo' }), dataType: 'json', success: function(data) { if (data.error) { data.username = reqParams.user; t.cachedResults[data.username] = data; popup.hide(true); t.showNote(data.error, target); return; } if( target.posted_in ) { data.posted_in = target.posted_in; } t.cachedResults[String(data.userid)] = t.cachedResults[data.username] = t.cachedResults[data.url_userpic] = data; // non default userpic if (target.up_url) { t.cachedResults[target.up_url] = data; } t.currentRequests[popup_id] = null; if (t.currentId === popup_id) { t.renderPopup(popup_id); } }, error: function() { t.currentRequests[popup_id] = null; } }); }, hideHourglass: function () { if (this.hourglass) { this.hourglass.hide(); this.hourglass = null; } } }; // Update changing relations functionality to work through relations manager // that is declared in `js/relations/relations.js` if ( LJ.Flags.isEnabled('friendsAndSubscriptions') ) { // redeclare `changeRelation` method to interact with relations manager ContextualPopup.changeRelation = function (info, ctxPopupId, action, e) { LJ.Event.trigger('relations.change', { action: action, username: info.username }); // hide existed hourglass and add another one ContextualPopup.hideHourglass(); ContextualPopup.hourglass = new Hourglass() .setEvent(e) .show(); ContextualPopup.hourglass.element // entering mouse on the hourglass should not close popup .on('mouseenter', function () { popup.element.trigger('mouseenter'); }) // so mousing over hourglass doesn't make ctxpopup think mouse is outside .addClass('lj_hourglass'); return false; }; // subscribe to change relation events (function () { LJ.Event.on('relations.changed', function (eventData) { var data = eventData.data, username = eventData.username; ContextualPopup.hideHourglass(); if (data.error) { ContextualPopup.showNote(data.error.message); return; } if ( ContextualPopup.cachedResults[username] ) { $.extend(ContextualPopup.cachedResults[username], data); } // if the popup is up, reload it ContextualPopup.renderPopup(username); }); }()); } }(jQuery)); ; /* file-end: js/contextualhover.js ----------------------------------------------------------------------------------*/