/* --------------------------------------------------------------------------------- file-start: js/core/main.js */ /* --------------------------------------------------------------------------------- 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/lj.js */ ;(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.promise(); }; /* * 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); }; }()); ; /* file-end: js/core/lj.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; }; /** * Invert the keys and values of an object. The values must be serializable. * @param {Object} obj Source object * @return {Object} Result object */ LJ.Object.invert = function (obj) { return Object.keys(obj).reduce(function (result, key) { result[ obj[key] ] = key; return result; }, {}); }; /** * 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'); */ LJ.Object.resolve = get; 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/object.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; }; }; /** * Functional style negotion * @param {Function} func Function, result of which invocation will be inverted * @param {*} context Context of `func` invocation * @return {Boolean} Result * * @example * // found items that are non in widgets list * list.filter( LJ.Function.not(that.isWidgetInList, that) ); */ LJ.Function.not = function (func, context) { return function () { return !func.apply(context, arguments); }; }; /** * 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; }; /** * Creates a function that is restricted to execute `func` once. Repeat calls * to the function return the value of the first call. The `func` is executed * with the `this` binding of the created function. * * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var initialize = LJ.Function.once(createApplication); * initialize(); * initialize(); * // `initialize` executes `createApplication` once */ LJ.Function.once = function (func) { var ran, result; if (typeof func !== 'function') { throw new TypeError('Expected a function'); } return function() { if (ran) { return result; } ran = true; result = func.apply(this, arguments); // clear the `func` variable so the function may be garbage collected func = null; return result; }; }; })(); ; /* file-end: js/core/function.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/console.js */ /** * IE console object dummy functions */ (function (window) { 'use strict'; /** * See https://developer.chrome.com/devtools/docs/console-api */ var methods = [ 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'profile', 'profileEnd', 'time', 'timeEnd', 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' ]; function noop() {} if ( !window.console ) { window.console = {}; } methods.forEach(function (method) { if ( !console[method] ) { console[method] = noop; } }); }(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; }; })(); }()); ; /* 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 * * Notice: server side file to export flags - cgi-bin/LJ/Hooks/General.pm * * @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 = {}; $.extend(LJ.Flags, LJ.get('flags') || {}); // 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; }; /** * 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]; }; }(jQuery)); ; /* 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/'; if (!location.origin) { location.origin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : ''); } window.onerror = function(msg, url, line) { if (location.origin !== LJ.get('siteroot')) { return; } var errorObject = { 'msg' : msg, 'url' : url, 'line' : line, 'where' : String(window.location) }; if (!msg) { return; } if ( LJ.get('remote') ) { errorObject.user = LJ.get('remote.username'); } 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) { if ( errorObject.hasOwnProperty(key) ) { data.push(key + '=' + encodeURIComponent(errorObject[key])); } } src = logDomain + 'log?' + data.join('&'); beacon = new Image(); beacon.src = src; // track errors to GA LJ.Track.event('Error', LJ.Cookie.get('ljstaging') || 'prod', errorObject.msg); return false; }; })(); ; /* 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 */ !function(a){"use strict";function b(a,b,c){if("string"!=typeof a||"function"!=typeof b)throw new Error("Provide correct hook name or handler.");f.hasOwnProperty(a)||(f[a]=[]),f[a].push({fn:b,context:c})}function c(a,c,d){var f=function(){return e(a,f),c.apply(this,arguments)};b(a,f,d)}function d(b){var c=f[b],d=null,e=null;if(Array.isArray(c)&&0!==c.length)return d=Array.prototype.slice.call(arguments,1),c.forEach(function(b){var c=b.context;e=b.fn.apply("undefined"==typeof c?a:c,d)}),e}function e(a,b){if("string"!=typeof a)throw new Error("Hook name should be provided.");f.hasOwnProperty(a)&&(f[a]="function"==typeof b?f[a].filter(function(a){return a.fn!==b}):[])}LJ.define("LJ.Event"),LJ.Event.on=b,LJ.Event.once=c,LJ.Event.trigger=d,LJ.Event.off=e;var f={}}(this);; /* file-end: js/core/event.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/cookie.js */ ;(function ($) { 'use strict'; LJ.define('LJ.Cookie'); /* Cookie plugin. Copyright (c) 2006 Klaus Hartl (stilbuero.de) */ function cookie(name, value, options) { // name and value given, set/delete cookie if (value !== undefined) { 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 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.slice(0, name.length + 1) === (name + '=')) { return decodeURIComponent(_cookie.slice(name.length + 1)); } } } return null; } } // export for old compatibility window.Cookie = cookie; LJ.Cookie = { set: function (name, value, options) { return cookie(name, value, options); }, get: function (name) { return cookie(name); }, /** * Method that helps to set cookies for the whole domain * It sets default domain and path */ setGlobal: function (name, value, options) { options = $.extend({ domain: LJ.get('siteroot').replace(/^https?:\/\/www\./, ''), path: '/' }, options || {}); return cookie(name, value, options); } }; }(jQuery)); ; /* file-end: js/core/cookie.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/prop.js */ ;(function ($) { 'use strict'; LJ.define('LJ.Prop'); /** * Work with props * Perl location of accessible props: etc/lj-props-conf.pl */ LJ.Prop = (function () { return { get: get, set: set, remove: remove }; /** * Read from cookies */ function _read(name) { return LJ.Cookie.get('prop_' + name); } /** * Write prop value to cookie, reset if `NULL` */ function _write(name, value) { LJ.Cookie.setGlobal( 'prop_' + name, // Remove cookie if stringified null value === 'null' ? null : value, { expires: 30 } ); return value; } /** * Get prop value * * Notice: * If prop has not been set or has been removed - it's value will be `null` * * @example * * LJ.Prop.get('discovery_about_off').then(function (value) { * console.log('Prop value: ', value); * }); */ function get(name) { var defer = $.Deferred(); // user is logged in - try to get prop from server if ( LJ.get('remote') ) { LJ.Api.call('user.get_prop', { name: name }, function (response) { if ( response.hasOwnProperty('value') ) { try { defer.resolve(response.value); } catch (e) { defer.reject('Can not parse prop value: ' + name); } defer.resolve(response.value); return; } defer.reject('Something went wrong during reading of prop ' + name); }); } else { defer.resolve( _read(name) ); } return defer.promise().then(function (value) { // resolve the resulted promise with parsed JSON or reject it try { return JSON.parse(value); } catch (e) { return $.Deferred().reject(e); } }); } /** * Set prop * * @example * * LJ.Prop.set('discovery_about_off', 1).then(function () { * console.log('prop has been set'); * }); */ function set(name, value) { var defer = $.Deferred(); // stringify the value before saving value = JSON.stringify(value); if ( LJ.get('remote') ) { LJ.Api.call('user.set_prop', { name: name, value: value }, function ( response ) { if ( response.status === 'OK' ) { // for logged in user we should set prop and cookie defer.resolve(); _write(name, value); return; } defer.reject('Something went wrong during writing of prop ' + name); }); } else { _write(name, value); defer.resolve(); } return defer.promise(); } /** * Remove prop * * @example * * LJ.Prop.remove('discovery_about_off').then(function () { * console.log('prop cleared. Now it is equal to NULL'); * }); */ function remove(name) { return set(name, null); } }()); }(jQuery)); ; /* file-end: js/core/prop.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/lj.api.js */ /*global Unique*/ ;(function ($) { 'use strict'; /** * @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 : Date.now()), 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; 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) { 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 { console.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) { console.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(); } } }); 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) { console.warn('LJ.Api.init was already called before'); } context._initFired = true; context.options = $.extend({}, options); if (!context.options.auth_token) { console.warn('Auth token has not been specified, request may fail'); } if (cdn.endpoint) { if ( LJ.get('rpc.public') ) { cdn.methods = $.extend({}, LJ.get('rpc.public')); } } 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), cacheTime = publicMethod ? Math.ceil(cdn.time / Number(cdn.methods[name])) : null, 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 = cacheTime; } 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' + cacheTime + 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 ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- 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() { 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 { 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)) { console.log('Warn: Module ', name, ' has already been registered for ', this.widgetName); return; } this.__modules[name] = module.call(this, jQuery, options); } else { 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 */ /* --------------------------------------------------------------------------------- file-start: js/deprecated/basic.deprecated.js */ /** Deprecated stuff from js/basic.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)); }; /* 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; }; 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); }; /* 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; }); } }); /* 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("&"); } }; ; /* file-end: js/deprecated/basic.deprecated.js ----------------------------------------------------------------------------------*/ (function ($) { 'use strict'; // set `js` ID for the root element (for CSS) $('html').attr('id', 'js'); // Fix facebook redirect hash: LJSUP-18379 // http://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url // https://developers.facebook.com/blog/post/552/ (function () { if ( location.hash !== '#_=_' ) { return; } // fix for browsers that support history API if ( history && history.pushState ) { history.pushState('', document.title, location.pathname); return; } // fix for browsers that don't support history API var $window = $(window), top = $window.scrollTop(), left = $window.scrollLeft(); location.hash = ''; // reset scroll positions $window.scrollTop(top); $window.scrollLeft(left); }()); }(jQuery)); /** * Unique id generator * @todo Move it from global namespace */ window.Unique = { length: 0, id: function(){ return ++this.length; } }; /** * @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 = String(num); if (/^\d+$/.test(num)) { var delim = LJ.ml('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 = LJ.ml('date.format.short'); } else if (format === 'long') { format = LJ.ml('date.format.long'); } return format; } function getMonth(idx) { var month = months[ idx % 12 ]; return LJ.ml(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 || datestr instanceof Date) { return datestr; } var testStr = normalizeFormat(format), positions = [ null ], pos = 0, token, regs = { '%Y' : '(\\d{4})', '%M' : '(\\d{2})', '%D' : '(\\d{2})', '%H' : '(\\d{2})', '%m' : '(\\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; case '%H': d.setHours( arr[ i ] ); break; case '%m': d.setMinutes( 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; }; }()); /** * @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 { 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() { 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 + ']'; 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); }; }()); // 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; }; } /** * 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 (!LJ.get('remote')) { // 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 }, 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)); // switch to Version 3 // @todo Remove this code after old design becomes unavailable (function ($) { 'use strict'; $(function () { $('.s-switchv3-switch').on('click', function () { if ( LJ.get('remote') ) { // user is logged in - make API request LJ.Api.call('settings.set_old_design', { value: 0 }, location.reload.bind(location)); } else { // user is logged out - remove the cookie LJ.Cookie.setGlobal('ljold', null); location.reload(); } }); }); }(jQuery)); ; /* file-end: js/basic.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/jquery_fn.js */ /* --------------------------------------------------------------------------------- file-start: js/hourglass.js */ !function(a){"use strict";function b(){this.element=a("",{css:{position:"absolute",display:"none",zIndex:5e3},width:17,height:17,src:Site&&Site.imgprefix?Site.imgprefix+"/hourglass.gif?v=1674":"/img/hourglass.gif?v=1674"}),this.element.appendTo(document.body),this.ele=this.element.get(0),arguments.length&&this.init.apply(this,arguments)}b.prototype.init=function(a,b){return"string"==typeof b&&this.element.addClass(b),"undefined"!=typeof a&&(this.setContainer(a),this.show()),this},b.prototype.setPosition=function(a,b){return this.element.css({left:a-8,top:b-8}),this},b.prototype.setContainer=function(b){var c=a(b),d=c.offset(),e=d.left+c.width()/2,f=d.top+c.height()/2;return this.setPosition(e,f),this},b.prototype.setEvent=function(a){return a.pageX&&a.pageY?this.setPosition(a.pageX,a.pageY):this.setContainer(a.target),this},b.prototype.show=function(){return this.element.show(),this},b.prototype.hide=function(){return this.element.hide(),this.remove(),this},b.prototype.remove=function(){return this.element.remove(),this},b.prototype.hourglass_at_widget=function(a){return this.setContainer(a),this.show(),this},b.prototype.hourglass_at=function(a,b){return this.setPosition(a,b),this.show(),this},b.prototype.add_class_name=function(a){return this.element.addClass(a),this},window.Hourglass=b}(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() { if ( $this.hasClass('placeholder') ) { $this.removeClass('placeholder').val(''); } }); } if (this.value === this.getAttribute('placeholder') || !this.value) { $this.val(this.getAttribute('placeholder')).addClass('placeholder'); } else { $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(){ 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/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(a,b){"use strict";var c=b.LJ=b.LJ||{};c.UI=c.UI||{},c.UI._templates={},c.UI.loadTemplate=function(b,d){var e="",f=Site.server_time||String(Date.now()).replace(/\d{3}$/,"");return d=d||a.noop,f=Math.floor(f/Site.templates_update_time),c.UI._templates[b]?void d(void 0,b):(e+=Site.statprefix+"/tmpl??",e+=b.replace(/^templates-/,"").replace(/-/g,"/")+".tmpl?",e+="tm="+f,e+=";uselang="+Site.locale,e+=";v="+Site.version,void a.ajax({url:e,cache:!0,dataType:"script"}).success(function(){c.UI._templates[b]?d(void 0,b):(d(new Error("Template or server error"),b),console.log("Failed to setup template "+b))}).error(function(){d(new Error("Network error"),b),console.log("Failed to load template "+b)}))},c.UI.registerTemplate=function(b,d,e){var f;switch(e=e||"JQuery"){case"JQuery":if(f=a("#"+d),!f.length)return void console.log("Template node #"+d+" was not found");a.template(b,f.html());break;case"JQuery.stat":a.template(b,d),e="JQuery"}c.UI._templates[b]={type:e,data:d}},c.UI.template=function(b,d){var e,f,g=c.UI._templates[b];return g?f=a.tmpl(b,d):(e="Warn: template "+b+" was called but is not defined yet.",console.log(e),a())}}(jQuery,this);; /* file-end: js/core/template.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/core/track.js */ /* --------------------------------------------------------------------------------- file-start: js/core/atiKeys.js */ (function () { 'use strict'; LJ.Event.on('ATI:Register', function () { /** * digitCode for ATI. * 1 - home pages (without categories) * 2 - journals * 3 - services * 9 - magazine */ var HOMEPAGE = 1, JOURNALS = 2, SERVICEPAGE = 3, DISCOVERY = 9; // Profile page stats var profilePrefix = LJ.get('journal.is_community') ? 'profile_comm' : 'profile', profileOwn = LJ.get('can_manage') && LJ.get('journal.is_personal'); LJ.Track.ati.addGroup( JOURNALS , { // stats sidebar 'click .b-profile-stat-list .b-profile-stat-entrycount a' : 'profile::stat::post', 'click .b-profile-stat-list .b-profile-stat-posted a' : 'profile::stat::comments::posted', 'click .b-profile-stat-list .b-profile-stat-received a' : 'profile::stat::comments::received', 'click .b-profile-stat-list .b-profile-stat-tag a' : 'profile::stat::tags', 'click .b-profile-stat-list .b-profile-stat-points a' : 'profile::stat::points', 'click .b-profile-stat-list .b-profile-stat-memcount a' : 'profile::stat::favourite', 'click .b-profile-stat-list .b-profile-stat-photos a' : 'profile::stat::photos', 'click .b-profile-stat-list .b-profile-stat-vgift a' : 'profile::stat::vgifts', 'click .b-profile-stat-list .b-profile-stat-userpic a' : 'profile::stat::upics', // tabs friends 'click .b-profile-friends .b-menu-item' : function ($element) { var data = $element.data(); //cancel own profile clicks or if cannot get the key entirely if ( !profileOwn || !data.blockName || !data.tabName ) { return false; } return [profilePrefix, data.blockName, data.tabName].join('::'); }, // tabs about 'click .b-profile-about .b-menu-item' : function ($element) { var data = $element.data('pill'); if ( !data ) { return false; } return [profilePrefix, data].join('::'); }, // controls top menu 'click .b-profile-actions .b-profile-actions-edituser' : 'profile::control::add', 'click .b-profile-actions .b-profile-actions-addfriend' : 'profile::control::add', 'click .b-profile-actions .b-profile-actions-viewfriendsfeed': 'profile::control::feed', 'click .b-profile-actions .b-profile-actions-postentry' : 'profile::control::post', 'click .b-profile-actions .b-profile-actions-trackuser' : 'profile::control::subscr', 'click .b-profile-actions .b-profile-actions-sendmessage' : 'profile::control::message', 'click .b-profile-actions .b-profile-actions-sendgift' : 'profile::control::vgift', 'click .b-profile-actions .b-profile-actions-editfriends' : 'profile::control::editfriends', 'click .b-profile-actions .b-profile-actions-manageprofile' : 'profile::control::editprofile', 'click .b-profile-actions .b-profile-actions-addaliascomm' : 'profile::control::addnote', 'click .b-profile-userinfo .b-profile-group-geo .b-profile-group-body': 'profile::control::addnote', 'click .b-profile-userinfo .b-profile-group-school li' : 'profile::search::study' }); // main menu stats LJ.Track.ati.addGroup( SERVICEPAGE , { 'click .s-logo' : 'main::menu::logo', 'click .s-nav-rootlink-discovery': 'main::menu::discovery', 'click .s-nav-rootlink-browse' : 'main::menu::browse', 'click .s-nav-rootlink-feed' : 'main::menu::feed', 'click .s-nav-item-editgroups a' : 'main::menu::groups', 'click .s-nav-item-edit a' : 'main::menu::editfriends', 'click .s-nav-item-friendsfriends a': 'main::menu::friendsfriends', 'click .s-nav-item-manage a' : 'main::menu::comm', 'click .s-nav-item-banusers a' : 'main::menu::banusers', 'click .s-nav-rootlink-shop' : 'main::menu::shop', 'click .s-nav-item-paid-account a': 'main::menu::paidacc', 'click .s-nav-item-promo a' : 'main::menu::promo', 'click .s-nav-item-paid-history a': 'main::menu::paidhistory', 'click .s-nav-item-tokens a' : 'main::menu::tokens', 'click .s-nav-rootlink-support': 'main::menu::support', 'click .s-nav-item-about a' : 'main::menu::about', 'click .s-nav-item-faq a' : 'main::menu::faq', 'click .s-nav-item-legal a' : 'main::menu::legal', 'click .s-nav-item-privacy a' : 'main::menu::privacy', 'click .s-nav-item-dmca a' : 'main::menu::dmca', 'click .s-nav-rootlink-blog' : 'main::menu::myblog', 'click .s-nav-item-you a' : 'main::menu::username', 'click .s-nav-item-post a' : 'main::menu::post', 'click .s-nav-item-profile a' : 'main::menu::profile', 'click .s-nav-item-messages a' : 'main::menu::messages', 'click .s-nav-item-scheduled a' : 'main::menu::scheduled', 'click .s-nav-item-comments a' : 'main::menu::comments', 'click .s-nav-item-statistics a': 'main::menu::stat', 'click .s-nav-item-tags a' : 'main::menu::tags', 'click .s-nav-item-customize a' : 'main::menu::customize', 'click .s-nav-item-settings a' : 'main::menu::settings', 'click .s-nav-item-logout a' : 'main::menu::logout', 'click .s-do-item-post' : 'main::minormenu::post', 'click .s-welcometo-switch' : 'main::minormenu::switchold', 'click .s-do-item-message' : 'main::minormenu::inbox', 'click .s-do-item-search header': 'main::minormenu::searchicon', 'submit .s-search form' : 'main::minormenu::search', 'click .s-welcometo-switcher': 'main::welcome::switch', 'submit .s-feedback form' : 'main::welcome::feedback' }); // mainpage + categories + special pages stats LJ.Track.ati.addGroup( HOMEPAGE , { 'click .p-home .s-footer .s-social-item-f a.lj-track' : 'main::footer::facebook', 'click .p-home .s-footer .s-social-item-tw a.lj-track': 'main::footer::twitter', 'click .p-home .s-footer .s-social-item-vk a.lj-track': 'main::footer::vk', 'click .p-home .s-footer .s-social-item-gp a.lj-track': 'main::footer::google', 'click .p-home .s-footer .s-footer-nav-item-about' : 'main::footer::about', 'click .p-home .s-footer .s-footer-nav-item-legal' : 'main::footer::tos', 'click .p-home .s-footer .s-footer-nav-item-privacy': 'main::footer::privacy', 'click .p-home .b-ljpromo-commpromo' : 'main::promo::commpromo', 'click .p-home .b-ljpromo-selfpromo' : 'main::promo::selfpromo', 'click .p-home .b-ljmustread' : 'main::promo::mustread', 'click .p-home .b-topten-promo-users': 'main::promo::users', 'click .p-home .b-topten-promo-comm' : 'main::promo::comm', 'click .p-home .b-topten-switcher-item-alltime-users': 'main::popular::users::alltime', 'click .p-home .b-topten-switcher-item-alltime-comm' : 'main::popular::comm::alltime', 'click .p-home .b-topten-switcher-item-day-users' : 'main::popular::users::day', 'click .p-home .b-topten-switcher-item-day-comm' : 'main::popular::comm::day', 'click .p-home .b-topten-items-users' : 'main::popular::users', 'click .p-home .b-topten-items-comm' : 'main::popular::comm', 'click .p-home .b-topten-footer-users': 'main::popular::allusers', 'click .p-home .b-topten-footer-comm' : 'main::popular::allcomm', 'click .p-home .l-flatslide-intro-settings': 'main::rating::settings::open', 'click .p-home .l-flatslide-scrolltop' : 'main::up', 'click .p-home .l-flatslide-menu-button': function ($element) { if ( $element.hasClass('l-flatslide-menu-button-opened') ) { return 'main::category::open'; } return 'main::category::close'; }, 'click .p-home .l-flatslide-menu-link' : function ($element) { var name = $element.data('name'); if ( !name ) { return; } return 'main::category::' + name; }, 'click .p-home .l-flatslide-settings-different-item' : 'main::rating::showone', 'click .p-home .l-flatslide-settings-friends-item' : 'main::rating::showfriends', 'click .p-home .l-flatslide-settings-hidden-item' : 'main::rating::showall', 'click .p-home .l-flatslide-settings-hidden-settings': 'main::rating::settings', 'click .p-home .b-todaylj-item' : 'main::sidebar::discovery', 'click .p-home .b-mainpage-banner-aside' : 'main::sidebar::ljmaps', 'click .p-home .b-featuredjournal-body-interesting' : 'main::sidebar::interesting', 'click .b-discoverytimes-head a' : 'main::ljtimes::discovery', 'click .b-discoverytimes-item-head a' : 'main::ljtimes::discovery', 'click .b-discoverytimes-item-body a' : 'main::ljtimes::discovery::post', 'click .b-discoverytimes-aside-random' : 'main::ljtimes::random', 'click .b-ljmaps-brand' : 'main::ljtimes::ljmaps', 'change .b-mainpage-settings-location-body select': 'main::rating::switch' }); // Discovery page stats. LJ.Track.ati.addGroup( DISCOVERY , { 'click .b-mainpage-state-discovery .b-discoveryannouncements-figure a' : 'discovery::preview', 'click .b-mainpage-state-discovery .b-discoveryannouncements-title a' : 'discovery::preview', 'submit .b-mainpage-discovery-feedback-form' : 'discovery::sendmsg', 'click .b-mainpage-state-discovery .b-discoveryannouncements-labels a' : 'discovery::preview::category', 'click .b-discoveryarticle .b-entryunit-comments' : 'discovery::post::comments', 'click .b-discoveryarticle .b-discoveryarticle-meta .b-flatbutton-green': 'discovery::post::goto', 'click .b-discoveryarticle .b-discoveryarticle-aside .b-todaylj-item a' : 'discovery::post::today', 'click .b-discoveryarticle .b-discoveryarticle-addfriend' : 'discovery::post::addfriend', 'click .b-discoveryarticle .b-mainpage-seealso-item' : 'discovery::post::seealso', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-todaylj-item' : 'discovery::sidebar::top', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-users .b-topten-body' : 'discovery::sidebar::users', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-users .b-topten-switcher-item-alltime-users': 'discovery::sidebar::users::alltime', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-users .b-topten-switcher-item-day-users' : 'discovery::sidebar::users::day', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-comm .b-topten-body' : 'discovery::sidebar::comm', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-comm .b-topten-switcher-item-alltime-comm' : 'discovery::sidebar::comm::alltime', 'click .b-mainpage-state-discovery .l-mainpage-aside .b-topten-comm .b-topten-switcher-item-day-comm' : 'discovery::sidebar::comm::day', 'click .b-mainpage-state-discovery .l-flatslide-menu-item' : function ($element) { var name = $element.data('pill'); if ( !name ) { return; } return 'discovery::category::' + name; }, 'click .b-mainpage-state-discovery .l-flatslide-menu-button': function ($element) { if ( $element.hasClass('l-flatslide-menu-button-opened') ) { return 'discovery::category::open'; } return 'discovery::category::close'; } }); // Feed page LJ.Track.ati.addGroup(JOURNALS, { 'click .b-lenta a.l-flatslide-settingslink' : 'feed::settings', 'click .b-lenta a.l-flatslide-menu-button' : 'feed::filters', 'click .l-flatslide-menu-item a[href*="feed?show=P"]' : 'feed::filters::journals', 'click .l-flatslide-menu-item a[href*="feed?show=C"]' : 'feed::filters::comms', 'click .l-flatslide-menu-item a[href*="feed?show=Y"]' : 'feed::filters::rss', 'click .l-flatslide-menu-item a[href*="editgroups.bml"]': 'feed::filters::settings' }); }); }());; /* file-end: js/core/atiKeys.js ----------------------------------------------------------------------------------*/ /*global ga*/ /* * Methods to track stuff using Google Analytics and ATI statistics */ (function($) { 'use strict'; /** * @example * LJ.Track.event('Category', 'Subcategory', 'Value', some_optional_number); * LJ.Track.timing('Category', 'Subcategory', time_in_ms); */ LJ.define('LJ.Track'); var trackedTiming = {}; var trackAnalytics; if ( LJ.Flags.isEnabled('ga_universal') ) { trackAnalytics = function () { if ( typeof ga !== 'function' ) { console.warn('Google Analytics is not ready'); return; } var args = Array.prototype.slice.call(arguments, 0); if ( LJ.get('is_dev_server') ) { console.info(args); return; } // add 'send' as argument, because of `ga` invocation arguments // => ga('send', ...); args.unshift('send'); ga.apply(null, args); }; // https://developers.google.com/analytics/devguides/collection/analyticsjs/events LJ.Track.event = trackAnalytics.bind(null, 'event'); // https://developers.google.com/analytics/devguides/collection/analyticsjs/user-timings LJ.Track.timing = trackAnalytics.bind(null, 'timing'); } else { trackAnalytics = function () { 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 */ 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'); } } }; /** * ATI Statistics * LJ.ATI defines at /cgi-bin/LJ/PageStats/ATI.pm * * Example of usage: * * LJ.Track.ati.addGroup( digitAtiCode, { 'eventType #jQuerySelector': function (element) }); * * @digitAtiCode digitCode ATI argument. * 1 - home pages (without categories) * 2 - journals * 3 - services * 9 - magazine * 0 - other pages * - jQuery event type; * @element eventType and selector as $('#jQuerySelector'). * @function - function, that returning ATI key for '#jQuerySelector' * * Example of usage: * * LJ.Track.ati.addGroup( eventType, { '#jQuerySelector': 'key::for::selector' }); * * String with key can be used instead of function. */ LJ.Track.ati = {}; /** * Adding groups js/core/atiKeys.js * * @param digitCode ATI argument. * @param keys {Object} */ LJ.Track.ati.addGroup = function (digitCode, keys) { // register events on // every pair { selector : key } for (var key in keys) { if ( keys.hasOwnProperty(key) ){ LJ.Track.ati._register( digitCode, key, keys[key] ); } } }; LJ.Track.ati._register = function (digitCode, method, key) { var delegateEventSplitter = /^(\S+)\s*(.*)$/; var match = method.match(delegateEventSplitter); var eventType = match[1], selector = match[2]; $('html').on(eventType, selector, function (event) { //imitate onclick LJ.Track.ati._click( digitCode, $.isFunction(key) ? key( $(event.currentTarget) ) : key ); }); }; /** * Send statistics to ATI only from production servers. * @param digitCode * @see LJ.Track.ati.addGroup for info * * @param key * @private */ LJ.Track.ati._click = function (digitCode, key) { if (!digitCode || !key ) { return; } // xt_click() docs at http://help.atinternet-solutions.com/EN/implementation/specific_tags/tg_clicks_en.htm if ( !LJ.get('is_dev_server') ) { if ( window.xt_click ) { window.xt_click(window, 'C', digitCode, key, 'S'); } else { // Hardcode ATI link. No xtcore.js loaded in iframes (because double page view issue LJSUP-19065). var date = new Date(); new Image().src = 'http://logc400.xiti.com/hit.xiti?s=528851' + '&s2=' + digitCode + '&p=' + key + '&clic=S' + '&hl=' + date.getHours() + 'x' + date.getMinutes() + 'x' + date.getSeconds() + '&r=' + screen.width + 'x' + screen.height + 'x' + screen.pixelDepth + 'x' + screen.colorDepth; } } else { console.log('C', digitCode, key, 'S'); } }; LJ.Event.trigger('ATI:Register'); LJ.Event.on('ATI:Widgets', function (widgets) { var tmpl = 'PUB-[{widgetName}]-[logged_in]-[widgets]----', query = []; $.each(widgets, function (value) { query.push(tmpl.supplant({widgetName: value})); }); if ( LJ.get('is_dev_server') ) { console.log('Stats for ATI. Registed widgets:', widgets.join()); } else { new Image().src = 'http://logc400.xiti.com/get.ad?xts=528851' + '&ati=' + query.join() + '&type=AT&rn=111' + '&url=http://i.rl0.ru/0.gif'; } }); LJ.Event.on('ATI:RegionalRatingChange', function (region) { var regionMapping = { ru : 1, ru_moscow : 2, ru_central: 3, ru_south : 4, ru_north : 5, ru_eastern: 6, ru_siberia: 7, ru_ural : 8, ru_volga : 9, by : 10, ua : 11, cyr : 12, // remote is sup : 13 - 1 = 12 noncyr : 13 // remote isn't sup: 13 - 0 = 13 }; // homepage module watch for LJ.ATI.params change LJ.ATI.params.x19 = region ? regionMapping[region] : regionMapping[13 - LJ.get('remote_is_sup')]; if ( LJ.get('is_dev_server') ) { console.log('Regional rating is changed to:', LJ.ATI.params.x19 ); } else { window.xt_click( window, 'F', LJ.ATI.level2id, LJ.ATI.page + '&' + LiveJournal.constructUrl('', LJ.ATI.params).replace('?', '') ); } }); }(jQuery)); /* * 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(a){"use strict";var b={},c=0,d="lj-widget",e="."+d;LJ.UI._widgets=b,LJ.UI.initWidgetNode=function(a,b,c){return a.hasClass(d)?void console.log("Node already has class "+d):(a.addClass(d),a.attr("data-widget",b),void(c&&a.attr("data-bootstrap",c)))},LJ.UI.initWidget=function(e,f){var g,h=e.data("widget"),i=e.data("widget-options"),j=e.data("bootstrap")||null;if(!e.attr("data-widget-id")){switch(typeof i){case"object":break;case"string":try{i=JSON.parse(i||"{}")}catch(k){g="Invalid options string: "+i+" for widget "+h,console.log(g),i={}}}if(f){if("function"!=typeof a.fn[h])return g="Widget "+h+" was not loaded",void console.log(g);a.fn[h].apply(e,[i])}b[++c]={ready:!!f,entryPoint:j,options:i,name:h,node:e},e.attr("data-widget-id",c).addClass(d).addClass(d+"-"+c)}},LJ.UI.removeWidget=function(a){var c=a.data("widget-id");return a.is(d)?b.hasOwnProperty(c)?void console.log("Widget "+c+" was removed already or never created"):void delete b[c]:void console.log("Widget was not found on node")},LJ.UI.bootstrap=function(c){var d,f,g,h;a(e).each(function(){LJ.UI.initWidget(a(this))});for(f in b)if(b.hasOwnProperty(f)){if(d=b[f],d.ready)continue;if(!c||d.entryPoint===c){if(g=a.fn[d.name],"function"!=typeof g){h="Widget "+d.name+" was not loaded",console.log(h);continue}g.apply(d.node,[d.options]),d.ready=!0}}}}(jQuery,this);; /* file-end: js/core/widget.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/livejournal.js */ /* --------------------------------------------------------------------------------- file-start: js/jquery/jquery.lj.share.js */ LJ.injectStyle('.ljshare-container{position:absolute;border:1px solid #555;-moz-border-radius:4px;background-color:#fff;padding:.1em;line-height:1.3em}.ljshare-service-list li{border:1px solid #fff;padding:.1em}.ljshare-service-list li:hover{background-color:#eee;border:1px solid #bbb;-moz-border-radius:2px;cursor:pointer}'); LJ.UI.registerTemplate('templates-Widgets-share', " ", 'JQuery.stat'); //= require_ml sharing.popup.title /** * @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: LJ.get('siteroot') + '/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' }, 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; 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 = LJ.Social.Share.getUrl(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; } } // encode all params ['url', 'title', 'text', 'hashtags'].forEach(function (field) { if ( !params[field] ) { params[field] = ''; return; } // Decode fields // Notice: fields comes encoded from server, but LJ.Social.Share needs // not encoded fields var value = params[field]; while ( decodeURIComponent(value) !== value ) { value = decodeURIComponent(value); } params[field] = value; }); 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'); // if we are trying to open in tab and browser supports it (IE > 8) // we should not prevent default action if ( !LJ.Social.Share.isTab(service) || ($.browser.msie && $.browser.version < 9) ) { e.preventDefault(); } this._container.bubble('hide'); this.shareLink(target.href, service); }, /** * Share link for service */ shareLink: function (url, service) { if ( LJ.Social.Share.isTab(service) ) { /** * 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) { LJ.Social.Share.openPopup(service, url, { width: $(window).width(), height: $(window).height() }); } /** * all other browsers support target='_blank' * and we should do nothing for opening in new tab */ } else { LJ.Social.Share.openPopup(service, url); } }, /** * 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; // 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: LJ.Social.Share.services().map(function (service) { return { service: service, url: LJ.Social.Share.getUrl(service, params), title: LJ.Social.Share.getTitle(service) }; }) }); 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'); } }); }(jQuery)); ; /* file-end: js/jquery/jquery.lj.share.js ----------------------------------------------------------------------------------*/ /*global ContextualPopup, LJ_IPPU*/ // 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', updateWalletBalance); LJ.Event.on('xdr/message', processXdr); // run other hooks LJ.Event.trigger('page_load'); // Lazy like buttons loader $(document.body).ljLikes(); // When journal v3 is enabled - widgets will parse lazy via lj-screenable directive var isFeed = /^\/feed/.test(location.pathname); if ( LJ.Flags.isDisabled('journal_v3') && !isFeed ) { LJ.Event.trigger('social:widgets:parse'); } if ( LJ.Flags.isDisabled('friendsfeed_v3') && isFeed ) { LJ.Event.trigger('social:widgets:parse'); } 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')); }); initSpoilers(); initResizeHelper(); initBanner(); initMobileLink(); }; // Add handler for mobile link close function initMobileLink() { $(document.body).on('click', '.b-message-mobile-close', function(event) { event.preventDefault(); LJ.Cookie.set('hide_mobile_link', 1, { expires: 7, domain: location.host.replace('www', '') }); $(document.body).addClass('p-mobile-msg-off'); }); } function initBanner() { var slot = $('.common-banner'); if (!slot.length || LJ.Cookie.get('common_banner_close') || !LJ.get('remote')) { return; } // add close handler slot.find('.common-banner-close').show().on('click', function () { var expires = new Date(), height = slot.height(); // 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.setGlobal('common_banner_close', '1', { expires: expires }); if (height > 0) { LJ.Track.event('Banner', 'Close event', 'Size ' + height); } }); } /** * Spoilers functionality - expand hidden text in posts when user clicks on corresponding link */ function initSpoilers() { $('body').on('click', '.lj-spoiler > .lj-spoiler-head a', function (event) { event.preventDefault(); $(this).closest('.lj-spoiler').toggleClass('lj-spoiler-opened'); }); } /** * Special helper class is added to the body if browser doesn't support media queries and * screen width is less then 1000px. */ function initResizeHelper() { var $window = $(window), $body = $('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 ($.browser.msie && Number($.browser.version) <= 8) { $window.on('resize', resizeFunc); resizeFunc(); } } /** * 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 */ function processXdr(message) { var type, messageCopy, name; if ( !message.type ) { return; } type = decodeURIComponent(message.type); messageCopy = {}; for (name in message) { if (message.hasOwnProperty(name) && name !== 'type') { messageCopy[name] = decodeURIComponent(message[name]); } } LJ.Event.trigger(type, messageCopy); } //refresh number of tokens in the header function updateWalletBalance() { $.get(LiveJournal.getAjaxUrl('get_balance'), function (resp) { if (!resp || resp.status !== 'OK') { return; } var newBalance = resp.balance ? parseInt(resp.balance, 10) : 0, balance = $('#LJ_Wallet_Balance'); if ( balance.length !== 0 ) { balance.html( resp.balance ? balance.html().replace(/\d+/, newBalance) : '' ); } else { balance = $('#LJ_Wallet_Balance_Controlstrip'); if ( balance.length ) { balance.html(newBalance); } } LJ.Event.trigger('balance_updated', resp.balance); }, 'json'); } }(jQuery)); 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) { if (status === 'success') { LiveJournal.pollAnswersReceived(data); } else { 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)') + '
'; if (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) { if ( args.hasOwnProperty(i) ) { queryArr.push(i + '=' + ( ( escapeArgs ) ? encodeURIComponent(args[i]) : args[i] )); } } } if ( queryArr.length === 0 ) { return base; } return queryStr + queryArr.join('&'); }; //ljuniq cookie is checked here now instead of PageStats/Omniture.pm (function () { 'use strict'; /** * Generate a string for ljuniq cookie * * @return {String} */ function generateLjUniq() { var alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', result = '', len = 15, i; 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; } // set ljuniq cookie, if it hasn't been set before if ( !LJ.Cookie.get('ljuniq') ) { LJ.Cookie.setGlobal('ljuniq', generateLjUniq(), { expires: 5000 }); } }()); 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'); }; ; /* 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, // if 'auto' - outerWidth() will be used // by default - 13px arrowWidth: 13, 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', bubbleOpenClass: 'p-openpopup' }, 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; $.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 () { 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 () { 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) { 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, 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'), // popup arrow drawn with borders (6px at left and right side) popupArrowWidth = typeof options.arrowWidth === 'number' ? options.arrowWidth : popupArrow.outerWidth(), targetOffset = targetControl.offset(), targetLeft = Math.round(targetOffset.left), targetTop = Math.round(targetOffset.top), targetWidth = targetControl.width(), outerWidth = targetControl.outerWidth(), targetHeight = targetControl.height(), 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 }, 'lb': { x: leftPositionX, y: topPositionY }, 'tl': { x: leftPositionX, y: topPositionY }, 'tr': { x: rightPositionX, y: topPositionY }, 'bl': { x: leftPositionX, y: bottomPositionY }, 'br': { x: rightPositionX, y: bottomPositionY }, 'rt': { 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 }]); $('body').addClass(this.options.classNames.bubbleOpenClass); 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'); $('body').removeClass(this.options.classNames.bubbleOpenClass); 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) { 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 */ /*global OK,VK,gapi,twttr,ticketManager*/ Site.page.template['CleanHtml/v3/LikeStatic.tmpl'] = '\n\n\n\n \n \n \n
\n\n\n\n Facebook0\n
\n\n\n\n Twitter0\n\n\n\n\n Google+0\n\n\n\n\n VK0\n\n\n\n\n Surfingbird\n\n\n\n\n Tumblr\n\n\n\n\n OK0\n\n\n\n\n Give 10\n\n'; //= require_ml sharing.service.digg //= require_ml sharing.service.email //= require_ml sharing.service.email //= require_ml sharing.service.facebook //= require_ml sharing.service.livejournal //= require_ml sharing.service.moimir //= require_ml sharing.service.odnoklassniki //= require_ml sharing.service.stumbleupon //= require_ml sharing.service.tumblr //= require_ml sharing.service.twitter //= require_ml sharing.service.vkontakte ;(function ($) { 'use strict'; LJ.define('LJ.Social'); LJ.Social.load = (function () { var locale = LJ.get('remoteLocale'); var scripts = { ok: 'http://connect.ok.ru/connect.js', vk: '//vk.com/js/api/openapi.js?105', google: function () { return LJ.injectScript( 'https://apis.google.com/js/platform.js', // replace ru_RU with ru { text: '{lang: "' + locale.replace(/_.*/,'') + '"}' } ); }, facebook: function () { var fbRoot = $('
', { id: 'fb-root' }).appendTo('body'); return LJ.injectScript( '//connect.facebook.net/' + locale + '/all.js' ).then(function () { FB.init({ appId: '214181831945836', xfbml: false }, null, fbRoot.get(0)); }); }, // twitter and surfingbird buttons works through iframe at the moment surfingbird: 'http://surfingbird.ru/share/share.min.js', twitter: 'http://platform.twitter.com/widgets.js', ramblerKassa: 'http://s2.kassa.rl0.ru/widget/js/ticketmanager.js' }; /** * Scripts loader. Also it caches loading promise to load script once. * @param {String} type Social script provider * @return {Promise} Script loading promise */ function load(type) { if ( load[type] ) { return load[type]; } if ( !scripts[type] ) { throw new Error('Social script for ' + type + ' is not provided.'); } load[type] = typeof scripts[type] === 'function' ? scripts[type]() : LJ.injectScript( scripts[type] ); return load[type]; } return load; }()); /** * Parse tweets, FB posts, Youtube subscribe buttons, etc * @param {HTMLElement} [element] Html element that contains widgets. * Default: body (now it's provided via widgets defaults) */ LJ.Social.parseWidgets = function (element) { // parse twitter embedded posts. if ( $('.twitter-tweet').length !== 0) { LJ.Social.load('twitter').then(function () { twttr.widgets.load(element); }); } // Twitter timeline // Notice: twitter script will parse widgets automatically // // https://dev.twitter.com/docs/embedded-timelines if ( $('.twitter-timeline').length !== 0 ) { LJ.Social.load('twitter'); } // parse fb embedded posts // https://developers.facebook.com/docs/plugins/embedded-posts if ( $('.fb-post').length !== 0 ) { LJ.Social.load('facebook').then(function () { FB.XFBML.parse(element); }); } // facebook follow button // https://developers.facebook.com/docs/plugins/follow-button if ( $('.fb-follow').length !== 0 ) { LJ.Social.load('facebook').then(function () { FB.XFBML.parse(element); }); } // facebook like box // https://developers.facebook.com/docs/plugins/like-box-for-pages if ( $('.fb-like-box').length !== 0 ) { LJ.Social.load('facebook').then(function () { FB.XFBML.parse(element); }); } // parse github embedded gist if ( $('.gh-gist').length !== 0 ) { LJ.Social.parseGists(element); } // Render all youtube subscribe buttons // https://developers.google.com/youtube/youtube_subscribe_button if ( $('.g-ytsubscribe').length !== 0 ) { LJ.Social.load('google').then(function () { gapi.ytsubscribe.go(element); }); } // parse rambler kassa widget if ( $('.rkassa').length !== 0 ) { LJ.Social.load('ramblerKassa').then(function () { var key = ''; $('body').append(key); LJ.Social.parseRamblerKassa(element); }); } }; LJ.Social.parseGists = function (element) { var gistSelector = '.gh-gist'; var $element; element = element || document.body; $element = $(element); function parse (node) { var id = node.data('gist-id'); if ( !id ) { return; } $.ajax({ method: 'post', dataType: 'jsonp', url: 'https://gist.github.com/{id}.json'.supplant({id: id}) }) .then(function (response) { node.html(response.div); node.append( $('').attr('rel', 'stylesheet').attr('href', response.stylesheet) ); }); } if ( $element.hasClass(gistSelector) ) { return parse($element); } $element.find('.gh-gist').each(function (index, node) { parse( $(node) ); }); }; LJ.Social.parseLikes = function () { return LJ.Social.parseLikes[ LJ.Flags.isEnabled('ljlike_v3') ? 'v3' : 'v2' ].apply(LJ.Social, arguments); }; LJ.Social.parseLikes.v3 = (function () { function LikeProvider(service, config) { this.service = service; $.extend(this, config); // bind events if ( typeof this.bindEvents === 'function' ) { this.bindEvents(); } } // // Static methods // /** * Register a provider * @param {String} provider Provider identifier * @param {Object} config Config object with methods and properties */ LikeProvider.create = function (provider, config) { var _providers = this._providers = this._providers || {}; _providers[provider] = new LikeProvider(provider, config); }; /** * Return template collection of buttons templates * @return {jQuery} Cloned collection of buttons */ LikeProvider.buttons = function () { if ( !this._buttons ) { this._buttons = $($.parseHTML( LJ.get('template')['CleanHtml/v3/LikeStatic.tmpl'].trim() )); } return this._buttons.clone(); }; /** * Get collection of buttons * @param {Array} providers Array of providers to get buttons for * @param {Object} options Options for buttons * @return {DocumentFragment} Collection of parsed buttons to append */ LikeProvider.parse = function(providers, options) { var fragment = document.createDocumentFragment(); var buttons = this.buttons(); providers.forEach(function (_provider) { var provider = this._providers[_provider]; var button; if ( provider ) { button = buttons.filter( provider.selector ); provider.parse(button, options); fragment.appendChild( button.get(0) ); } }, this); return fragment; }; // // Instance methods // /** Default events; Backbone-like event hash or function that returns event hash; * Provided function will be bound to the `body` * Notice: `this` is bound to the instance * * @example * events: function () { * // extend default events with one custom event * return $.extend({ * 'click .selector': function (event) { * console.log(event); * } * }, LikeProvider.prototype.events); * } */ LikeProvider.prototype.events = { 'click .lj-like-item': function (event) { var that = this; var button = $(event.currentTarget); // filter handler for currently clicked button // Notice: we have as much handlers as providers we have, // we should have this check because this is base events if ( !button.is(this.selector) ) { return; } // track buttons click LJ.Track.event('Like', this.service); if ( this.popup ) { var options = button.data('options'); this.open( options ).then(function () { // request counter after possible change that.updateCounter(button, options.url); }); } } }; /** * Parse like button * @param {jQuery} parent Likes parent node */ LikeProvider.prototype.parse = function (button, options) { // save options into button button.data('options', options); // initialize if ( typeof this.init === 'function' ) { this.init(button, options); } this.updateCounter(button, options.url); }; /** * Update button counter * @param {jQuery} button Button * @param {String} url Url to get counter for * @return {Promise} Promise that will be resolved with counter */ LikeProvider.prototype.updateCounter = function (button, url) { var defer = $.Deferred(); // get count if ( typeof this.count === 'function' ) { this.count(url).then(function (count) { // if count is a string "0" we should not show counter as well if ( count && count !== '0' ) { button.find('.b-flatsocial-counter').text(count); } defer.resolve(count); }, defer.reject); } else { defer.resolve(); } return defer.promise(); }; /** * Bind events */ LikeProvider.prototype.bindEvents = function () { var that = this; if ( typeof this.events === 'function' ) { this.events = this.events.call(this); } // bind events once if ( this.events && typeof this.events === 'object' ) { $.each(this.events, function (prop, value) { if ( typeof value !== 'function' ) { console.warn('You should provider function as event handler.'); return; } var firstSpace = prop.indexOf(' '); var eventType = prop.slice(0, firstSpace); var selector = prop.slice(firstSpace + 1); // add events to BODY and bind them to instance // We should do it on DOMContentLoaded, because sometimes our scripts // are placed in $(function () { $('body').on(eventType, selector, value.bind(that)); }); }); } }; /** * Open popup and focus on it * @return {Promise} Promise that will be resolved, when popup closed. * Notice: if other popup for same provider is opened - * promise will be rejected (for cleanup purposes */ LikeProvider.prototype.open = function (options) { return LJ.Social.Share.openPopup(this.service, options, this.popup); }; LikeProvider.create('vkontakte', { selector: '.lj-like-item-vkontakte', popup: { url: '//vk.com/share.php?url={url}&title={title}', width: 550, height: 330 }, count: function (url) { var defer = $.Deferred(); // VK service has no external API that is why we need to use their internal endpoint, // which is JSONP with `VK.Share.count(index, count);` response // We replace their function during counter request LJ.define('VK.Share'); var _original = VK.Share.count; VK.Share.count = function (index, count) { defer.resolve(count); VK.Share.count = _original; }; $.getScript('//vk.com/share.php?act=count&index=1&url=' + url) .then(null, function () { VK.Share.count = _original; defer.reject(); }); return defer.promise(); } }); LikeProvider.create('facebook', { selector: '.lj-like-item-facebook', popup:{ url: 'https://www.facebook.com/sharer/sharer.php?u={url}', width: 600, height: 500 }, count: function (url) { return $.getJSON('//graph.facebook.com/fql?q=SELECT+total_count+FROM+link_stat+WHERE+url%3D%22' + url + '%22&callback=?') .then(function (response) { return response.data[0].total_count; }); } }); // Server support is needed for counters LikeProvider.create('google', { selector: '.lj-like-item-google', popup: { url: 'https://plus.google.com/share?url={url}', width: 700, height: 500 } }); LikeProvider.create('twitter', { selector: '.lj-like-item-twitter', popup: { url: 'https://twitter.com/intent/tweet?url={url}&text={title}&hashtags={hashtags}', width: 600, height: 450 }, count: function (url) { return $.getJSON('//cdn.api.twitter.com/1/urls/count.json?url=' + url + '&callback=?') .then(function (response) { return response.count; }); } }); LikeProvider.create('odnoklassniki', { selector: '.lj-like-item-odnoklassniki', popup: { url: 'http://www.odnoklassniki.ru/dk?st.cmd=addShare&st._surl={url}', width: 550, height: 360 }, count: function ok(url) { return $.getJSON('//www.odnoklassniki.ru/dk?st.cmd=shareData&ref=' + url + '&cb=?') .then(function (response) { return response.count; }); } }); LikeProvider.create('tumblr', { selector: '.lj-like-item-tumblr', popup: { url: 'https://www.tumblr.com/share?v=3&u={url}&t={title}&s=', width: 428, height: 450 } }); LikeProvider.create('surfingbird', { selector: '.lj-like-item-surfinbird', popup: { url: 'http://surfingbird.ru/share?url={url}', width: 650, height: 470 } }); LikeProvider.create('repost', { selector: '.lj-like-item-repost', events: null, init: function (button, options) { LJ.Api.call('repost.get_status', { url: options.url }, function (data) { button.find('a').replaceWith( LJ.Social.renderRepostButton(options.url, data) ); }); } }); /** * LiveJournal Give 10 Button * See: entry.js => Donate.* * * @todo Reimplement donate button without Donate.* */ LikeProvider.create('livejournal', { selector: '.lj-like-item-livejournal', events: null, init: function (button, options) { LJ.Api.call('social.give_button', { journal: options.journal, ditemid: options.ditemid }, function (response) { if ( response.status === 'ok' && response.html ) { button.html( response.html ); } }); } }); function parse($node) { if ( !$node.jquery ) { $node = $($node); } var options = $node.data(); var services = options.services.trim().split(','); if ( $node.data('parsed') ) { return; } $node.append( LikeProvider.parse(services, options) ); $node.data('parsed', true); } return parse; }()); LJ.Social.parseLikes.v2 = (function () { 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', vk: '.lj-like-item-vkontakte', ok: '.lj-like-item-odnoklassniki' }; /** * 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); parseOK($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; } LJ.Social.load('facebook').then(function () { FB.XFBML.parse( item.get(0) ); }); } /** * 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(); if ($button.length === 0) { return; } LJ.Social.load('google').then(function () { gapi.plusone.render($button.get(0), { size: $button.attr('size'), href: $button.attr('href') }); }); } /** * Parse and replace twitter button * @param {jQuery} $node jQuery node with .lj-like class */ function parseTwitter($node) { var item = $node.find( selectors.twitter ), link; if (item.length === 0) { return; } // link to replace with iframe link = item.children().eq(0); link.replaceWith( createIframe({ src: LiveJournal.constructUrl('http://platform.twitter.com/widgets/tweet_button.html', { url: link.data('url'), text: link.data('text') || '', count: link.data('count'), lang: link.data('lang') || 'en', hashtags: link.data('hashtags') || '' }) }) ); } /** * Parse surfingbird share button * @param {jQuery} $node jQuery .lj-like node */ function parseSurfingbird($node) { var item = $node.find( selectors.surfingbird ), link; if (item.length === 0) { return; } link = item.find('.surfinbird__like_button'); link.replaceWith( createIframe({ src: LiveJournal.constructUrl('http://surfingbird.ru/button', { url: link.data('url'), caption: link.data('text'), layout: 'common' }) }) ); } /** * 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.Social.renderRepostButton(url, data)); }); } function parseVK($node) { var vk = $node.find(selectors.vk), id = vk.attr('id'); if ( vk.length === 0 ) { return; } LJ.Social.load('vk').then(function () { // initialize API if ( !parseVK.initialized ) { VK.init({ apiId: LJ.get('vk_api_id'), onlyWidgets: true }); parseVK.initialized = true; } VK.Widgets.Like(id, vk.data('vk-options')); }); } function parseOK($node) { var ok = $node.find( selectors.ok ).children(); if ( ok.length === 0 ) { return; } LJ.Social.load('ok').then(function () { OK.CONNECT.insertShareWidget( ok.attr('id'), ok.data('url'), '{width:100,height:30,st:"straight",sz:20,nt:1}' ); }); } return parse; }()); /** * @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.Social.parseLikes() * @todo Move plugin to separate file */ (function () { 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) { // for likes v3 we do not need to parse comments if ( LJ.Flags.isEnabled('ljlike_v3') ) { LJ.Social.parseLikes( node ); return; } 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.Social.parseLikes( node.html(html) ); } /** * 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 }; }()); /** * Share handler * @param {String} service Social service, eg twitter, facebok... * @param {Object} options Sharing object {url, title, hashtags, text} * @return {Promise} Return promise that will be resolved when sharing popup will be closed */ LJ.Social.Share = (function () { var SHARE_CONFIG = { livejournal: { url: LJ.get('siteroot') + '/update.bml?repost_type=c&repost={url}&nodraft=1', tab: true }, facebook: { url: 'https://www.facebook.com/sharer/sharer.php?u={url}', width: 600, height: 500 }, twitter: { url: 'http://twitter.com/share?url={url}&text={title}&hashtags={hashtags}' }, vkontakte: { url: '//vk.com/share.php?url={url}&title={title}', width: 550, height: 330 }, moimir: { url: 'http://connect.mail.ru/share?url={url}' }, stumbleupon: { url: 'http://www.stumbleupon.com/submit?url={url}', tab: true }, digg: { url: 'http://digg.com/submit?url={url}', tab: true }, email: { title: 'E-mail', url: 'http://api.addthis.com/oexchange/0.8/forward/email/offer?username=internal&url={url}&title={title}', height: 600 }, tumblr: { url: 'https://www.tumblr.com/share?v=3&u={url}&t={title}&s=', width: 428, height: 450 }, odnoklassniki: { url: 'http://www.odnoklassniki.ru/dk?st.cmd=addShare&st.s=1&st._surl={url}', width: 550, height: 360 } }; var SERVICES_ORDER = [ 'livejournal', 'facebook', 'twitter', 'vkontakte', 'moimir', 'stumbleupon', 'digg', 'email', 'tumblr', 'odnoklassniki' ]; var DEFAULT_OPTIONS = { width: 640, height: 480 }; var popupDefer; /** * Open share window * @param {String} service Service * @param {Object} params Share params * @param {Object} options Share window options * @return {Promise} Promise that will be resolved on close */ function openPopup(service, params, options) { options = $.extend({}, DEFAULT_OPTIONS, SHARE_CONFIG[service], options || {}); // url provided if ( typeof params === 'string' ) { options.url = params; params = {}; } else if ( !params || typeof params !== 'object' || !params.url ) { throw new TypeError('Incorrect params provided. You should provide object with at least `url` field.'); } var left = Math.round( ($(window).width() - options.width) / 2 ); var top = Math.round( ($(window).height() - options.height) / 2 ); var win = window.open( getUrl(service, params, options.url), 'share_' + service, [ 'width=' + options.width, 'height=' + options.height, 'left=' + left, 'top=' + top, 'personalbar=0,toolbar=0,scrollbars=1,resizable=1' ].join(',') ); // Notice: // If we do not focus window and try to share other post - popup window // will lose the focus and we will not see it again win.focus(); // reject previous popup if ( popupDefer ) { popupDefer.reject(); } var defer = $.Deferred(); var promise = defer.promise(); // poll popup closing var interval = setInterval(function () { if ( win.closed ) { defer.resolve(); } }, 1000); var cleanup = function () { win = null; clearInterval(interval); }; // do not use jQuery .always() that is not compatible with Promises A+ spec promise.then(cleanup, cleanup); // export promise to allow reject it popupDefer = defer; return promise; } /** * Get share url for serverce (that could be opeened in new tab) * @param {String} service Service * @param {Object} params Params object * @param {String} [url] Url to use (with supplant params). Default - from config * @return {String]} Share url */ function getUrl(service, params, url) { if ( typeof url === 'undefined' ) { url = SHARE_CONFIG[service].url; } if ( service === 'tumblr' ) { params = $.extend({}, params, { url: encodeURIComponent(params.url) }); } return url.supplant(params); } /** * Open sharing as a tab, or as a popup * @param {String} service Service name * @return {Boolean} Result */ function isTab(service) { return SHARE_CONFIG[service].tab; } /** * Services available */ function services() { if ( LJ.get('LJShareParams.links') ) { return LJ.get('LJShareParams.links'); } return Object.keys( SHARE_CONFIG ).sort(function (a, b) { return SERVICES_ORDER.indexOf(a) - SERVICES_ORDER.indexOf(b); }); } /** * Get service title * @param {String} service Service * @return {String} Service title */ function getTitle(service) { // @todo replace with LJ.ml when require_ml directive will be provided for production return LJ.get('LJShareParams.services.' + service + '.title') || service; } return { openPopup: openPopup, getUrl: getUrl, getTitle: getTitle, isTab: isTab, services: services }; }()); LJ.Social.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)); }; 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(); } }); } }); }); LJ.Social.parseRamblerKassa = LJ.Function.once(function (element) { var base = element || document; $(base).on('click', '.rkassa', function (event) { var $element = $(event.target); var id = $element.data('id'); event.preventDefault(); ticketManager.movieSchedule(id); }); }); LJ.Event.on('social:widgets:parse', LJ.Social.parseWidgets); LJ.Event.on('social:likes:parse', LJ.Social.parseLikes); }(jQuery)); ; /* file-end: js/entry/likes.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/pagescroller.js */ jQuery(function(){function a(){for(var a=jQuery(window).scrollTop(),b=0;ba)return b-1;return c.length-1}function b(b){if(c.length){var d=document.activeElement;if(d){var e=d.nodeName.toLowerCase();if("input"==e||"textarea"==e||"select"==e)return}var f;if(78===b.keyCode){var g=a()+1;if(g>=c.length)return;f=c.eq(g).offset(),window.scrollTo(f.left,f.top-10)}if(80===b.keyCode){var g=a()-1;if(0>g)return;f=c.eq(g).offset(),window.scrollTo(f.left,f.top-10)}}}var c=jQuery(".entry");c.length>1&&jQuery(document).keyup(b)});; /* file-end: js/pagescroller.js ----------------------------------------------------------------------------------*/ window.DonateButton = { buyMore: function(node, ml_message, event) { var bubble = jQuery(node).data('buyMoreCachedBubble'); if (!bubble) { bubble = jQuery('' + 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' ) { LJ.Event.trigger( '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; $(document).on('click', this.selector, function(ev) { self.handler(this, ev); }); }, handler: function(el) { var im = new Image(); im.onload = im.onerror = $.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 = $('').attr('src', image.src), $el = $(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 = $('', { href: href }).append(img); $el.next('.b-mediaplaceholder-external').remove(); } $el.replaceWith(img); } }, video: { handler: function(link, html) { link.parentNode.replaceChild($(window.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; }; LJ.Event.on('page_load', function() { $('.b-mediaplaceholder').each(function() { if (storage.inStorage(this.href)) { this.onclick.apply(this); } }); }); }(jQuery)); ; /* file-end: js/journal.js ----------------------------------------------------------------------------------*/ /* --------------------------------------------------------------------------------- file-start: js/livejournal-local.js */ /*global DOM*/ window.$ = 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 */ !function(){"use strict";function a(a){var c,d;if("object"!=typeof a||null===a)throw new TypeError("Data should be an object.");return c=a.username,d=a.action,-1===b.indexOf(d)?void console.error("Action "+d+" is not allowed."):void LJ.Api.call("relations."+d.toLowerCase(),{target:c},function(b){LJ.Event.trigger("relations.changed",{action:d,username:c,data:b}),"function"==typeof a.callback&&a.callback(b)})}var b=["addFriend","removeFriend","subscribe","unsubscribe","join","leave","setBan","setUnban","banEverywhere","unbanEverywhere"];LJ.Event.on("relations.change",a)}();; /* 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 BODY:not(.s-schemius) .b-contextualhover A:link,\n BODY:not(.s-schemius) .b-contextualhover A:visited {\n background: #FFF;\n border-bottom: 0 !important;\n text-decoration: none !important;\n color: #00C !important;\n }\n\n BODY:not(.s-schemius) .b-contextualhover A:hover,\n BODY:not(.s-schemius) .b-contextualhover A:active,\n BODY:not(.s-schemius) .b-contextualhover A:focus {\n border-bottom: 0 !important;\n text-decoration: underline !important;\n color: #00C !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.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\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}}
  • ${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, LJWidgetIPPU, LJ_IPPU, LJWidgetIPPU_AddAlias */ /** * 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. * * @return {Promise} Promise that will be resolved after ippu widget is loaded */ var loadIPPU = (function() { // all dependencies are listed via require var files = ['ljwidget_ippu.js']; return LJ.Function.once(function() { return LJ.injectScript( LJ.get('statprefix') + '/js/??' + files.join(',') ).then(createAlias); }); function createAlias() { window.LJWidgetIPPU_AddAlias = new Class(LJWidgetIPPU, { init: function (opts) { 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 var 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, 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); 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 that = this; el = jQuery(el); el.on('mouseenter', function () { that.show(); }); el.on('mouseleave', function () { that.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: LJ.get('siteroot') + '/manage/notes.bml', click: function (e) { var that = this; e.preventDefault(); LJ.Track.event('Site', 'ContextualHover', 'Edit note'); loadIPPU().then(function() { addAlias(that, data.alias_title, data.username, data.alias || ''); }); }, text: data.alias_title }); } else { buildObject.headLinks.push([ '', '', '', ' ', '' + data.alias_title + '', '' ].join('')); } } if (data.is_logged_in && !data.is_requester) { // add/remove friend link (function () { if ( LJ.Flags.isEnabled('new_friends_and_subscriptions') ) { // 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('new_friends_and_subscriptions') && !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 // join/leave community should not be displayed if membership is 'closed' if ( data.is_logged_in && data.is_comm && data.membership !== 'closed' ) { // 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 && LJ.get('journal.is_community') ) || data.posted_in ) { linkGroup.push({ url: ( ( data.posted_in ) ? data.posted_in : LJ.get('journal.journal_url') ) + '/?poster=' + data.username, text: ( LJ.get('remote.username') === 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: LJ.get('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: LJ.get('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: LJ.get('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 ( !LJ.get('remote_is_suspended') ) { buildObject.reportBot = { url: LJ.get('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'; } // show social capital only if user is cyrillic: LJSUP-19251 if ( LJ.get('remote_is_sup') && data.value ) { buildObject.socialCap = { first: Boolean(data.first), value: data.value }; } buildObject.partner = Boolean(data.partner); 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 ( !LJ.get('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.hideHourglass(); 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().then(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('new_friends_and_subscriptions') ) { // 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 ----------------------------------------------------------------------------------*/ ; /* file-end: js/core/main.js ----------------------------------------------------------------------------------*/