PageSourceSearch

https://www.yha.org.hk/wp-content/themes/yha/scripts/common.js?v=1790942120

js yha.org.hk collected 2026-10-02 11:55:41 UTC 979,048 bytes, 40,523 lines download raw bytes

1var YHA = YHA || {common:{}};
2
3
4
5(function() {
6
7	YHA.common.base_url = window.base_url;
8
9	YHA.common.template_url = window.template_url;
10
11	YHA.common.lang = window.lang;
12
13	YHA.common.isMobile = (function() {
14
15		var check = false;
16
17		(function(a) {
18
19			if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /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|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(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|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4)))
20
21				check = true;
22
23		})(navigator.userAgent || navigator.vendor || window.opera);
24
25		return check;
26
27	})();
28
29
30
31	YHA.common.formatDate = function(date) {
32
33		if(date instanceof Date) {
34
35			var thisDate = date;
36
37		} else {
38
39			var thisDate = new Date(date);
40
41		}
42
43		var year = thisDate.getFullYear();
44
45		var month = thisDate.getMonth();
46
47		var day = thisDate.getDate();
48
49		var shortMonthsInYear   = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
50
51	                              'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
52
53		switch(YHA.common.lang) {
54
55			case 'en':
56
57				return day + ' ' + shortMonthsInYear[month] + ' ' + year;
58
59				break;
60
61			case 'zh':
62
63			case 'sc':
64
65				return year + '年' + (month+1) + '月' + day + '日';
66
67				break;
68
69			default:
70
71				return day + ' ' + shortMonthsInYear[month] + ' ' + year;
72
73		}
74
75	};
76
77
78
79	YHA.common.popupError = function(msg) {
80
81		$.magnificPopup.open({
82
83			items: {
84
85				src: '<div class="error-popup popup-content">' +
86
87						'<div class="table error-content">' +
88
89							'<div class="table-cell">' +
90
91								msg +
92
93							'</div>' +
94
95						'</div>' +
96
97						'<div class="btn btn-cricle btn-close" onclick="$.magnificPopup.close();">' +
98
99							'<div class="table">' +
100
101								'<div class="table-cell">' +
102
103									'OK' +
104
105								'</div>' +
106
107							'</div>' +
108
109						'</div>' +
110
111					'</div>',
112
113				type: 'inline'
114
115			},
116
117			fixedContentPos: true
118
119		});
120
121	}
122
123})(); 
124/*! jQuery v1.11.3 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
125
126!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.3",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);
vendor: 3,641 bytes, line 126
126return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b="length"in a&&a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s
vendor: 18,080 bytes, line 126
126=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")}
vendor: 16,846 bytes, lines 126-130
126)||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;
127
128
129
130return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?m.queue(this[0],a):void 0===b?this:this.each(function(){var c=m.queue(this,a,b);m._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&m.dequeue(this,a)})},dequeue:function(a){return this.each(function(){m.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=m.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=m._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var S=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=["Top","Right","Bottom","Left"],U=function(a,b){return a=b||a,"none"===m.css(a,"display")||!m.contains(a.ownerDocument,a)},V=m.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===m.type(c)){e=!0;for(h in c)m.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,m.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(m(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="<input type='radio' checked='checked' name='t'/>",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function aa(){return!0}function ba(){return!1}function ca(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{}
vendor: 1,726 bytes, line 130
130,e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>
vendor: 54,828 bytes, lines 130-132
130=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[m.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=Z.test(e)?this.mouseHooks:Y.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new m.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=f.srcElement||y),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,f):a},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button,g=b.fromElement;return null==a.pageX&&null!=b.clientX&&(d=a.target.ownerDocument||y,e=d.documentElement,c=d.body,a.pageX=b.clientX+(e&&e.scrollLeft||c&&c.scrollLeft||0)-(e&&e.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||c&&c.scrollTop||0)-(e&&e.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&g&&(a.relatedTarget=g===a.target?b.toElement:g),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ca()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ca()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return m.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return m.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=m.extend(new m.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?m.event.trigger(e,null,b):m.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},m.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){var d="on"+b;a.detachEvent&&(typeof a[d]===K&&(a[d]=null),a.detachEvent(d,c))},m.Event=function(a,b){return this instanceof m.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?aa:ba):this.type=a,b&&m.extend(this,b),this.timeStamp=a&&a.timeStamp||m.now(),void(this[m.expando]=!0)):new m.Event(a,b)},m.Event.prototype={isDefaultPrevented:ba,isPropagationStopped:ba,isImmediatePropagationStopped:ba,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=aa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=aa,a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=aa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},m.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){m.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!m.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.submitBubbles||(m.event.special.submit={setup:function(){return m.nodeName(this,"form")?!1:void m.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=m.nodeName(b,"input")||m.nodeName(b,"button")?b.form:void 0;c&&!m._data(c,"submitBubbles")&&(m.event.add(c,"submit._submit",function(a){a._submit_bubble=!0}),m._data(c,"submitBubbles",!0))})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&m.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){return m.nodeName(this,"form")?!1:void m.event.remove(this,"._submit")}}),k.changeBubbles||(m.event.special.change={setup:function(){return X.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(m.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._just_changed=!0)}),m.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1),m.event.simulate("change",this,a,!0)})),!1):void m.event.add(this,"beforeactivate._change",function(a){var b=a.target;X.test(b.nodeName)&&!m._data(b,"changeBubbles")&&(m.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||m.event.simulate("change",this.parentNode,a,!0)}),m._data(b,"changeBubbles",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return m.event.remove(this,"._change"),!X.test(this.nodeName)}}),k.focusinBubbles||m.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){m.event.simulate(b,a.target,m.event.fix(a),!0)};m.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=m._data(d,b);e||d.addEventListener(a,c,!0),m._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=m._data(d,b)-1;e?m._data(d,b,e):(d.removeEventListener(a,c,!0),m._removeData(d,b))}}}),m.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(f in a)this.on(f,b,c,a[f],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=ba;else if(!d)return this;return 1===e&&(g=d,d=function(a){return m().off(a),g.apply(this,arguments)},d.guid=g.guid||(g.guid=m.guid++)),this.each(function(){m.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,m(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=ba),this.each(function(){m.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){m.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?m.event.trigger(a,b,c,!0):void 0}});function da(a){var b=ea.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}var ea="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",fa=/ jQuery\d+="(?:null|\d+)"/g,ga=new RegExp("<(?:"+ea+")[\\s/>]","i"),ha=/^\s+/,ia=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ja=/<([\w:]+)/,ka=/<tbody/i,la=/<|&#?\w+;/,ma=/<(?:script|style|link)/i,na=/checked\s*(?:[^=]|=\s*.checked.)/i,oa=/^$|\/(?:java|ecma)script/i,pa=/^true\/(.*)/,qa=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ra={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:k.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},sa=da(y),ta=sa.appendChild(y.createElement("div"));ra.optgroup=ra.option,ra.tbody=ra.tfoot=ra.colgroup=ra.caption=ra.thead,ra.th=ra.td;function ua(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ua(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function va(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wa(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xa(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function ya(a){var b=pa.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function za(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Aa(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Ba(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xa(b).text=a.text,ya(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!ga.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(ta.innerHTML=a.outerHTML,ta.removeChild(f=ta.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ua(f),h=ua(a),g=0;null!=(e=h[g]);++g)d[g]&&Ba(e,d[g]);if(b)if(c)for(h=h||ua(a),d=d||ua(f),g=0;null!=(e=h[g]);g++)Aa(e,d[g]);else Aa(a,f);return d=ua(f,"script"),d.length>0&&za(d,!i&&ua(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=da(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(la.test(f)){h=h||o.appendChild(b.createElement("div")),i=(ja.exec(f)||["",""])[1].toLowerCase(),l=ra[i]||ra._default,h.innerHTML=l[1]+f.replace(ia,"<$1></$2>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&ha.test(f)&&p.push(b.createTextNode(ha.exec(f)[0])),!k.tbody){f="table"!==i||ka.test(f)?"<table>"!==l[1]||ka.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ua(p,"input"),va),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ua(o.appendChild(f),"script"),g&&za(h),c)){e=0;while(f=h[e++])oa.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wa(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ua(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&za(ua(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ua(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fa,""):void 0;if(!("string"!=typeof a||ma.test(a)||!k.htmlSerialize&&ga.test(a)||!k.leadingWhitespace&&ha.test(a)||ra[(ja.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ia,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ua(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ua(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&na.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ua(i,"script"),xa),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ua(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,ya),j=0;f>j;j++)d=g[j],oa.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qa,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Ca,Da={};function Ea(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fa(a){var b=y,c=Da[a];return c||(c=Ea(a,b),"none"!==c&&c||(Ca=(Ca||m("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ca[0].contentWindow||Ca[0].contentDocument).document,b.write(),b.close(),c=Ea(a,b),Ca.detach()),Da[a]=c),c}!function(){var a;k.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,d;return c=y.getElementsByTagName("body")[0],c&&c.style?(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(y.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(d),a):void 0}}();var Ga=/^margin/,Ha=new RegExp("^("+S+")(?!px)[a-z%]+$","i"),Ia,Ja,Ka=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ia=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c.getPropertyValue(b)||c[b]:void 0,c&&(""!==g||m.contains(a.ownerDocument,a)||(g=m.style(a,b)),Ha.test(g)&&Ga.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0===g?g:g+""}):y.documentElement.currentStyle&&(Ia=function(a){return a.currentStyle},Ja=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ia(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Ha.test(g)&&!Ka.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function La(a,b){return{get:function(){var c=a();if(null!=c)return c?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d,e,f,g,h;if(b=y.createElement("div"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=d&&d.style){c.cssText="float:left;opacity:.5",k.opacity="0.5"===c.opacity,k.cssFloat=!!c.cssFloat,b.style.backgroundClip="content-box",b.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===b.style.backgroundClip,k.boxSizing=""===c.boxSizing||""===c.MozBoxSizing||""===c.WebkitBoxSizing,m.extend(k,{reliableHiddenOffsets:function(){return null==g&&i(),g},boxSizingReliable:function(){return null==f&&i(),f},pixelPosition:function(){return null==e&&i(),e},reliableMarginRight:function(){return null==h&&i(),h}});function i(){var b,c,d,i;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),b.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",e=f=!1,h=!0,a.getComputedStyle&&(e="1%"!==(a.getComputedStyle(b,null)||{}).top,f="4px"===(a.getComputedStyle(b,null)||{width:"4px"}).width,i=b.appendChild(y.createElement("div")),i.style.cssText=b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",i.style.marginRight=i.style.width="0",b.style.width="1px",h=!parseFloat((a.getComputedStyle(i,null)||{}).marginRight),b.removeChild(i)),b.innerHTML="<table><tr><td></td><td>t</td></tr></table>",i=b.getElementsByTagName("td"),i[0].style.cssText="margin:0;border:0;padding:0;display:none",g=0===i[0].offsetHeight,g&&(i[0].style.display="",i[1].style.display="none",g=0===i[0].offsetHeight),c.removeChild(d))}}}(),m.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var Ma=/alpha\([^)]*\)/i,Na=/opacity\s*=\s*([^)]*)/,Oa=/^(none|table(?!-c[ea]).+)/,Pa=new RegExp("^("+S+")(.*)$","i"),Qa=new RegExp("^([+-])=("+S+")","i"),Ra={position:"absolute",visibility:"hidden",display:"block"},Sa={letterSpacing:"0",fontWeight:"400"},Ta=["Webkit","O","Moz","ms"];function Ua(a,b){if(b in a)return b;var c=b.charAt(0).toUpperCase()+b.slice(1),d=b,e=Ta.length;while(e--)if(b=Ta[e]+c,b in a)return b;return d}function Va(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=m._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&U(d)&&(f[g]=m._data(d,"olddisplay",Fa(d.nodeName)))):(e=U(d),(c&&"none"!==c||!e)&&m._data(d,"olddisplay",e?c:m.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function Wa(a,b,c){var d=Pa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Xa(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=m.css(a,c+T[f],!0,e)),d?("content"===c&&(g-=m.css(a,"padding"+T[f],!0,e)),"margin"!==c&&(g-=m.css(a,"border"+T[f]+"Width",!0,e))):(g+=m.css(a,"padding"+T[f],!0,e),"padding"!==c&&(g+=m.css(a,"border"+T[f]+"Width",!0,e)));return g}function Ya(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ia(a),g=k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Ja(a,b,f),(0>e||null==e)&&(e=a.style[b]),Ha.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Xa(a,b,c||(g?"border":"content"),d,f)+"px"}m.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Ja(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":k.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=m.camelCase(b),i=a.style;if(b=m.cssProps[h]||(m.cssProps[h]=Ua(i,h)),g=m.cssHooks[b]||m.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=Qa.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(m.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||m.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=m.camelCase(b);return b=m.cssProps[h]||(m.cssProps[h]=Ua(a.style,h)),g=m.cssHooks[b]||m.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Ja(a,b,d)),"normal"===f&&b in Sa&&(f=Sa[b]),""===c||c?(e=parseFloat(f),c===!0||m.isNumeric(e)?e||0:f):f}}),m.each(["height","width"],function(a,b){m.cssHooks[b]={get:function(a,c,d){return c?Oa.test(m.css(a,"display"))&&0===a.offsetWidth?m.swap(a,Ra,function(){return Ya(a,b,d)}):Ya(a,b,d):void 0},set:function(a,c,d){var e=d&&Ia(a);return Wa(a,c,d?Xa(a,b,d,k.boxSizing&&"border-box"===m.css(a,"boxSizing",!1,e),e):0)}}}),k.opacity||(m.cssHooks.opacity={get:function(a,b){return Na.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=m.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===m.trim(f.replace(Ma,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Ma.test(f)?f.replace(Ma,e):f+" "+e)}}),m.cssHooks.marginRight=La(k.reliableMarginRight,function(a,b){return b?m.swap(a,{display:"inline-block"},Ja,[a,"marginRight"]):void 0}),m.each({margin:"",padding:"",border:"Width"},function(a,b){m.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+T[d]+b]=f[d]||f[d-2]||f[0];return e}},Ga.test(a)||(m.cssHooks[a+b].set=Wa)}),m.fn.extend({css:function(a,b){return V(this,function(a,b,c){var d,e,f={},g=0;if(m.isArray(b)){for(d=Ia(a),e=b.length;e>g;g++)f[b[g]]=m.css(a,b[g],!1,d);return f}return void 0!==c?m.style(a,b,c):m.css(a,b)},a,b,arguments.length>1)},show:function(){return Va(this,!0)},hide:function(){return Va(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){U(this)?m(this).show():m(this).hide()})}});function Za(a,b,c,d,e){
131
132return new Za.prototype.init(a,b,c,d,e)}m.Tween=Za,Za.prototype={constructor:Za,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(m.cssNumber[c]?"":"px")},cur:function(){var a=Za.propHooks[this.prop];return a&&a.get?a.get(this):Za.propHooks._default.get(this)},run:function(a){var b,c=Za.propHooks[this.prop];return this.options.duration?this.pos=b=m.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Za.propHooks._default.set(this),this}},Za.prototype.init.prototype=Za.prototype,Za.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=m.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){m.fx.step[a.prop]?m.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[m.cssProps[a.prop]]||m.cssHooks[a.prop])?m.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Za.propHooks.scrollTop=Za.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},m.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},m.fx=Za.prototype.init,m.fx.step={};var $a,_a,ab=/^(?:toggle|show|hide)$/,bb=new RegExp("^(?:([+-])=|)("+S+")([a-z%]*)$","i"),cb=/queueHooks$/,db=[ib],eb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=bb.exec(b),f=e&&e[3]||(m.cssNumber[a]?"":"px"),g=(m.cssNumber[a]||"px"!==f&&+d)&&bb.exec(m.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,m.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function fb(){return setTimeout(function(){$a=void 0}),$a=m.now()}function gb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=T[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function hb(a,b,c){for(var d,e=(eb[b]||[]).concat(eb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,l,n=this,o={},p=a.style,q=a.nodeType&&U(a),r=m._data(a,"fxshow");c.queue||(h=m._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,n.always(function(){n.always(function(){h.unqueued--,m.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=m.css(a,"display"),l="none"===j?m._data(a,"olddisplay")||Fa(a.nodeName):j,"inline"===l&&"none"===m.css(a,"float")&&(k.inlineBlockNeedsLayout&&"inline"!==Fa(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",k.shrinkWrapBlocks()||n.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],ab.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||m.style(a,d)}else j=void 0;if(m.isEmptyObject(o))"inline"===("none"===j?Fa(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=m._data(a,"fxshow",{}),f&&(r.hidden=!q),q?m(a).show():n.done(function(){m(a).hide()}),n.done(function(){var b;m._removeData(a,"fxshow");for(b in o)m.style(a,b,o[b])});for(d in o)g=hb(q?r[d]:0,d,n),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=m.camelCase(c),e=b[d],f=a[c],m.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=m.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=db.length,h=m.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=$a||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:m.extend({},b),opts:m.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:$a||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=m.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);g>f;f++)if(d=db[f].call(j,a,k,j.opts))return d;return m.map(k,hb,j),m.isFunction(j.opts.start)&&j.opts.start.call(a,j),m.fx.timer(m.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}m.Animation=m.extend(kb,{tweener:function(a,b){m.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],eb[c]=eb[c]||[],eb[c].unshift(b)},prefilter:function(a,b){b?db.unshift(a):db.push(a)}}),m.speed=function(a,b,c){var d=a&&"object"==typeof a?m.extend({},a):{complete:c||!c&&b||m.isFunction(a)&&a,duration:a,easing:c&&b||b&&!m.isFunction(b)&&b};return d.duration=m.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in m.fx.speeds?m.fx.speeds[d.duration]:m.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){m.isFunction(d.old)&&d.old.call(this),d.queue&&m.dequeue(this,d.queue)},d},m.fn.extend({fadeTo:function(a,b,c,d){return this.filter(U).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=m.isEmptyObject(a),f=m.speed(b,c,d),g=function(){var b=kb(this,m.extend({},a),f);(e||m._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=m.timers,g=m._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&cb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&m.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=m._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=m.timers,g=d?d.length:0;for(c.finish=!0,m.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),m.each(["toggle","show","hide"],function(a,b){var c=m.fn[b];m.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),m.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){m.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),m.timers=[],m.fx.tick=function(){var a,b=m.timers,c=0;for($a=m.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||m.fx.stop(),$a=void 0},m.fx.timer=function(a){m.timers.push(a),a()?m.fx.start():m.timers.pop()},m.fx.interval=13,m.fx.start=function(){_a||(_a=setInterval(m.fx.tick,m.fx.interval))},m.fx.stop=function(){clearInterval(_a),_a=null},m.fx.speeds={slow:600,fast:200,_default:400},m.fn.delay=function(a,b){return a=m.fx?m.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a,b,c,d,e;b=y.createElement("div"),b.setAttribute("className","t"),b.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",d=b.getElementsByTagName("a")[0],c=y.createElement("select"),e=c.appendChild(y.createElement("option")),a=b.getElementsByTagName("input")[0],d.style.cssText="top:1px",k.getSetAttribute="t"!==b.className,k.style=/top/.test(d.getAttribute("style")),k.hrefNormalized="/a"===d.getAttribute("href"),k.checkOn=!!a.value,k.optSelected=e.selected,k.enctype=!!y.createElement("form").enctype,c.disabled=!0,k.optDisabled=!e.disabled,a=y.createElement("input"),a.setAttribute("value",""),k.input=""===a.getAttribute("value"),a.value="t",a.setAttribute("type","radio"),k.radioValue="t"===a.value}();var lb=/\r/g;m.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=m.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,m(this).val()):a,null==e?e="":"number"==typeof e?e+="":m.isArray(e)&&(e=m.map(e,function(a){return null==a?"":a+""})),b=m.valHooks[this.type]||m.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=m.valHooks[e.type]||m.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(lb,""):null==c?"":c)}}}),m.extend({valHooks:{option:{get:function(a){var b=m.find.attr(a,"value");return null!=b?b:m.trim(m.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&m.nodeName(c.parentNode,"optgroup"))){if(b=m(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=m.makeArray(b),g=e.length;while(g--)if(d=e[g],m.inArray(m.valHooks.option.get(d),f)>=0)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),m.each(["radio","checkbox"],function(){m.valHooks[this]={set:function(a,b){return m.isArray(b)?a.checked=m.inArray(m(a).val(),b)>=0:void 0}},k.checkOn||(m.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var mb,nb,ob=m.expr.attrHandle,pb=/^(?:checked|selected)$/i,qb=k.getSetAttribute,rb=k.input;m.fn.extend({attr:function(a,b){return V(this,m.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){m.removeAttr(this,a)})}}),m.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===K?m.prop(a,b,c):(1===f&&m.isXMLDoc(a)||(b=b.toLowerCase(),d=m.attrHooks[b]||(m.expr.match.bool.test(b)?nb:mb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=m.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void m.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=m.propFix[c]||c,m.expr.match.bool.test(c)?rb&&qb||!pb.test(c)?a[d]=!1:a[m.camelCase("default-"+c)]=a[d]=!1:m.attr(a,c,""),a.removeAttribute(qb?c:d)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&m.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),nb={set:function(a,b,c){return b===!1?m.removeAttr(a,c):rb&&qb||!pb.test(c)?a.setAttribute(!qb&&m.propFix[c]||c,c):a[m.camelCase("default-"+c)]=a[c]=!0,c}},m.each(m.expr.match.bool.source.match(/\w+/g),function(a,b){var c=ob[b]||m.find.attr;ob[b]=rb&&qb||!pb.test(b)?function(a,b,d){var e,f;return d||(f=ob[b],ob[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,ob[b]=f),e}:function(a,b,c){return c?void 0:a[m.camelCase("default-"+b)]?b.toLowerCase():null}}),rb&&qb||(m.attrHooks.value={set:function(a,b,c){return m.nodeName(a,"input")?void(a.defaultValue=b):mb&&mb.set(a,b,c)}}),qb||(mb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},ob.id=ob.name=ob.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},m.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:mb.set},m.attrHooks.contenteditable={set:function(a,b,c){mb.set(a,""===b?!1:b,c)}},m.each(["width","height"],function(a,b){m.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),k.style||(m.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var sb=/^(?:input|select|textarea|button|object)$/i,tb=/^(?:a|area)$/i;m.fn.extend({prop:function(a,b){return V(this,m.prop,a,b,arguments.length>1)},removeProp:function(a){return a=m.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),m.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!m.isXMLDoc(a),f&&(b=m.propFix[b]||b,e=m.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=m.find.attr(a,"tabindex");return b?parseInt(b,10):sb.test(a.nodeName)||tb.test(a.nodeName)&&a.href?0:-1}}}}),k.hrefNormalized||m.each(["href","src"],function(a,b){m.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),k.optSelected||(m.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null}}),m.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){m.propFix[this.toLowerCase()]=this}),k.enctype||(m.propFix.enctype="encoding");var ub=/[\t\r\n\f]/g;m.fn.extend({addClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j="string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).addClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=m.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0,i=this.length,j=0===arguments.length||"string"==typeof a&&a;if(m.isFunction(a))return this.each(function(b){m(this).removeClass(a.call(this,b,this.className))});if(j)for(b=(a||"").match(E)||[];i>h;h++)if(c=this[h],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ub," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?m.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(m.isFunction(a)?function(c){m(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=m(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===K||"boolean"===c)&&(this.className&&m._data(this,"__className__",this.className),this.className=this.className||a===!1?"":m._data(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ub," ").indexOf(b)>=0)return!0;return!1}}),m.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){m.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),m.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var vb=m.now(),wb=/\?/,xb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;m.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=m.trim(b+"");return e&&!m.trim(e.replace(xb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():m.error("Invalid JSON: "+b)},m.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||m.error("Invalid XML: "+b),c};var yb,zb,Ab=/#.*$/,Bb=/([?&])_=[^&]*/,Cb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Db=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Eb=/^(?:GET|HEAD)$/,Fb=/^\/\//,Gb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Hb={},Ib={},Jb="*/".concat("*");try{zb=location.href}catch(Kb){zb=y.createElement("a"),zb.href="",zb=zb.href}yb=Gb.exec(zb.toLowerCase())||[];function Lb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(m.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Mb(a,b,c,d){var e={},f=a===Ib;function g(h){var i;return e[h]=!0,m.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Nb(a,b){var c,d,e=m.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&m.extend(!0,a,c),a}function Ob(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Pb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}m.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:zb,type:"GET",isLocal:Db.test(yb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Jb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":m.parseJSON,"text xml":m.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Nb(Nb(a,m.ajaxSettings),b):Nb(m.ajaxSettings,a)},ajaxPrefilter:Lb(Hb),ajaxTransport:Lb(Ib),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=m.ajaxSetup({},b),l=k.context||k,n=k.context&&(l.nodeType||l.jquery)?m(l):m.event,o=m.Deferred(),p=m.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!j){j={};while(b=Cb.exec(f))j[b[1].toLowerCase()]=b[2]}b=j[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?f:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return i&&i.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||zb)+"").replace(Ab,"").replace(Fb,yb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=m.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(c=Gb.exec(k.url.toLowerCase()),k.crossDomain=!(!c||c[1]===yb[1]&&c[2]===yb[2]&&(c[3]||("http:"===c[1]?"80":"443"))===(yb[3]||("http:"===yb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=m.param(k.data,k.traditional)),Mb(Hb,k,b,v),2===t)return v;h=m.event&&k.global,h&&0===m.active++&&m.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!Eb.test(k.type),e=k.url,k.hasContent||(k.data&&(e=k.url+=(wb.test(e)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=Bb.test(e)?e.replace(Bb,"$1_="+vb++):e+(wb.test(e)?"&":"?")+"_="+vb++)),k.ifModified&&(m.lastModified[e]&&v.setRequestHeader("If-Modified-Since",m.lastModified[e]),m.etag[e]&&v.setRequestHeader("If-None-Match",m.etag[e])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+Jb+"; q=0.01":""):k.accepts["*"]);for(d in k.headers)v.setRequestHeader(d,k.headers[d]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(d in{success:1,error:1,complete:1})v[d](k[d]);if(i=Mb(Ib,k,b,v)){v.readyState=1,h&&n.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,i.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,c,d){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),i=void 0,f=d||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,c&&(u=Ob(k,v,c)),u=Pb(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(m.lastModified[e]=w),w=v.getResponseHeader("etag"),w&&(m.etag[e]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,h&&n.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),h&&(n.trigger("ajaxComplete",[v,k]),--m.active||m.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return m.get(a,b,c,"json")},getScript:function(a,b){return m.get(a,void 0,b,"script")}}),m.each(["get","post"],function(a,b){m[b]=function(a,c,d,e){return m.isFunction(c)&&(e=e||d,d=c,c=void 0),m.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),m._evalUrl=function(a){return m.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},m.fn.extend({wrapAll:function(a){if(m.isFunction(a))return this.each(function(b){m(this).wrapAll(a.call(this,b))});if(this[0]){var b=m(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return this.each(m.isFunction(a)?function(b){m(this).wrapInner(a.call(this,b))}:function(){var b=m(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=m.isFunction(a);return this.each(function(c){m(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){m.nodeName(this,"body")||m(this).replaceWith(this.childNodes)}).end()}}),m.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0||!k.reliableHiddenOffsets()&&"none"===(a.style&&a.style.display||m.css(a,"display"))},m.expr.filters.visible=function(a){return!m.expr.filters.hidden(a)};var Qb=/%20/g,Rb=/\[\]$/,Sb=/\r?\n/g,Tb=/^(?:submit|button|image|reset|file)$/i,Ub=/^(?:input|select|textarea|keygen)/i;function Vb(a,b,c,d){var e;if(m.isArray(b))m.each(b,function(b,e){c||Rb.test(a)?d(a,e):Vb(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==m.type(b))d(a,b);else for(e in b)Vb(a+"["+e+"]",b[e],c,d)}m.param=function(a,b){var c,d=[],e=function(a,b){b=m.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=m.ajaxSettings&&m.ajaxSettings.traditional),m.isArray(a)||a.jquery&&!m.isPlainObject(a))m.each(a,function(){e(this.name,this.value)});else for(c in a)Vb(c,a[c],b,e);return d.join("&").replace(Qb,"+")},m.fn.extend({serialize:function(){return m.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=m.prop(this,"elements");return a?m.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!m(this).is(":disabled")&&Ub.test(this.nodeName)&&!Tb.test(a)&&(this.checked||!W.test(a))}).map(function(a,b){var c=m(this).val();return null==c?null:m.isArray(c)?m.map(c,function(a){return{name:b.name,value:a.replace(Sb,"\r\n")}}):{name:b.name,value:c.replace(Sb,"\r\n")}}).get()}}),m.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&Zb()||$b()}:Zb;var Wb=0,Xb={},Yb=m.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Xb)Xb[a](void 0,!0)}),k.cors=!!Yb&&"withCredentials"in Yb,Yb=k.ajax=!!Yb,Yb&&m.ajaxTransport(function(a){if(!a.crossDomain||k.cors){var b;return{send:function(c,d){var e,f=a.xhr(),g=++Wb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)void 0!==c[e]&&f.setRequestHeader(e,c[e]+"");f.send(a.hasContent&&a.data||null),b=function(c,e){var h,i,j;if(b&&(e||4===f.readyState))if(delete Xb[g],b=void 0,f.onreadystatechange=m.noop,e)4!==f.readyState&&f.abort();else{j={},h=f.status,"string"==typeof f.responseText&&(j.text=f.responseText);try{i=f.statusText}catch(k){i=""}h||!a.isLocal||a.crossDomain?1223===h&&(h=204):h=j.text?200:404}j&&d(h,i,j,f.getAllResponseHeaders())},a.async?4===f.readyState?setTimeout(b):f.onreadystatechange=Xb[g]=b:b()},abort:function(){b&&b(void 0,!0)}}}});function Zb(){try{return new a.XMLHttpRequest}catch(b){}}function $b(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}m.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return m.globalEval(a),a}}}),m.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),m.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=y.head||m("head")[0]||y.documentElement;return{send:function(d,e){b=y.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||e(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var _b=[],ac=/(=)\?(?=&|$)|\?\?/;m.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=_b.pop()||m.expando+"_"+vb++;return this[a]=!0,a}}),m.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(ac.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&ac.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=m.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(ac,"$1"+e):b.jsonp!==!1&&(b.url+=(wb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||m.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,_b.push(e)),g&&m.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),m.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||y;var d=u.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=m.buildFragment([a],b,e),e&&e.length&&m(e).remove(),m.merge([],d.childNodes))};var bc=m.fn.load;m.fn.load=function(a,b,c){if("string"!=typeof a&&bc)return bc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=m.trim(a.slice(h,a.length)),a=a.slice(0,h)),m.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(f="POST"),g.length>0&&m.ajax({url:a,type:f,dataType:"html",data:b}).done(function(a){e=arguments,g.html(d?m("<div>").append(m.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,e||[a.responseText,b,a])}),this},m.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){m.fn[b]=function(a){return this.on(b,a)}}),m.expr.filters.animated=function(a){return m.grep(m.timers,function(b){return a===b.elem}).length};var cc=a.document.documentElement;function dc(a){return m.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}m.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=m.css(a,"position"),l=m(a),n={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=m.css(a,"top"),i=m.css(a,"left"),j=("absolute"===k||"fixed"===k)&&m.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),m.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(n.top=b.top-h.top+g),null!=b.left&&(n.left=b.left-h.left+e),"using"in b?b.using.call(a,n):l.css(n)}},m.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){m.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,m.contains(b,e)?(typeof e.getBoundingClientRect!==K&&(d=e.getBoundingClientRect()),c=dc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===m.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),m.nodeName(a[0],"html")||(c=a.offset()),c.top+=m.css(a[0],"borderTopWidth",!0),c.left+=m.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-m.css(d,"marginTop",!0),left:b.left-c.left-m.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||cc;while(a&&!m.nodeName(a,"html")&&"static"===m.css(a,"position"))a=a.offsetParent;return a||cc})}}),m.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);m.fn[a]=function(d){return V(this,function(a,d,e){var f=dc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?m(f).scrollLeft():e,c?e:m(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),m.each(["top","left"],function(a,b){m.cssHooks[b]=La(k.pixelPosition,function(a,c){return c?(c=Ja(a,b),Ha.test(c)?m(a).position()[b]+"px":c):void 0})}),m.each({Height:"height",Width:"width"},function(a,b){m.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){m.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return V(this,function(b,c,d){var e;return m.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?m.css(b,c,g):m.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),m.fn.size=function(){return this.length},m.fn.andSelf=m.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return m});var ec=a.jQuery,fc=a.$;return m.noConflict=function(b){return a.$===m&&(a.$=fc),b&&a.jQuery===m&&(a.jQuery=ec),m},typeof b===K&&(a.jQuery=a.$=m),m});
vendor: 5,831 bytes, lines 133-444
133
134
135// Sticky Plugin v1.0.3 for jQuery
136
137// =============
138
139// Author: Anthony Garand
140
141// Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)
142
143// Improvements by Leonardo C. Daronco (daronco)
144
145// Created: 02/14/2011
146
147// Date: 07/20/2015
148
149// Website: http://stickyjs.com/
150
151// Description: Makes an element on the page stick on the screen as you scroll
152
153//              It will only set the 'top' and 'position' of your element, you
154
155//              might need to adjust the width in some cases.
156
157
158
159(function (factory) {
160
161    if (typeof define === 'function' && define.amd) {
162
163        // AMD. Register as an anonymous module.
164
165        define(['jquery'], factory);
166
167    } else if (typeof module === 'object' && module.exports) {
168
169        // Node/CommonJS
170
171        module.exports = factory(require('jquery'));
172
173    } else {
174
175        // Browser globals
176
177        factory(jQuery);
178
179    }
180
181}(function ($) {
182
183    var slice = Array.prototype.slice; // save ref to original slice()
184
185    var splice = Array.prototype.splice; // save ref to original slice()
186
187
188
189  var defaults = {
190
191      topSpacing: 0,
192
193      bottomSpacing: 0,
194
195      className: 'is-sticky',
196
197      wrapperClassName: 'sticky-wrapper',
198
199      center: false,
200
201      getWidthFrom: '',
202
203      widthFromWrapper: true, // works only when .getWidthFrom is empty
204
205      responsiveWidth: false
206
207    },
208
209    $window = $(window),
210
211    $document = $(document),
212
213    sticked = [],
214
215    windowHeight = $window.height(),
216
217    scroller = function() {
218
219      var scrollTop = $window.scrollTop(),
220
221        documentHeight = $document.height(),
222
223        dwh = documentHeight - windowHeight,
224
225        extra = (scrollTop > dwh) ? dwh - scrollTop : 0;
226
227
228
229      for (var i = 0, l = sticked.length; i < l; i++) {
230
231        var s = sticked[i],
232
233          elementTop = s.stickyWrapper.offset().top,
234
235          etse = elementTop - s.topSpacing - extra;
236
237
238
239        //update height in case of dynamic content
240
241        s.stickyWrapper.css('height', s.stickyElement.outerHeight());
242
243
244
245        if (scrollTop <= etse) {
246
247          if (s.currentTop !== null) {
248
249            s.stickyElement
250
251              .css({
252
253                'width': '',
254
255                'position': '',
256
257                'top': ''
258
259              });
260
261            s.stickyElement.parent().removeClass(s.className);
262
263            s.stickyElement.trigger('sticky-end', [s]);
264
265            s.currentTop = null;
266
267          }
268
269        }
270
271        else {
272
273          var newTop = documentHeight - s.stickyElement.outerHeight()
274
275            - s.topSpacing - s.bottomSpacing - scrollTop - extra;
276
277          if (newTop < 0) {
278
279            newTop = newTop + s.topSpacing;
280
281          } else {
282
283            newTop = s.topSpacing;
284
285          }
286
287          if (s.currentTop !== newTop) {
288
289            var newWidth;
290
291            if (s.getWidthFrom) {
292
293                newWidth = $(s.getWidthFrom).width() || null;
294
295            } else if (s.widthFromWrapper) {
296
297                newWidth = s.stickyWrapper.width();
298
299            }
300
301            if (newWidth == null) {
302
303                newWidth = s.stickyElement.width();
304
305            }
306
307            s.stickyElement
308
309              .css('width', newWidth)
310
311              .css('position', 'fixed')
312
313              .css('top', newTop);
314
315
316
317            s.stickyElement.parent().addClass(s.className);
318
319
320
321            if (s.currentTop === null) {
322
323              s.stickyElement.trigger('sticky-start', [s]);
324
325            } else {
326
327              // sticky is started but it have to be repositioned
328
329              s.stickyElement.trigger('sticky-update', [s]);
330
331            }
332
333
334
335            if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) {
336
337              // just reached bottom || just started to stick but bottom is already reached
338
339              s.stickyElement.trigger('sticky-bottom-reached', [s]);
340
341            } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) {
342
343              // sticky is started && sticked at topSpacing && overflowing from top just finished
344
345              s.stickyElement.trigger('sticky-bottom-unreached', [s]);
346
347            }
348
349
350
351            s.currentTop = newTop;
352
353          }
354
355
356
357          // Check if sticky has reached end of container and stop sticking
358
359          var stickyWrapperContainer = s.stickyWrapper.parent();
360
361          var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing);
362
363
364
365          if( unstick ) {
366
367            s.stickyElement
368
369              .css('position', 'absolute')
370
371              .css('top', '')
372
373              .css('bottom', 0);
374
375          } else {
376
377            s.stickyElement
378
379              .css('position', 'fixed')
380
381              .css('top', newTop)
382
383              .css('bottom', '');
384
385          }
386
387        }
388
389      }
390
391    },
392
393    resizer = function() {
394
395      windowHeight = $window.height();
396
397
398
399      for (var i = 0, l = sticked.length; i < l; i++) {
400
401        var s = sticked[i];
402
403        var newWidth = null;
404
405        if (s.getWidthFrom) {
406
407            if (s.responsiveWidth) {
408
409                newWidth = $(s.getWidthFrom).width();
410
411            }
412
413        } else if(s.widthFromWrapper) {
414
415            newWidth = s.stickyWrapper.width();
416
417        }
418
419        if (newWidth != null) {
420
421            s.stickyElement.css('width', newWidth);
422
423        }
424
425      }
426
427    },
428
429    methods = {
430
431      init: function(options) {
432
433        var o = $.extend({}, defaults, options);
434
435        return this.each(function() {
436
437          var stickyElement = $(this);
438
439
440
441          var stickyId = stickyElement.attr('id');
442
443          var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName;
444
445          var wrapper = $('<div></div>')
446
447            .attr('id', wrapperId)
448
449            .addClass(o.wrapperClassName);
450
451
452
453          stickyElement.wrapAll(wrapper);
454
455
456
457          var stickyWrapper = stickyElement.parent();
458
459
460
461          if (o.center) {
462
463            stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"});
464
465          }
466
467
468
469          if (stickyElement.css("float") === "right") {
470
471            stickyElement.css({"float":"none"}).parent().css({"float":"right"});
472
473          }
474
475
476
477          o.stickyElement = stickyElement;
478
479          o.stickyWrapper = stickyWrapper;
480
481          o.currentTop    = null;
482
483
484
485          sticked.push(o);
486
487
488
489          methods.setWrapperHeight(this);
490
491          methods.setupChangeListeners(this);
492
493        });
494
495      },
496
497
498
499      setWrapperHeight: function(stickyElement) {
500
501        var element = $(stickyElement);
502
503        var stickyWrapper = element.parent();
504
505        if (stickyWrapper) {
506
507          stickyWrapper.css('height', element.outerHeight());
508
509        }
510
511      },
512
513
514
515      setupChangeListeners: function(stickyElement) {
516
517        if (window.MutationObserver) {
518
519          var mutationObserver = new window.MutationObserver(function(mutations) {
520
521            if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) {
522
523              methods.setWrapperHeight(stickyElement);
524
525            }
526
527          });
528
529          mutationObserver.observe(stickyElement, {subtree: true, childList: true});
530
531        } else {
532
533          stickyElement.addEventListener('DOMNodeInserted', function() {
534
535            methods.setWrapperHeight(stickyElement);
536
537          }, false);
538
539          stickyElement.addEventListener('DOMNodeRemoved', function() {
540
541            methods.setWrapperHeight(stickyElement);
542
543          }, false);
544
545        }
546
547      },
548
549      update: scroller,
550
551      unstick: function(options) {
552
553        return this.each(function() {
554
555          var that = this;
556
557          var unstickyElement = $(that);
558
559
560
561          var removeIdx = -1;
562
563          var i = sticked.length;
564
565          while (i-- > 0) {
566
567            if (sticked[i].stickyElement.get(0) === that) {
568
569                splice.call(sticked,i,1);
570
571                removeIdx = i;
572
573            }
574
575          }
576
577          if(removeIdx !== -1) {
578
579            unstickyElement.unwrap();
580
581            unstickyElement
582
583              .css({
584
585                'width': '',
586
587                'position': '',
588
589                'top': '',
590
591                'float': ''
592
593              })
594
595            ;
596
597          }
598
599        });
600
601      }
602
603    };
604
605
606
607  // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):
608
609  if (window.addEventListener) {
610
611    window.addEventListener('scroll', scroller, false);
612
613    window.addEventListener('resize', resizer, false);
614
615  } else if (window.attachEvent) {
616
617    window.attachEvent('onscroll', scroller);
618
619    window.attachEvent('onresize', resizer);
620
621  }
622
623
624
625  $.fn.sticky = function(method) {
626
627    if (methods[method]) {
628
629      return methods[method].apply(this, slice.call(arguments, 1));
630
631    } else if (typeof method === 'object' || !method ) {
632
633      return methods.init.apply( this, arguments );
634
635    } else {
636
637      $.error('Method ' + method + ' does not exist on jQuery.sticky');
638
639    }
640
641  };
642
643
644
645  $.fn.unstick = function(method) {
646
647    if (methods[method]) {
648
649      return methods[method].apply(this, slice.call(arguments, 1));
650
651    } else if (typeof method === 'object' || !method ) {
652
653      return methods.unstick.apply( this, arguments );
654
655    } else {
656
657      $.error('Method ' + method + ' does not exist on jQuery.sticky');
658
659    }
660
661  };
662
663  $(function() {
664
665    setTimeout(scroller, 0);
666
667  });
668
669}));
670
671
672/*!
673
674 * Modernizr v2.8.3
675
676 * www.modernizr.com
677
678 *
679
680 * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
681
682 * Available under the BSD and MIT licenses: www.modernizr.com/license/
683
684 */
685
686window.Modernizr=function(a,b,c){function d(a){t.cssText=a}function e(a,b){return d(x.join(a+";")+(b||""))}function f(a,b){return typeof a===b}function g(a,b){return!!~(""+a).indexOf(b)}function h(a,b){for(var d in a){var e=a[d];if(!g(e,"-")&&t[e]!==c)return"pfx"==b?e:!0}return!1}function i(a,b,d){for(var e in a){var g=b[a[e]];if(g!==c)return d===!1?a[e]:f(g,"function")?g.bind(d||b):g}return!1}function j(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+z.join(d+" ")+d).split(" ");return f(b,"string")||f(b,"undefined")?h(e,b):(e=(a+" "+A.join(d+" ")+d).split(" "),i(e,b,c))}function k(){o.input=function(c){for(var d=0,e=c.length;e>d;d++)E[c[d]]=!!(c[d]in u);return E.list&&(E.list=!(!b.createElement("datalist")||!a.HTMLDataListElement)),E}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" ")),o.inputtypes=function(a){for(var d,e,f,g=0,h=a.length;h>g;g++)u.setAttribute("type",e=a[g]),d="text"!==u.type,d&&(u.value=v,u.style.cssText="position:absolute;visibility:hidden;",/^range$/.test(e)&&u.style.WebkitAppearance!==c?(q.appendChild(u),f=b.defaultView,d=f.getComputedStyle&&"textfield"!==f.getComputedStyle(u,null).WebkitAppearance&&0!==u.offsetHeight,q.removeChild(u)):/^(search|tel)$/.test(e)||(d=/^(url|email)$/.test(e)?u.checkValidity&&u.checkValidity()===!1:u.value!=v)),D[a[g]]=!!d;return D}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var l,m,n="2.8.3",o={},p=!0,q=b.documentElement,r="modernizr",s=b.createElement(r),t=s.style,u=b.createElement("input"),v=":)",w={}.toString,x=" -webkit- -moz- -o- -ms- ".split(" "),y="Webkit Moz O ms",z=y.split(" "),A=y.toLowerCase().split(" "),B={svg:"http://www.w3.org/2000/svg"},C={},D={},E={},F=[],G=F.slice,H=function(a,c,d,e){var f,g,h,i,j=b.createElement("div"),k=b.body,l=k||b.createElement("body");if(parseInt(d,10))for(;d--;)h=b.createElement("div"),h.id=e?e[d]:r+(d+1),j.appendChild(h);return f=["&#173;",'<style id="s',r,'">',a,"</style>"].join(""),j.id=r,(k?j:l).innerHTML+=f,l.appendChild(j),k||(l.style.background="",l.style.overflow="hidden",i=q.style.overflow,q.style.overflow="hidden",q.appendChild(l)),g=c(j,a),k?j.parentNode.removeChild(j):(l.parentNode.removeChild(l),q.style.overflow=i),!!g},I=function(b){var c=a.matchMedia||a.msMatchMedia;
vendor: 9,226 bytes, lines 686-699
686if(c)return c(b)&&c(b).matches||!1;var d;return H("@media "+b+" { #"+r+" { position: absolute; } }",function(b){d="absolute"==(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle).position}),d},J=function(){function a(a,e){e=e||b.createElement(d[a]||"div"),a="on"+a;var g=a in e;return g||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(a,""),g=f(e[a],"function"),f(e[a],"undefined")||(e[a]=c),e.removeAttribute(a))),e=null,g}var d={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return a}(),K={}.hasOwnProperty;m=f(K,"undefined")||f(K.call,"undefined")?function(a,b){return b in a&&f(a.constructor.prototype[b],"undefined")}:function(a,b){return K.call(a,b)},Function.prototype.bind||(Function.prototype.bind=function(a){var b=this;if("function"!=typeof b)throw new TypeError;var c=G.call(arguments,1),d=function(){if(this instanceof d){var e=function(){};e.prototype=b.prototype;var f=new e,g=b.apply(f,c.concat(G.call(arguments)));return Object(g)===g?g:f}return b.apply(a,c.concat(G.call(arguments)))};return d}),C.flexbox=function(){return j("flexWrap")},C.flexboxlegacy=function(){return j("boxDirection")},C.canvas=function(){var a=b.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))},C.canvastext=function(){return!(!o.canvas||!f(b.createElement("canvas").getContext("2d").fillText,"function"))},C.webgl=function(){return!!a.WebGLRenderingContext},C.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:H(["@media (",x.join("touch-enabled),("),r,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=9===a.offsetTop}),c},C.geolocation=function(){return"geolocation"in navigator},C.postmessage=function(){return!!a.postMessage},C.websqldatabase=function(){return!!a.openDatabase},C.indexedDB=function(){return!!j("indexedDB",a)},C.hashchange=function(){return J("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},C.history=function(){return!(!a.history||!history.pushState)},C.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},C.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},C.rgba=function(){return d("background-color:rgba(150,255,150,.5)"),g(t.backgroundColor,"rgba")},C.hsla=function(){return d("background-color:hsla(120,40%,100%,.5)"),g(t.backgroundColor,"rgba")||g(t.backgroundColor,"hsla")},C.multiplebgs=function(){return d("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(t.background)},C.backgroundsize=function(){return j("backgroundSize")},C.borderimage=function(){return j("borderImage")},C.borderradius=function(){return j("borderRadius")},C.boxshadow=function(){return j("boxShadow")},C.textshadow=function(){return""===b.createElement("div").style.textShadow},C.opacity=function(){return e("opacity:.55"),/^0.55$/.test(t.opacity)},C.cssanimations=function(){return j("animationName")},C.csscolumns=function(){return j("columnCount")},C.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return d((a+"-webkit- ".split(" ").join(b+a)+x.join(c+a)).slice(0,-a.length)),g(t.backgroundImage,"gradient")},C.cssreflections=function(){return j("boxReflect")},C.csstransforms=function(){return!!j("transform")},C.csstransforms3d=function(){var a=!!j("perspective");return a&&"webkitPerspective"in q.style&&H("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=9===b.offsetLeft&&3===b.offsetHeight}),a},C.csstransitions=function(){return j("transition")},C.fontface=function(){var a;return H('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&0===g.indexOf(d.split(" ")[0])}),a},C.generatedcontent=function(){var a;return H(["#",r,"{font:0/0 a}#",r,':after{content:"',v,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},C.video=function(){var a=b.createElement("video"),c=!1;try{(c=!!a.canPlayType)&&(c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,""))}catch(d){}return c},C.audio=function(){var a=b.createElement("audio"),c=!1;try{(c=!!a.canPlayType)&&(c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,""))}catch(d){}return c},C.localstorage=function(){try{return localStorage.setItem(r,r),localStorage.removeItem(r),!0}catch(a){return!1}},C.sessionstorage=function(){try{return sessionStorage.setItem(r,r),sessionStorage.removeItem(r),!0}catch(a){return!1}},C.webworkers=function(){return!!a.Worker},C.applicationcache=function(){return!!a.applicationCache},C.svg=function(){return!!b.createElementNS&&!!b.createElementNS(B.svg,"svg").createSVGRect},C.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="<svg/>",(a.firstChild&&a.firstChild.namespaceURI)==B.svg},C.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(w.call(b.createElementNS(B.svg,"animate")))},C.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(w.call(b.createElementNS(B.svg,"clipPath")))};for(var L in C)m(C,L)&&(l=L.toLowerCase(),o[l]=C[L](),F.push((o[l]?"":"no-")+l));return o.input||k(),o.addTest=function(a,b){if("object"==typeof a)for(var d in a)m(a,d)&&o.addTest(d,a[d]);else{if(a=a.toLowerCase(),o[a]!==c)return o;b="function"==typeof b?b():b,"undefined"!=typeof p&&p&&(q.className+=" "+(b?"":"no-")+a),o[a]=b}return o},d(""),s=u=null,function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=s.elements;return"string"==typeof a?a.split(" "):a}function e(a){var b=r[a[p]];return b||(b={},q++,a[p]=q,r[q]=b),b}function f(a,c,d){if(c||(c=b),k)return c.createElement(a);d||(d=e(c));var f;return f=d.cache[a]?d.cache[a].cloneNode():o.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!f.canHaveChildren||n.test(a)||f.tagUrn?f:d.frag.appendChild(f)}function g(a,c){if(a||(a=b),k)return a.createDocumentFragment();c=c||e(a);for(var f=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)f.createElement(h[g]);return f}function h(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return s.shivMethods?f(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(s,b.frag)}function i(a){a||(a=b);var d=e(a);return!s.shivCSS||j||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),k||h(a,d),a}var j,k,l="3.7.0",m=a.html5||{},n=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,o=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,p="_html5shiv",q=0,r={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",j="hidden"in a,k=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){j=!0,k=!0}}();var s={elements:m.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:l,shivCSS:m.shivCSS!==!1,supportsUnknownElements:k,shivMethods:m.shivMethods!==!1,type:"default",shivDocument:i,createElement:f,createDocumentFragment:g};a.html5=s,i(b)}(this,b),o._version=n,o._prefixes=x,o._domPrefixes=A,o._cssomPrefixes=z,o.mq=I,o.hasEvent=J,o.testProp=function(a){return h([a])},o.testAllProps=j,o.testStyles=H,o.prefixed=function(a,b,c){return b?j(a,b,c):j(a,"pfx")},q.className=q.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(p?" js "+F.join(" "):""),o}(this,this.document);
687
688
689//! moment.js
690
691//! version : 2.9.0
692
693//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
694
695//! license : MIT
696
697//! momentjs.com
698
699(function(a){function b(a,b,c){switch(arguments.length){case 2:return null!=a?a:b;case 3:return null!=a?a:null!=b?b:c;default:throw new Error("Implement me")}}function c(a,b){return Bb.call(a,b)}function d(){return{empty:!1,unusedTokens:[],unusedInput:[],overflow:-2,charsLeftOver:0,nullInput:!1,invalidMonth:null,invali
699dFormat:!1,userInvalidated:!1,iso:!1}}function e(a){vb.suppressDeprecationWarnings===!1&&"undefined"!=typeof console&&console.warn&&console.warn("Deprecation warning: "+a)}function f(a,b){var c=!0;return o(function(){return c&&(e(a),c=!1),b.apply(this,arguments)},b)}function g(a,b){sc[a]||(e(b),sc[a]=!0)}function h(a,b){return function(c){return r(a.call(this,c),b)}}function i(a,b){return function(c){return this.localeData().ordinal(a.call(this,c),b)}}function j(a,b){var c,d,e=12*(b.year()-a.year())+(b.month()-a.month()),f=a.clone().add(e,"months");return 0>b-f?(c=a.clone().add(e-1,"months"),d=(b-f)/(f-c)):(c=a.clone().add(e+1,"months"),d=(b-f)/(c-f)),-(e+d)}function k(a,b,c){var d;return null==c?b:null!=a.meridiemHour?a.meridiemHour(b,c):null!=a.isPM?(d=a.isPM(c),d&&12>b&&(b+=12),d||12!==b||(b=0),b):b}function l(){}function m(a,b){b!==!1&&H(a),p(this,a),this._d=new Date(+a._d),uc===!1&&(uc=!0,vb.updateOffset(this),uc=!1)}function n(a){var b=A(a),c=b.year||0,d=b.quarter||0,e=b.month||0,f=b.week||0,g=b.day||0,h=b.hour||0,i=b.minute||0,j=b.second||0,k=b.millisecond||0;this._milliseconds=+k+1e3*j+6e4*i+36e5*h,this._days=+g+7*f,this._months=+e+3*d+12*c,this._data={},this._locale=vb.localeData(),this._bubble()}function o(a,b){for(var d in b)c(b,d)&&(a[d]=b[d]);return c(b,"toString")&&(a.toString=b.toString),c(b,"valueOf")&&(a.valueOf=b.valueOf),a}function p(a,b){var c,d,e;if("undefined"!=typeof b._isAMomentObject&&(a._isAMomentObject=b._isAMomentObject),"undefined"!=typeof b._i&&(a._i=b._i),"undefined"!=typeof b._f&&(a._f=b._f),"undefined"!=typeof b._l&&(a._l=b._l),"undefined"!=typeof b._strict&&(a._strict=b._strict),"undefined"!=typeof b._tzm&&(a._tzm=b._tzm),"undefined"!=typeof b._isUTC&&(a._isUTC=b._isUTC),"undefined"!=typeof b._offset&&(a._offset=b._offset),"undefined"!=typeof b._pf&&(a._pf=b._pf),"undefined"!=typeof b._locale&&(a._locale=b._locale),Kb.length>0)for(c in Kb)d=Kb[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function q(a){return 0>a?Math.ceil(a):Math.floor(a)}function r(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.length<b;)d="0"+d;return(e?c?"+":"":"-")+d}function s(a,b){var c={milliseconds:0,months:0};return c.months=b.month()-a.month()+12*(b.year()-a.year()),a.clone().add(c.months,"M").isAfter(b)&&--c.months,c.milliseconds=+b-+a.clone().add(c.months,"M"),c}function t(a,b){var c;return b=M(b,a),a.isBefore(b)?c=s(a,b):(c=s(b,a),c.milliseconds=-c.milliseconds,c.months=-c.months),c}function u(a,b){return function(c,d){var e,f;return null===d||isNaN(+d)||(g(b,"moment()."+b+"(period, number) is deprecated. Please use moment()."+b+"(number, period)."),f=c,c=d,d=f),c="string"==typeof c?+c:c,e=vb.duration(c,d),v(this,e,a),this}}function v(a,b,c,d){var e=b._milliseconds,f=b._days,g=b._months;d=null==d?!0:d,e&&a._d.setTime(+a._d+e*c),f&&pb(a,"Date",ob(a,"Date")+f*c),g&&nb(a,ob(a,"Month")+g*c),d&&vb.updateOffset(a,f||g)}function w(a){return"[object Array]"===Object.prototype.toString.call(a)}function x(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function y(a,b,c){var d,e=Math.min(a.length,b.length),f=Math.abs(a.length-b.length),g=0;for(d=0;e>d;d++)(c&&a[d]!==b[d]||!c&&C(a[d])!==C(b[d]))&&g++;return g+f}function z(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=lc[a]||mc[b]||b}return a}function A(a){var b,d,e={};for(d in a)c(a,d)&&(b=z(d),b&&(e[b]=a[d]));return e}function B(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}vb[b]=function(e,f){var g,h,i=vb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=vb().utc().set(d,a);return i.call(vb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function C(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function D(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function E(a,b,c){return jb(vb([a,11,31+b-c]),b,c).week}function F(a){return G(a)?366:365}function G(a){return a%4===0&&a%100!==0||a%400===0}function H(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[Db]<0||a._a[Db]>11?Db:a._a[Eb]<1||a._a[Eb]>D(a._a[Cb],a._a[Db])?Eb:a._a[Fb]<0||a._a[Fb]>24||24===a._a[Fb]&&(0!==a._a[Gb]||0!==a._a[Hb]||0!==a._a[Ib])?Fb:a._a[Gb]<0||a._a[Gb]>59?Gb:a._a[Hb]<0||a._a[Hb]>59?Hb:a._a[Ib]<0||a._a[Ib]>999?Ib:-1,a._pf._overflowDayOfYear&&(Cb>b||b>Eb)&&(b=Eb),a._pf.overflow=b)}
699function I(b){return null==b._isValid&&(b._isValid=!isNaN(b._d.getTime())&&b._pf.overflow<0&&!b._pf.empty&&!b._pf.invalidMonth&&!b._pf.nullInput&&!b._pf.invalidFormat&&!b._pf.userInvalidated,b._strict&&(b._isValid=b._isValid&&0===b._pf.charsLeftOver&&0===b._pf.unusedTokens.length&&b._pf.bigHour===a)),b._isValid}function J(a){return a?a.toLowerCase().replace("_","-"):a}function K(a){for(var b,c,d,e,f=0;f<a.length;){for(e=J(a[f]).split("-"),b=e.length,c=J(a[f+1]),c=c?c.split("-"):null;b>0;){if(d=L(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&y(e,c,!0)>=b-1)break;b--}f++}return null}function L(a){var b=null;if(!Jb[a]&&Lb)try{b=vb.locale(),require("./locale/"+a),vb.locale(b)}catch(c){}return Jb[a]}function M(a,b){var c,d;return b._isUTC?(c=b.clone(),d=(vb.isMoment(a)||x(a)?+a:+vb(a))-+c,c._d.setTime(+c._d+d),vb.updateOffset(c,!1),c):vb(a).local()}function N(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function O(a){var b,c,d=a.match(Pb);for(b=0,c=d.length;c>b;b++)d[b]=rc[d[b]]?rc[d[b]]:N(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function P(a,b){return a.isValid()?(b=Q(b,a.localeData()),nc[b]||(nc[b]=O(b)),nc[b](a)):a.localeData().invalidDate()}function Q(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Qb.lastIndex=0;d>=0&&Qb.test(a);)a=a.replace(Qb,c),Qb.lastIndex=0,d-=1;return a}function R(a,b){var c,d=b._strict;switch(a){case"Q":return _b;case"DDDD":return bc;case"YYYY":case"GGGG":case"gggg":return d?cc:Tb;case"Y":case"G":case"g":return ec;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?dc:Ub;case"S":if(d)return _b;case"SS":if(d)return ac;case"SSS":if(d)return bc;case"DDD":return Sb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Wb;case"a":case"A":return b._locale._meridiemParse;case"x":return Zb;case"X":return $b;case"Z":case"ZZ":return Xb;case"T":return Yb;case"SSSS":return Vb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?ac:Rb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Rb;case"Do":return d?b._locale._ordinalParse:b._locale._ordinalParseLenient;default:return c=new RegExp($(Z(a.replace("\\","")),"i"))}}function S(a){a=a||"";var b=a.match(Xb)||[],c=b[b.length-1]||[],d=(c+"").match(jc)||["-",0,0],e=+(60*d[1])+C(d[2]);return"+"===d[0]?e:-e}function T(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[Db]=3*(C(b)-1));break;case"M":case"MM":null!=b&&(e[Db]=C(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b,a,c._strict),null!=d?e[Db]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[Eb]=C(b));break;case"Do":null!=b&&(e[Eb]=C(parseInt(b.match(/\d{1,2}/)[0],10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=C(b));break;case"YY":e[Cb]=vb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[Cb]=C(b);break;case"a":case"A":c._meridiem=b;break;case"h":case"hh":c._pf.bigHour=!0;case"H":case"HH":e[Fb]=C(b);break;case"m":case"mm":e[Gb]=C(b);break;case"s":case"ss":e[Hb]=C(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Ib]=C(1e3*("0."+b));break;case"x":c._d=new Date(C(b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=S(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=C(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=vb.parseTwoDigitYear(b)}}function U(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[Cb],jb(vb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[Cb],jb(vb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=kb(d,e,f,h,g),a._a[Cb]=i.year,a._dayOfYear=i.dayOfYear}function V(a){var c,d,e,f,g=[];if(!a._d){for(e=X(a),a._w&&null==a._a[Eb]&&null==a._a[Db]&&U(a),a._dayOfYear&&(f=b(a._a[Cb],e[Cb]),a._dayOfYear>F(f)&&(a._pf._overflowDayOfYear=!0),d=fb(f,0,a._dayOfYear),a._a[Db]=d.getUTCMonth(),a._a[Eb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];24===a._a[Fb]&&0===a._a[Gb]&&0===a._a[Hb]&&0===a._a[Ib]&&(a._nextDay=!0,a._a[Fb]=0),a._d=(a._useUTC?fb:eb).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()-a._tzm),a._nextDay&&(a._a[Fb]=24)}}function W(a){var b;a._d||(b=A(a._i),a._a=[b.year,b.month,b.day||b.date,b.hour,b.minute,b.second,b.millisecond],V(a))}function X(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function Y(b){if(b._f===vb.ISO_8601)return void ab(b);b._a=[],b._pf.empty=!0;var c,d,e,f,g,h=""+b._i,i=h.length,j=0;for(e=Q(b._f,b._locale).match(Pb)||[],c=0;c<e.length;c++)f=e[c],d=(h.match(R(f,b))||[])[0],d&&(g=h.substr(0,h.indexOf(d)),g.length>0&&b._pf.unusedInput.push(g),h=h.slice(h.indexOf(d)+d.length),j+=d.length),rc[f]?(d?b._pf.empty=!1:b._pf.unusedTokens.push(f),T(f,d,b)):b._strict&&!d&&b._pf.unusedTokens.push(f);b._pf.charsLeftOver=i-j,h.length>0&&b._pf.unusedInput.push(h),b._pf.bigHour===!0&&b._a[Fb]<=12&&(b._pf.bigHour=a),b._a[Fb]=k(b._locale,b._a[Fb],b._meridiem),V(b),H(b)}function Z(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function $(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function _(a){var b,c,e,f,g;
699if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;f<a._f.length;f++)g=0,b=p({},a),null!=a._useUTC&&(b._useUTC=a._useUTC),b._pf=d(),b._f=a._f[f],Y(b),I(b)&&(g+=b._pf.charsLeftOver,g+=10*b._pf.unusedTokens.length,b._pf.score=g,(null==e||e>g)&&(e=g,c=b));o(a,c||b)}function ab(a){var b,c,d=a._i,e=fc.exec(d);if(e){for(a._pf.iso=!0,b=0,c=hc.length;c>b;b++)if(hc[b][1].exec(d)){a._f=hc[b][0]+(e[6]||" ");break}for(b=0,c=ic.length;c>b;b++)if(ic[b][1].exec(d)){a._f+=ic[b][0];break}d.match(Xb)&&(a._f+="Z"),Y(a)}else a._isValid=!1}function bb(a){ab(a),a._isValid===!1&&(delete a._isValid,vb.createFromInputFallback(a))}function cb(a,b){var c,d=[];for(c=0;c<a.length;++c)d.push(b(a[c],c));return d}function db(b){var c,d=b._i;d===a?b._d=new Date:x(d)?b._d=new Date(+d):null!==(c=Mb.exec(d))?b._d=new Date(+c[1]):"string"==typeof d?bb(b):w(d)?(b._a=cb(d.slice(0),function(a){return parseInt(a,10)}),V(b)):"object"==typeof d?W(b):"number"==typeof d?b._d=new Date(d):vb.createFromInputFallback(b)}function eb(a,b,c,d,e,f,g){var h=new Date(a,b,c,d,e,f,g);return 1970>a&&h.setFullYear(a),h}function fb(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function gb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function hb(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function ib(a,b,c){var d=vb.duration(a).abs(),e=Ab(d.as("s")),f=Ab(d.as("m")),g=Ab(d.as("h")),h=Ab(d.as("d")),i=Ab(d.as("M")),j=Ab(d.as("y")),k=e<oc.s&&["s",e]||1===f&&["m"]||f<oc.m&&["mm",f]||1===g&&["h"]||g<oc.h&&["hh",g]||1===h&&["d"]||h<oc.d&&["dd",h]||1===i&&["M"]||i<oc.M&&["MM",i]||1===j&&["y"]||["yy",j];return k[2]=b,k[3]=+a>0,k[4]=c,hb.apply({},k)}function jb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=vb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function kb(a,b,c,d,e){var f,g,h=fb(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:F(a-1)+g}}function lb(b){var c,d=b._i,e=b._f;return b._locale=b._locale||vb.localeData(b._l),null===d||e===a&&""===d?vb.invalid({nullInput:!0}):("string"==typeof d&&(b._i=d=b._locale.preparse(d)),vb.isMoment(d)?new m(d,!0):(e?w(e)?_(b):Y(b):db(b),c=new m(b),c._nextDay&&(c.add(1,"d"),c._nextDay=a),c))}function mb(a,b){var c,d;if(1===b.length&&w(b[0])&&(b=b[0]),!b.length)return vb();for(c=b[0],d=1;d<b.length;++d)b[d][a](c)&&(c=b[d]);return c}function nb(a,b){var c;return"string"==typeof b&&(b=a.localeData().monthsParse(b),"number"!=typeof b)?a:(c=Math.min(a.date(),D(a.year(),b)),a._d["set"+(a._isUTC?"UTC":"")+"Month"](b,c),a)}function ob(a,b){return a._d["get"+(a._isUTC?"UTC":"")+b]()}function pb(a,b,c){return"Month"===b?nb(a,c):a._d["set"+(a._isUTC?"UTC":"")+b](c)}function qb(a,b){return function(c){return null!=c?(pb(this,a,c),vb.updateOffset(this,b),this):ob(this,a)}}function rb(a){return 400*a/146097}function sb(a){return 146097*a/400}function tb(a){vb.duration.fn[a]=function(){return this._data[a]}}function ub(a){"undefined"==typeof ender&&(wb=zb.moment,zb.moment=a?f("Accessing Moment through the global scope is deprecated, and will be removed in an upcoming release.",vb):vb)}for(var vb,wb,xb,yb="2.9.0",zb="undefined"==typeof global||"undefined"!=typeof window&&window!==global.window?this:global,Ab=Math.round,Bb=Object.prototype.hasOwnProperty,Cb=0,Db=1,Eb=2,Fb=3,Gb=4,Hb=5,Ib=6,Jb={},Kb=[],Lb="undefined"!=typeof module&&module&&module.exports,Mb=/^\/?Date\((\-?\d+)/i,Nb=/(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,Ob=/^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,Pb=/(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,Qb=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,Rb=/\d\d?/,Sb=/\d{1,3}/,Tb=/\d{1,4}/,Ub=/[+\-]?\d{1,6}/,Vb=/\d+/,Wb=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,Xb=/Z|[\+\-]\d\d:?\d\d/gi,Yb=/T/i,Zb=/[\+\-]?\d+/,$b=/[\+\-]?\d+(\.\d{1,3})?/,_b=/\d/,ac=/\d\d/,bc=/\d{3}/,cc=/\d{4}/,dc=/[+-]?\d{6}/,ec=/[+-]?\d+/,fc=/^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,gc="YYYY-MM-DDTHH:mm:ssZ",hc=[["YYYYYY-MM-DD",/[+-]\d{6}-\d{2}-\d{2}/],["YYYY-MM-DD",/\d{4}-\d{2}-\d{2}/],["GGGG-[W]WW-E",/\d{4}-W\d{2}-\d/],["GGGG-[W]WW",/\d{4}-W\d{2}/],["YYYY-DDD",/\d{4}-\d{3}/]],ic=[["HH:mm:ss.SSSS",/(T| )\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss",/(T| )\d\d:\d\d:\d\d/],["HH:mm",/(T| )\d\d:\d\d/],["HH",/(T| )\d\d/]],jc=/([\+\-]|\d\d)/gi,kc=("Date|Hours|Minutes|Seconds|Milliseconds".split("|"),{Milliseconds:1,Seconds:1e3,Minutes:6e4,Hours:36e5,Days:864e5,Months:2592e6,Years:31536e6}),lc={ms:"millisecond",s:"second",m:"minute",h:"hour",d:"day",D:"date",w:"week",W:"isoWeek",M:"month",Q:"quarter",y:"year",DDD:"dayOfYear",e:"weekday",E:"isoWeekday",gg:"weekYear",GG:"isoWeekYear"},mc={dayofyear:"dayOfYear",isoweekday:"isoWeekday",isoweek:"isoWeek",weekyear:"weekYear",isoweekyear:"isoWeekYear"},nc={},oc={s:45,m:45,h:22,d:26,M:11},pc="DDD w W M D d".split(" "),qc="M D H h m s w W".split(" "),rc={M:function(){return this.month()+1},MMM:function(a){return this.localeData().monthsShort(this,a)},MMMM:function(a){return this.localeData().months(this,a)},D:function(){return this.date()},DDD:function(){return this.dayOfYear()},d:function(){return this.day()},dd:function(a){return this.localeData().weekdaysMin(this,a)},ddd:function(a){return this.localeData().weekdaysShort(this,a)},dddd:function(a){return this.localeData().weekdays(this,a)},w:function(){return this.week()},W:function(){return this.isoWeek()},YY:function(){return r(this.year()%100,2)},YYYY:function(){return r(this.year(),4)},YYYYY:function(){return r(this.year(),5)},YYYYYY:function(){var a=this.year(),b=a>=0?"+":"-";return b+r(Math.abs(a),6)},gg:function(){return r(this.weekYear()%100,2)},gggg:function(){return r(this.weekYear(),4)},ggggg:function(){return r(this.weekYear(),5)},GG:function(){return r(this.isoWeekYear()%100,2)},GGGG:function(){return r(this.isoWeekYear(),4)},GGGGG:function(){return r(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return C(this.milliseconds()/100)},SS:function(){return r(C(this.milliseconds()/10),2)},SSS:function(){return r(this.milliseconds(),3)},SSSS:function(){return r(this.milliseconds(),3)},Z:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+":"+r(C(a)%60,2)},ZZ:function(){var a=this.utcOffset(),b="+";return 0>a&&(a=-a,b="-"),b+r(C(a/60),2)+r(C(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},x:function(){return this.valueOf()},X:function(){return this.unix()},Q:function(){return this.quarter()}},sc={},tc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"],uc=!1;pc.length;)xb=pc.pop(),rc[xb+"o"]=i(rc[xb],xb);for(;qc.length;)xb=qc.pop(),rc[xb+xb]=h(rc[xb],2);rc.DDDD=h(rc.DDD,3),o(l.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b;this._ordinalParseLenient=new RegExp(this._ordinalParse.source+"|"+/\d{1,2}/.source)},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a,b,c){var d,e,f;for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),d=0;12>d;d++){if(e=vb.utc([2e3,d]),c&&!this._longMonthsParse[d]&&(this._longMonthsParse[d]=new RegExp("^"+this.months(e,"").replace(".","")+"$","i"),this._shortMonthsParse[d]=new RegExp("^"+this.monthsShort(e,"").replace(".","")+"$","i")),c||this._monthsParse[d]||(f="^"+this.months(e,"")+"|^"+this.monthsShort(e,""),this._monthsParse[d]=new RegExp(f.replace(".",""),"i")),c&&"MMMM"===b&&this._longMonthsParse[d].test(a))return d;if(c&&"MMM"===b&&this._shortMonthsParse[d].test(a))return d;if(!c&&this._monthsParse[d].test(a))return d}},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=vb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b,c){var d=this._calendar[a];return"function"==typeof d?d.apply(b,[c]):d},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",_ordinalParse:/\d{1,2}/,preparse:function(a){return a},postformat:function(a){return a},week:function(a){return jb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},firstDayOfWeek:function(){return this._week.dow},firstDayOfYear:function(){return this._week.doy},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),vb=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=c,g._l=e,g._strict=f,g._isUTC=!1,g._pf=d(),lb(g)},vb.suppressDeprecationWarnings=!1,vb.createFromInputFallback=f("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i+(a._useUTC?" UTC":""))}),vb.min=function(){var a=[].slice.call(arguments,0);return mb("isBefore",a)},vb.max=function(){var a=[].slice.call(arguments,0);return mb("isAfter",a)},vb.utc=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=c,g._strict=f,g._pf=d(),lb(g).utc()},vb.unix=function(a){return vb(1e3*a)},vb.duration=function(a,b){var d,e,f,g,h=a,i=null;return vb.isDuration(a)?h={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(h={},b?h[b]=a:h.milliseconds=a):(i=Nb.exec(a))?(d="-"===i[1]?-1:1,h={y:0,d:C(i[Eb])*d,h:C(i[Fb])*d,m:C(i[Gb])*d,s:C(i[Hb])*d,ms:C(i[Ib])*d}):(i=Ob.exec(a))?(d="-"===i[1]?-1:1,f=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*d},h={y:f(i[2]),M:f(i[3]),d:f(i[4]),h:f(i[5]),m:f(i[6]),s:f(i[7]),w:f(i[8])}):null==h?h={}:"object"==typeof h&&("from"in h||"to"in h)&&(g=t(vb(h.from),vb(h.to)),h={},h.ms=g.milliseconds,h.M=g.months),e=new n(h),vb.isDuration(a)&&c(a,"_locale")&&(e._locale=a._locale),e},vb.version=yb,vb.defaultFormat=gc,vb.ISO_8601=function(){},vb.momentProperties=Kb,vb.updateOffset=function(){},vb.relativeTimeThreshold=function(b,c){return oc[b]===a?!1:c===a?oc[b]:(oc[b]=c,!0)},vb.lang=f("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return vb.locale(a,b)}),vb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?vb.defineLocale(a,b):vb.localeData(a),c&&(vb.duration._locale=vb._locale=c)),vb._locale._abbr},vb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Jb[a]||(Jb[a]=new l),Jb[a].set(b),vb.locale(a),Jb[a]):(delete Jb[a],null)},vb.langData=f("moment.langData is deprecated. Use moment.localeData instead.",function(a){return vb.localeData(a)}),vb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return vb._locale;if(!w(a)){if(b=L(a))return b;a=[a]}return K(a)},vb.isMoment=function(a){return a instanceof m||null!=a&&c(a,"_isAMomentObject")},vb.isDuration=function(a){return a instanceof n};for(xb=tc.length-1;xb>=0;--xb)B(tc[xb]);vb.normalizeUnits=function(a){return z(a)},vb.invalid=function(a){var b=vb.utc(0/0);return null!=a?o(b._pf,a):b._pf.userInvalidated=!0,b},vb.parseZone=function(){return vb.apply(null,arguments).parseZone()},vb.parseTwoDigitYear=function(a){return C(a)+(C(a)>68?1900:2e3)},vb.isDate=x,o(vb.fn=m.prototype,{clone:function(){return vb(this)}
699,valueOf:function(){return+this._d-6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=vb(this).utc();return 0<a.year()&&a.year()<=9999?"function"==typeof Date.prototype.toISOString?this.toDate().toISOString():P(a,"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]"):P(a,"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]")},toArray:function(){var a=this;return[a.year(),a.month(),a.date(),a.hours(),a.minutes(),a.seconds(),a.milliseconds()]},isValid:function(){return I(this)},isDSTShifted:function(){return this._a?this.isValid()&&y(this._a,(this._isUTC?vb.utc(this._a):vb(this._a)).toArray())>0:!1},parsingFlags:function(){return o({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.utcOffset(0,a)},local:function(a){return this._isUTC&&(this.utcOffset(0,a),this._isUTC=!1,a&&this.subtract(this._dateUtcOffset(),"m")),this},format:function(a){var b=P(this,a||vb.defaultFormat);return this.localeData().postformat(b)},add:u(1,"add"),subtract:u(-1,"subtract"),diff:function(a,b,c){var d,e,f=M(a,this),g=6e4*(f.utcOffset()-this.utcOffset());return b=z(b),"year"===b||"month"===b||"quarter"===b?(e=j(this,f),"quarter"===b?e/=3:"year"===b&&(e/=12)):(d=this-f,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-g)/864e5:"week"===b?(d-g)/6048e5:d),c?e:q(e)},from:function(a,b){return vb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(vb(),a)},calendar:function(a){var b=a||vb(),c=M(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this,vb(b)))},isLeapYear:function(){return G(this.year())},isDST:function(){return this.utcOffset()>this.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},day:function(a){var b=this._isUTC?this._d.getUTCDay():this._d.getDay();return null!=a?(a=gb(a,this.localeData()),this.add(a-b,"d")):b},month:qb("Month",!0),startOf:function(a){switch(a=z(a)){case"year":this.month(0);case"quarter":case"month":this.date(1);case"week":case"isoWeek":case"day":this.hours(0);case"hour":this.minutes(0);case"minute":this.seconds(0);case"second":this.milliseconds(0)}return"week"===a?this.weekday(0):"isoWeek"===a&&this.isoWeekday(1),"quarter"===a&&this.month(3*Math.floor(this.month()/3)),this},endOf:function(b){return b=z(b),b===a||"millisecond"===b?this:this.startOf(b).add(1,"isoWeek"===b?"week":b).subtract(1,"ms")},isAfter:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+this>+a):(c=vb.isMoment(a)?+a:+vb(a),c<+this.clone().startOf(b))},isBefore:function(a,b){var c;return b=z("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+a>+this):(c=vb.isMoment(a)?+a:+vb(a),+this.clone().endOf(b)<c)},isBetween:function(a,b,c){return this.isAfter(a,c)&&this.isBefore(b,c)},isSame:function(a,b){var c;return b=z(b||"millisecond"),"millisecond"===b?(a=vb.isMoment(a)?a:vb(a),+this===+a):(c=+vb(a),+this.clone().startOf(b)<=c&&c<=+this.clone().endOf(b))},min:f("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(a){return a=vb.apply(null,arguments),this>a?this:a}),max:f("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=vb.apply(null,arguments),a>this?this:a}),zone:f("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779",function(a,b){return null!=a?("string"!=typeof a&&(a=-a),this.utcOffset(a,b),this):-this.utcOffset()}),utcOffset:function(a,b){var c,d=this._offset||0;return null!=a?("string"==typeof a&&(a=S(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._dateUtcOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.add(c,"m"),d!==a&&(!b||this._changeInProgress?v(this,vb.duration(a-d,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,vb.updateOffset(this,!0),this._changeInProgress=null)),this):this._isUTC?d:this._dateUtcOffset()},isLocal:function(){return!this._isUTC},isUtcOffset:function(){return this._isUTC},isUtc:function(){return this._isUTC&&0===this._offset},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.utcOffset(this._tzm):"string"==typeof this._i&&this.utcOffset(S(this._i)),this},hasAlignedHourOffset:function(a){return a=a?vb(a).utcOffset():0,(this.utcOffset()-a)%60===0},daysInMonth:function(){return D(this.year(),this.month())},dayOfYear:function(a){var b=Ab((vb(this).startOf("day")-vb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")}
699,quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=jb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=jb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=jb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return E(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return E(this.year(),a.dow,a.doy)},get:function(a){return a=z(a),this[a]()},set:function(a,b){var c;if("object"==typeof a)for(c in a)this.set(c,a[c]);else a=z(a),"function"==typeof this[a]&&this[a](b);return this},locale:function(b){var c;return b===a?this._locale._abbr:(c=vb.localeData(b),null!=c&&(this._locale=c),this)},lang:f("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.",function(b){return b===a?this.localeData():this.locale(b)}),localeData:function(){return this._locale},_dateUtcOffset:function(){return 15*-Math.round(this._d.getTimezoneOffset()/15)}}),vb.fn.millisecond=vb.fn.milliseconds=qb("Milliseconds",!1),vb.fn.second=vb.fn.seconds=qb("Seconds",!1),vb.fn.minute=vb.fn.minutes=qb("Minutes",!1),vb.fn.hour=vb.fn.hours=qb("Hours",!0),vb.fn.date=qb("Date",!0),vb.fn.dates=f("dates accessor is deprecated. Use date instead.",qb("Date",!0)),vb.fn.year=qb("FullYear",!0),vb.fn.years=f("years accessor is deprecated. Use year instead.",qb("FullYear",!0)),vb.fn.days=vb.fn.day,vb.fn.months=vb.fn.month,vb.fn.weeks=vb.fn.week,vb.fn.isoWeeks=vb.fn.isoWeek,vb.fn.quarters=vb.fn.quarter,vb.fn.toJSON=vb.fn.toISOString,vb.fn.isUTC=vb.fn.isUtc,o(vb.duration.fn=n.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=q(d/1e3),g.seconds=a%60,b=q(a/60),g.minutes=b%60,c=q(b/60),g.hours=c%24,e+=q(c/24),h=q(rb(e)),e-=q(sb(h)),f+=q(e/30),e%=30,h+=q(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return q(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*C(this._months/12)
700
701},humanize:function(a){var b=ib(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=vb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=vb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=z(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=z(a),"month"===a||"year"===a)return b=this._days+this._milliseconds/864e5,c=this._months+12*rb(b),"month"===a?c:c/12;switch(b=this._days+Math.round(sb(this._months/12)),a){case"week":return b/7+this._milliseconds/6048e5;case"day":return b+this._milliseconds/864e5;case"hour":return 24*b+this._milliseconds/36e5;case"minute":return 24*b*60+this._milliseconds/6e4;case"second":return 24*b*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+a)}},lang:vb.fn.lang,locale:vb.fn.locale,toIsoString:f("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale},toJSON:function(){return this.toISOString()}}),vb.duration.fn.toString=vb.duration.fn.toISOString;for(xb in kc)c(kc,xb)&&tb(xb.toLowerCase());vb.duration.fn.asMilliseconds=function(){return this.as("ms")},vb.duration.fn.asSeconds=function(){return this.as("s")},vb.duration.fn.asMinutes=function(){return this.as("m")},vb.duration.fn.asHours=function(){return this.as("h")},vb.duration.fn.asDays=function(){return this.as("d")},vb.duration.fn.asWeeks=function(){return this.as("weeks")},vb.duration.fn.asMonths=function(){return this.as("M")},vb.duration.fn.asYears=function(){return this.as("y")},vb.locale("en",{ordinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(a){var b=a%10,c=1===C(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th";return a+c}}),Lb?module.exports=vb:"function"==typeof define&&define.amd?(define(function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(zb.moment=wb),vb}),ub(!0)):ub()}).call(this);
702/*!
703
704 * FullCalendar v2.5.0
705
706 * Docs & License: http://fullcalendar.io/
707
708 * (c) 2015 Adam Shaw
709
710 */
711
712
713
714(function(factory) {
715
716	if (typeof define === 'function' && define.amd) {
717
718		define([ 'jquery', 'moment' ], factory);
719
720	}
721
722	else if (typeof exports === 'object') { // Node/CommonJS
723
724		module.exports = factory(require('jquery'), require('moment'));
725
726	}
727
728	else {
729
730		factory(jQuery, moment);
731
732	}
733
734})(function($, moment) {
735
736
737
738	;;
739
740
741
742	var FC = $.fullCalendar = {
743
744		version: "2.5.0",
745
746		internalApiVersion: 1
747
748	};
749
750	var fcViews = FC.views = {};
751
752
753
754
755
756	$.fn.fullCalendar = function(options) {
757
758		var args = Array.prototype.slice.call(arguments, 1); // for a possible method call
759
760		var res = this; // what this function will return (this jQuery object by default)
761
762
763
764		this.each(function(i, _element) { // loop each DOM element involved
765
766			var element = $(_element);
767
768			var calendar = element.data('fullCalendar'); // get the existing calendar object (if any)
769
770			var singleRes; // the returned value of this single method call
771
772
773
774			// a method call
775
776			if (typeof options === 'string') {
777
778				if (calendar && $.isFunction(calendar[options])) {
779
780					singleRes = calendar[options].apply(calendar, args);
781
782					if (!i) {
783
784						res = singleRes; // record the first method call result
785
786					}
787
788					if (options === 'destroy') { // for the destroy method, must remove Calendar object data
789
790						element.removeData('fullCalendar');
791
792					}
793
794				}
795
796			}
797
798			// a new calendar initialization
799
800			else if (!calendar) { // don't initialize twice
801
802				calendar = new Calendar(element, options);
803
804				element.data('fullCalendar', calendar);
805
806				calendar.render();
807
808			}
809
810		});
811
812
813
814		return res;
815
816	};
817
818
819
820
821
822	var complexOptions = [ // names of options that are objects whose properties should be combined
823
824		'header',
825
826		'buttonText',
827
828		'buttonIcons',
829
830		'themeButtonIcons'
831
832	];
833
834
835
836
837
838// Merges an array of option objects into a single object
839
840	function mergeOptions(optionObjs) {
841
842		return mergeProps(optionObjs, complexOptions);
843
844	}
845
846
847
848
849
850// Given options specified for the calendar's constructor, massages any legacy options into a non-legacy form.
851
852// Converts View-Option-Hashes into the View-Specific-Options format.
853
854	function massageOverrides(input) {
855
856		var overrides = { views: input.views || {} }; // the output. ensure a `views` hash
857
858		var subObj;
859
860
861
862		// iterate through all option override properties (except `views`)
863
864		$.each(input, function(name, val) {
865
866			if (name != 'views') {
867
868
869
870				// could the value be a legacy View-Option-Hash?
871
872				if (
873
874					$.isPlainObject(val) &&
875
876					!/(time|duration|interval)$/i.test(name) && // exclude duration options. might be given as objects
877
878					$.inArray(name, complexOptions) == -1 // complex options aren't allowed to be View-Option-Hashes
879
880				) {
881
882					subObj = null;
883
884
885
886					// iterate through the properties of this possible View-Option-Hash value
887
888					$.each(val, function(subName, subVal) {
889
890
891
892						// is the property targeting a view?
893
894						if (/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(subName)) {
895
896							if (!overrides.views[subName]) { // ensure the view-target entry exists
897
898								overrides.views[subName] = {};
899
900							}
901
902							overrides.views[subName][name] = subVal; // record the value in the `views` object
903
904						}
905
906						else { // a non-View-Option-Hash property
907
908							if (!subObj) {
909
910								subObj = {};
911
912							}
913
914							subObj[subName] = subVal; // accumulate these unrelated values for later
915
916						}
917
918					});
919
920
921
922					if (subObj) { // non-View-Option-Hash properties? transfer them as-is
923
924						overrides[name] = subObj;
925
926					}
927
928				}
929
930				else {
931
932					overrides[name] = val; // transfer normal options as-is
933
934				}
935
936			}
937
938		});
939
940
941
942		return overrides;
943
944	}
945
946
947
948	;;
949
950
951
952// exports
953
954	FC.intersectRanges = intersectRanges;
955
956	FC.applyAll = applyAll;
957
958	FC.debounce = debounce;
959
960	FC.isInt = isInt;
961
962	FC.htmlEscape = htmlEscape;
963
964	FC.cssToStr = cssToStr;
965
966	FC.proxy = proxy;
967
968	FC.capitaliseFirstLetter = capitaliseFirstLetter;
969
970
971
972
973
974	/* FullCalendar-specific DOM Utilities
975
976	 ----------------------------------------------------------------------------------------------------------------------*/
977
978
979
980
981
982// Given the scrollbar widths of some other container, create borders/margins on rowEls in order to match the left
983
984// and right space that was offset by the scrollbars. A 1-pixel border first, then margin beyond that.
985
986	function compensateScroll(rowEls, scrollbarWidths) {
987
988		if (scrollbarWidths.left) {
989
990			rowEls.css({
991
992				'border-left-width': 1,
993
994				'margin-left': scrollbarWidths.left - 1
995
996			});
997
998		}
999
1000		if (scrollbarWidths.right) {
1001
1002			rowEls.css({
1003
1004				'border-right-width': 1,
1005
1006				'margin-right': scrollbarWidths.right - 1
1007
1008			});
1009
1010		}
1011
1012	}
1013
1014
1015
1016
1017
1018// Undoes compensateScroll and restores all borders/margins
1019
1020	function uncompensateScroll(rowEls) {
1021
1022		rowEls.css({
1023
1024			'margin-left': '',
1025
1026			'margin-right': '',
1027
1028			'border-left-width': '',
1029
1030			'border-right-width': ''
1031
1032		});
1033
1034	}
1035
1036
1037
1038
1039
1040// Make the mouse cursor express that an event is not allowed in the current area
1041
1042	function disableCursor() {
1043
1044		$('body').addClass('fc-not-allowed');
1045
1046	}
1047
1048
1049
1050
1051
1052// Returns the mouse cursor to its original look
1053
1054	function enableCursor() {
1055
1056		$('body').removeClass('fc-not-allowed');
1057
1058	}
1059
1060
1061
1062
1063
1064// Given a total available height to fill, have `els` (essentially child rows) expand to accomodate.
1065
1066// By default, all elements that are shorter than the recommended height are expanded uniformly, not considering
1067
1068// any other els that are already too tall. if `shouldRedistribute` is on, it considers these tall rows and
1069
1070// reduces the available height.
1071
1072	function distributeHeight(els, availableHeight, shouldRedistribute) {
1073
1074
1075
1076		// *FLOORING NOTE*: we floor in certain places because zoom can give inaccurate floating-point dimensions,
1077
1078		// and it is better to be shorter than taller, to avoid creating unnecessary scrollbars.
1079
1080
1081
1082		var minOffset1 = Math.floor(availableHeight / els.length); // for non-last element
1083
1084		var minOffset2 = Math.floor(availableHeight - minOffset1 * (els.length - 1)); // for last element *FLOORING NOTE*
1085
1086		var flexEls = []; // elements that are allowed to expand. array of DOM nodes
1087
1088		var flexOffsets = []; // amount of vertical space it takes up
1089
1090		var flexHeights = []; // actual css height
1091
1092		var usedHeight = 0;
1093
1094
1095
1096		undistributeHeight(els); // give all elements their natural height
1097
1098
1099
1100		// find elements that are below the recommended height (expandable).
1101
1102		// important to query for heights in a single first pass (to avoid reflow oscillation).
1103
1104		els.each(function(i, el) {
1105
1106			var minOffset = i === els.length - 1 ? minOffset2 : minOffset1;
1107
1108			var naturalOffset = $(el).outerHeight(true);
1109
1110
1111
1112			if (naturalOffset < minOffset) {
1113
1114				flexEls.push(el);
1115
1116				flexOffsets.push(naturalOffset);
1117
1118				flexHeights.push($(el).height());
1119
1120			}
1121
1122			else {
1123
1124				// this element stretches past recommended height (non-expandable). mark the space as occupied.
1125
1126				usedHeight += naturalOffset;
1127
1128			}
1129
1130		});
1131
1132
1133
1134		// readjust the recommended height to only consider the height available to non-maxed-out rows.
1135
1136		if (shouldRedistribute) {
1137
1138			availableHeight -= usedHeight;
1139
1140			minOffset1 = Math.floor(availableHeight / flexEls.length);
1141
1142			minOffset2 = Math.floor(availableHeight - minOffset1 * (flexEls.length - 1)); // *FLOORING NOTE*
1143
1144		}
1145
1146
1147
1148		// assign heights to all expandable elements
1149
1150		$(flexEls).each(function(i, el) {
1151
1152			var minOffset = i === flexEls.length - 1 ? minOffset2 : minOffset1;
1153
1154			var naturalOffset = flexOffsets[i];
1155
1156			var naturalHeight = flexHeights[i];
1157
1158			var newHeight = minOffset - (naturalOffset - naturalHeight); // subtract the margin/padding
1159
1160
1161
1162			if (naturalOffset < minOffset) { // we check this again because redistribution might have changed things
1163
1164				$(el).height(newHeight);
1165
1166			}
1167
1168		});
1169
1170	}
1171
1172
1173
1174
1175
1176// Undoes distrubuteHeight, restoring all els to their natural height
1177
1178	function undistributeHeight(els) {
1179
1180		els.height('');
1181
1182	}
1183
1184
1185
1186
1187
1188// Given `els`, a jQuery set of <td> cells, find the cell with the largest natural width and set the widths of all the
1189
1190// cells to be that width.
1191
1192// PREREQUISITE: if you want a cell to take up width, it needs to have a single inner element w/ display:inline
1193
1194	function matchCellWidths(els) {
1195
1196		var maxInnerWidth = 0;
1197
1198
1199
1200		els.find('> *').each(function(i, innerEl) {
1201
1202			var innerWidth = $(innerEl).outerWidth();
1203
1204			if (innerWidth > maxInnerWidth) {
1205
1206				maxInnerWidth = innerWidth;
1207
1208			}
1209
1210		});
1211
1212
1213
1214		maxInnerWidth++; // sometimes not accurate of width the text needs to stay on one line. insurance
1215
1216
1217
1218		els.width(maxInnerWidth);
1219
1220
1221
1222		return maxInnerWidth;
1223
1224	}
1225
1226
1227
1228
1229
1230// Turns a container element into a scroller if its contents is taller than the allotted height.
1231
1232// Returns true if the element is now a scroller, false otherwise.
1233
1234// NOTE: this method is best because it takes weird zooming dimensions into account
1235
1236	function setPotentialScroller(containerEl, height) {
1237
1238		containerEl.height(height).addClass('fc-scroller');
1239
1240
1241
1242		// are scrollbars needed?
1243
1244		if (containerEl[0].scrollHeight - 1 > containerEl[0].clientHeight) { // !!! -1 because IE is often off-by-one :(
1245
1246			return true;
1247
1248		}
1249
1250
1251
1252		unsetScroller(containerEl); // undo
1253
1254		return false;
1255
1256	}
1257
1258
1259
1260
1261
1262// Takes an element that might have been a scroller, and turns it back into a normal element.
1263
1264	function unsetScroller(containerEl) {
1265
1266		containerEl.height('').removeClass('fc-scroller');
1267
1268	}
1269
1270
1271
1272
1273
1274	/* General DOM Utilities
1275
1276	 ----------------------------------------------------------------------------------------------------------------------*/
1277
1278
1279
1280	FC.getOuterRect = getOuterRect;
1281
1282	FC.getClientRect = getClientRect;
1283
1284	FC.getContentRect = getContentRect;
1285
1286	FC.getScrollbarWidths = getScrollbarWidths;
1287
1288
1289
1290
1291
1292// borrowed from https://github.com/jquery/jquery-ui/blob/1.11.0/ui/core.js#L51
1293
1294	function getScrollParent(el) {
1295
1296		var position = el.css('position'),
1297
1298			scrollParent = el.parents().filter(function() {
1299
1300				var parent = $(this);
1301
1302				return (/(auto|scroll)/).test(
1303
1304					parent.css('overflow') + parent.css('overflow-y') + parent.css('overflow-x')
1305
1306				);
1307
1308			}).eq(0);
1309
1310
1311
1312		return position === 'fixed' || !scrollParent.length ? $(el[0].ownerDocument || document) : scrollParent;
1313
1314	}
1315
1316
1317
1318
1319
1320// Queries the outer bounding area of a jQuery element.
1321
1322// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
1323
1324	function getOuterRect(el) {
1325
1326		var offset = el.offset();
1327
1328
1329
1330		return {
1331
1332			left: offset.left,
1333
1334			right: offset.left + el.outerWidth(),
1335
1336			top: offset.top,
1337
1338			bottom: offset.top + el.outerHeight()
1339
1340		};
1341
1342	}
1343
1344
1345
1346
1347
1348// Queries the area within the margin/border/scrollbars of a jQuery element. Does not go within the padding.
1349
1350// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
1351
1352// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
1353
1354	function getClientRect(el) {
1355
1356		var offset = el.offset();
1357
1358		var scrollbarWidths = getScrollbarWidths(el);
1359
1360		var left = offset.left + getCssFloat(el, 'border-left-width') + scrollbarWidths.left;
1361
1362		var top = offset.top + getCssFloat(el, 'border-top-width') + scrollbarWidths.top;
1363
1364
1365
1366		return {
1367
1368			left: left,
1369
1370			right: left + el[0].clientWidth, // clientWidth includes padding but NOT scrollbars
1371
1372			top: top,
1373
1374			bottom: top + el[0].clientHeight // clientHeight includes padding but NOT scrollbars
1375
1376		};
1377
1378	}
1379
1380
1381
1382
1383
1384// Queries the area within the margin/border/padding of a jQuery element. Assumed not to have scrollbars.
1385
1386// Returns a rectangle with absolute coordinates: left, right (exclusive), top, bottom (exclusive).
1387
1388	function getContentRect(el) {
1389
1390		var offset = el.offset(); // just outside of border, margin not included
1391
1392		var left = offset.left + getCssFloat(el, 'border-left-width') + getCssFloat(el, 'padding-left');
1393
1394		var top = offset.top + getCssFloat(el, 'border-top-width') + getCssFloat(el, 'padding-top');
1395
1396
1397
1398		return {
1399
1400			left: left,
1401
1402			right: left + el.width(),
1403
1404			top: top,
1405
1406			bottom: top + el.height()
1407
1408		};
1409
1410	}
1411
1412
1413
1414
1415
1416// Returns the computed left/right/top/bottom scrollbar widths for the given jQuery element.
1417
1418// NOTE: should use clientLeft/clientTop, but very unreliable cross-browser.
1419
1420	function getScrollbarWidths(el) {
1421
1422		var leftRightWidth = el.innerWidth() - el[0].clientWidth; // the paddings cancel out, leaving the scrollbars
1423
1424		var widths = {
1425
1426			left: 0,
1427
1428			right: 0,
1429
1430			top: 0,
1431
1432			bottom: el.innerHeight() - el[0].clientHeight // the paddings cancel out, leaving the bottom scrollbar
1433
1434		};
1435
1436
1437
1438		if (getIsLeftRtlScrollbars() && el.css('direction') == 'rtl') { // is the scrollbar on the left side?
1439
1440			widths.left = leftRightWidth;
1441
1442		}
1443
1444		else {
1445
1446			widths.right = leftRightWidth;
1447
1448		}
1449
1450
1451
1452		return widths;
1453
1454	}
1455
1456
1457
1458
1459
1460// Logic for determining if, when the element is right-to-left, the scrollbar appears on the left side
1461
1462
1463
1464	var _isLeftRtlScrollbars = null;
1465
1466
1467
1468	function getIsLeftRtlScrollbars() { // responsible for caching the computation
1469
1470		if (_isLeftRtlScrollbars === null) {
1471
1472			_isLeftRtlScrollbars = computeIsLeftRtlScrollbars();
1473
1474		}
1475
1476		return _isLeftRtlScrollbars;
1477
1478	}
1479
1480
1481
1482	function computeIsLeftRtlScrollbars() { // creates an offscreen test element, then removes it
1483
1484		var el = $('<div><div/></div>')
1485
1486			.css({
1487
1488				position: 'absolute',
1489
1490				top: -1000,
1491
1492				left: 0,
1493
1494				border: 0,
1495
1496				padding: 0,
1497
1498				overflow: 'scroll',
1499
1500				direction: 'rtl'
1501
1502			})
1503
1504			.appendTo('body');
1505
1506		var innerEl = el.children();
1507
1508		var res = innerEl.offset().left > el.offset().left; // is the inner div shifted to accommodate a left scrollbar?
1509
1510		el.remove();
1511
1512		return res;
1513
1514	}
1515
1516
1517
1518
1519
1520// Retrieves a jQuery element's computed CSS value as a floating-point number.
1521
1522// If the queried value is non-numeric (ex: IE can return "medium" for border width), will just return zero.
1523
1524	function getCssFloat(el, prop) {
1525
1526		return parseFloat(el.css(prop)) || 0;
1527
1528	}
1529
1530
1531
1532
1533
1534// Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
1535
1536	function isPrimaryMouseButton(ev) {
1537
1538		return ev.which == 1 && !ev.ctrlKey;
1539
1540	}
1541
1542
1543
1544
1545
1546	/* Geometry
1547
1548	 ----------------------------------------------------------------------------------------------------------------------*/
1549
1550
1551
1552	FC.intersectRects = intersectRects;
1553
1554
1555
1556// Returns a new rectangle that is the intersection of the two rectangles. If they don't intersect, returns false
1557
1558	function intersectRects(rect1, rect2) {
1559
1560		var res = {
1561
1562			left: Math.max(rect1.left, rect2.left),
1563
1564			right: Math.min(rect1.right, rect2.right),
1565
1566			top: Math.max(rect1.top, rect2.top),
1567
1568			bottom: Math.min(rect1.bottom, rect2.bottom)
1569
1570		};
1571
1572
1573
1574		if (res.left < res.right && res.top < res.bottom) {
1575
1576			return res;
1577
1578		}
1579
1580		return false;
1581
1582	}
1583
1584
1585
1586
1587
1588// Returns a new point that will have been moved to reside within the given rectangle
1589
1590	function constrainPoint(point, rect) {
1591
1592		return {
1593
1594			left: Math.min(Math.max(point.left, rect.left), rect.right),
1595
1596			top: Math.min(Math.max(point.top, rect.top), rect.bottom)
1597
1598		};
1599
1600	}
1601
1602
1603
1604
1605
1606// Returns a point that is the center of the given rectangle
1607
1608	function getRectCenter(rect) {
1609
1610		return {
1611
1612			left: (rect.left + rect.right) / 2,
1613
1614			top: (rect.top + rect.bottom) / 2
1615
1616		};
1617
1618	}
1619
1620
1621
1622
1623
1624// Subtracts point2's coordinates from point1's coordinates, returning a delta
1625
1626	function diffPoints(point1, point2) {
1627
1628		return {
1629
1630			left: point1.left - point2.left,
1631
1632			top: point1.top - point2.top
1633
1634		};
1635
1636	}
1637
1638
1639
1640
1641
1642	/* Object Ordering by Field
1643
1644	 ----------------------------------------------------------------------------------------------------------------------*/
1645
1646
1647
1648	FC.parseFieldSpecs = parseFieldSpecs;
1649
1650	FC.compareByFieldSpecs = compareByFieldSpecs;
1651
1652	FC.compareByFieldSpec = compareByFieldSpec;
1653
1654	FC.flexibleCompare = flexibleCompare;
1655
1656
1657
1658
1659
1660	function parseFieldSpecs(input) {
1661
1662		var specs = [];
1663
1664		var tokens = [];
1665
1666		var i, token;
1667
1668
1669
1670		if (typeof input === 'string') {
1671
1672			tokens = input.split(/\s*,\s*/);
1673
1674		}
1675
1676		else if (typeof input === 'function') {
1677
1678			tokens = [ input ];
1679
1680		}
1681
1682		else if ($.isArray(input)) {
1683
1684			tokens = input;
1685
1686		}
1687
1688
1689
1690		for (i = 0; i < tokens.length; i++) {
1691
1692			token = tokens[i];
1693
1694
1695
1696			if (typeof token === 'string') {
1697
1698				specs.push(
1699
1700					token.charAt(0) == '-' ?
1701
1702					{ field: token.substring(1), order: -1 } :
1703
1704					{ field: token, order: 1 }
1705
1706				);
1707
1708			}
1709
1710			else if (typeof token === 'function') {
1711
1712				specs.push({ func: token });
1713
1714			}
1715
1716		}
1717
1718
1719
1720		return specs;
1721
1722	}
1723
1724
1725
1726
1727
1728	function compareByFieldSpecs(obj1, obj2, fieldSpecs) {
1729
1730		var i;
1731
1732		var cmp;
1733
1734
1735
1736		for (i = 0; i < fieldSpecs.length; i++) {
1737
1738			cmp = compareByFieldSpec(obj1, obj2, fieldSpecs[i]);
1739
1740			if (cmp) {
1741
1742				return cmp;
1743
1744			}
1745
1746		}
1747
1748
1749
1750		return 0;
1751
1752	}
1753
1754
1755
1756
1757
1758	function compareByFieldSpec(obj1, obj2, fieldSpec) {
1759
1760		if (fieldSpec.func) {
1761
1762			return fieldSpec.func(obj1, obj2);
1763
1764		}
1765
1766		return flexibleCompare(obj1[fieldSpec.field], obj2[fieldSpec.field]) *
1767
1768			(fieldSpec.order || 1);
1769
1770	}
1771
1772
1773
1774
1775
1776	function flexibleCompare(a, b) {
1777
1778		if (!a && !b) {
1779
1780			return 0;
1781
1782		}
1783
1784		if (b == null) {
1785
1786			return -1;
1787
1788		}
1789
1790		if (a == null) {
1791
1792			return 1;
1793
1794		}
1795
1796		if ($.type(a) === 'string' || $.type(b) === 'string') {
1797
1798			return String(a).localeCompare(String(b));
1799
1800		}
1801
1802		return a - b;
1803
1804	}
1805
1806
1807
1808
1809
1810	/* FullCalendar-specific Misc Utilities
1811
1812	 ----------------------------------------------------------------------------------------------------------------------*/
1813
1814
1815
1816
1817
1818// Computes the intersection of the two ranges. Returns undefined if no intersection.
1819
1820// Expects all dates to be normalized to the same timezone beforehand.
1821
1822// TODO: move to date section?
1823
1824	function intersectRanges(subjectRange, constraintRange) {
1825
1826		var subjectStart = subjectRange.start;
1827
1828		var subjectEnd = subjectRange.end;
1829
1830		var constraintStart = constraintRange.start;
1831
1832		var constraintEnd = constraintRange.end;
1833
1834		var segStart, segEnd;
1835
1836		var isStart, isEnd;
1837
1838
1839
1840		if (subjectEnd > constraintStart && subjectStart < constraintEnd) { // in bounds at all?
1841
1842
1843
1844			if (subjectStart >= constraintStart) {
1845
1846				segStart = subjectStart.clone();
1847
1848				isStart = true;
1849
1850			}
1851
1852			else {
1853
1854				segStart = constraintStart.clone();
1855
1856				isStart =  false;
1857
1858			}
1859
1860
1861
1862			if (subjectEnd <= constraintEnd) {
1863
1864				segEnd = subjectEnd.clone();
1865
1866				isEnd = true;
1867
1868			}
1869
1870			else {
1871
1872				segEnd = constraintEnd.clone();
1873
1874				isEnd = false;
1875
1876			}
1877
1878
1879
1880			return {
1881
1882				start: segStart,
1883
1884				end: segEnd,
1885
1886				isStart: isStart,
1887
1888				isEnd: isEnd
1889
1890			};
1891
1892		}
1893
1894	}
1895
1896
1897
1898
1899
1900	/* Date Utilities
1901
1902	 ----------------------------------------------------------------------------------------------------------------------*/
1903
1904
1905
1906	FC.computeIntervalUnit = computeIntervalUnit;
1907
1908	FC.divideRangeByDuration = divideRangeByDuration;
1909
1910	FC.divideDurationByDuration = divideDurationByDuration;
1911
1912	FC.multiplyDuration = multiplyDuration;
1913
1914	FC.durationHasTime = durationHasTime;
1915
1916
1917
1918	var dayIDs = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
1919
1920	var intervalUnits = [ 'year', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond' ];
1921
1922
1923
1924
1925
1926// Diffs the two moments into a Duration where full-days are recorded first, then the remaining time.
1927
1928// Moments will have their timezones normalized.
1929
1930	function diffDayTime(a, b) {
1931
1932		return moment.duration({
1933
1934			days: a.clone().stripTime().diff(b.clone().stripTime(), 'days'),
1935
1936			ms: a.time() - b.time() // time-of-day from day start. disregards timezone
1937
1938		});
1939
1940	}
1941
1942
1943
1944
1945
1946// Diffs the two moments via their start-of-day (regardless of timezone). Produces whole-day durations.
1947
1948	function diffDay(a, b) {
1949
1950		return moment.duration({
1951
1952			days: a.clone().stripTime().diff(b.clone().stripTime(), 'days')
1953
1954		});
1955
1956	}
1957
1958
1959
1960
1961
1962// Diffs two moments, producing a duration, made of a whole-unit-increment of the given unit. Uses rounding.
1963
1964	function diffByUnit(a, b, unit) {
1965
1966		return moment.duration(
1967
1968			Math.round(a.diff(b, unit, true)), // returnFloat=true
1969
1970			unit
1971
1972		);
1973
1974	}
1975
1976
1977
1978
1979
1980// Computes the unit name of the largest whole-unit period of time.
1981
1982// For example, 48 hours will be "days" whereas 49 hours will be "hours".
1983
1984// Accepts start/end, a range object, or an original duration object.
1985
1986	function computeIntervalUnit(start, end) {
1987
1988		var i, unit;
1989
1990		var val;
1991
1992
1993
1994		for (i = 0; i < intervalUnits.length; i++) {
1995
1996			unit = intervalUnits[i];
1997
1998			val = computeRangeAs(unit, start, end);
1999
2000
2001
2002			if (val >= 1 && isInt(val)) {
2003
2004				break;
2005
2006			}
2007
2008		}
2009
2010
2011
2012		return unit; // will be "milliseconds" if nothing else matches
2013
2014	}
2015
2016
2017
2018
2019
2020// Computes the number of units (like "hours") in the given range.
2021
2022// Range can be a {start,end} object, separate start/end args, or a Duration.
2023
2024// Results are based on Moment's .as() and .diff() methods, so results can depend on internal handling
2025
2026// of month-diffing logic (which tends to vary from version to version).
2027
2028	function computeRangeAs(unit, start, end) {
2029
2030
2031
2032		if (end != null) { // given start, end
2033
2034			return end.diff(start, unit, true);
2035
2036		}
2037
2038		else if (moment.isDuration(start)) { // given duration
2039
2040			return start.as(unit);
2041
2042		}
2043
2044		else { // given { start, end } range object
2045
2046			return start.end.diff(start.start, unit, true);
2047
2048		}
2049
2050	}
2051
2052
2053
2054
2055
2056// Intelligently divides a range (specified by a start/end params) by a duration
2057
2058	function divideRangeByDuration(start, end, dur) {
2059
2060		var months;
2061
2062
2063
2064		if (durationHasTime(dur)) {
2065
2066			return (end - start) / dur;
2067
2068		}
2069
2070		months = dur.asMonths();
2071
2072		if (Math.abs(months) >= 1 && isInt(months)) {
2073
2074			return end.diff(start, 'months', true) / months;
2075
2076		}
2077
2078		return end.diff(start, 'days', true) / dur.asDays();
2079
2080	}
2081
2082
2083
2084
2085
2086// Intelligently divides one duration by another
2087
2088	function divideDurationByDuration(dur1, dur2) {
2089
2090		var months1, months2;
2091
2092
2093
2094		if (durationHasTime(dur1) || durationHasTime(dur2)) {
2095
2096			return dur1 / dur2;
2097
2098		}
2099
2100		months1 = dur1.asMonths();
2101
2102		months2 = dur2.asMonths();
2103
2104		if (
2105
2106			Math.abs(months1) >= 1 && isInt(months1) &&
2107
2108			Math.abs(months2) >= 1 && isInt(months2)
2109
2110		) {
2111
2112			return months1 / months2;
2113
2114		}
2115
2116		return dur1.asDays() / dur2.asDays();
2117
2118	}
2119
2120
2121
2122
2123
2124// Intelligently multiplies a duration by a number
2125
2126	function multiplyDuration(dur, n) {
2127
2128		var months;
2129
2130
2131
2132		if (durationHasTime(dur)) {
2133
2134			return moment.duration(dur * n);
2135
2136		}
2137
2138		months = dur.asMonths();
2139
2140		if (Math.abs(months) >= 1 && isInt(months)) {
2141
2142			return moment.duration({ months: months * n });
2143
2144		}
2145
2146		return moment.duration({ days: dur.asDays() * n });
2147
2148	}
2149
2150
2151
2152
2153
2154// Returns a boolean about whether the given duration has any time parts (hours/minutes/seconds/ms)
2155
2156	function durationHasTime(dur) {
2157
2158		return Boolean(dur.hours() || dur.minutes() || dur.seconds() || dur.milliseconds());
2159
2160	}
2161
2162
2163
2164
2165
2166	function isNativeDate(input) {
2167
2168		return  Object.prototype.toString.call(input) === '[object Date]' || input instanceof Date;
2169
2170	}
2171
2172
2173
2174
2175
2176// Returns a boolean about whether the given input is a time string, like "06:40:00" or "06:00"
2177
2178	function isTimeString(str) {
2179
2180		return /^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(str);
2181
2182	}
2183
2184
2185
2186
2187
2188	/* Logging and Debug
2189
2190	 ----------------------------------------------------------------------------------------------------------------------*/
2191
2192
2193
2194	FC.log = function() {
2195
2196		var console = window.console;
2197
2198
2199
2200		if (console && console.log) {
2201
2202			return console.log.apply(console, arguments);
2203
2204		}
2205
2206	};
2207
2208
2209
2210	FC.warn = function() {
2211
2212		var console = window.console;
2213
2214
2215
2216		if (console && console.warn) {
2217
2218			return console.warn.apply(console, arguments);
2219
2220		}
2221
2222		else {
2223
2224			return FC.log.apply(FC, arguments);
2225
2226		}
2227
2228	};
2229
2230
2231
2232
2233
2234	/* General Utilities
2235
2236	 ----------------------------------------------------------------------------------------------------------------------*/
2237
2238
2239
2240	var hasOwnPropMethod = {}.hasOwnProperty;
2241
2242
2243
2244
2245
2246// Merges an array of objects into a single object.
2247
2248// The second argument allows for an array of property names who's object values will be merged together.
2249
2250	function mergeProps(propObjs, complexProps) {
2251
2252		var dest = {};
2253
2254		var i, name;
2255
2256		var complexObjs;
2257
2258		var j, val;
2259
2260		var props;
2261
2262
2263
2264		if (complexProps) {
2265
2266			for (i = 0; i < complexProps.length; i++) {
2267
2268				name = complexProps[i];
2269
2270				complexObjs = [];
2271
2272
2273
2274				// collect the trailing object values, stopping when a non-object is discovered
2275
2276				for (j = propObjs.length - 1; j >= 0; j--) {
2277
2278					val = propObjs[j][name];
2279
2280
2281
2282					if (typeof val === 'object') {
2283
2284						complexObjs.unshift(val);
2285
2286					}
2287
2288					else if (val !== undefined) {
2289
2290						dest[name] = val; // if there were no objects, this value will be used
2291
2292						break;
2293
2294					}
2295
2296				}
2297
2298
2299
2300				// if the trailing values were objects, use the merged value
2301
2302				if (complexObjs.length) {
2303
2304					dest[name] = mergeProps(complexObjs);
2305
2306				}
2307
2308			}
2309
2310		}
2311
2312
2313
2314		// copy values into the destination, going from last to first
2315
2316		for (i = propObjs.length - 1; i >= 0; i--) {
2317
2318			props = propObjs[i];
2319
2320
2321
2322			for (name in props) {
2323
2324				if (!(name in dest)) { // if already assigned by previous props or complex props, don't reassign
2325
2326					dest[name] = props[name];
2327
2328				}
2329
2330			}
2331
2332		}
2333
2334
2335
2336		return dest;
2337
2338	}
2339
2340
2341
2342
2343
2344// Create an object that has the given prototype. Just like Object.create
2345
2346	function createObject(proto) {
2347
2348		var f = function() {};
2349
2350		f.prototype = proto;
2351
2352		return new f();
2353
2354	}
2355
2356
2357
2358
2359
2360	function copyOwnProps(src, dest) {
2361
2362		for (var name in src) {
2363
2364			if (hasOwnProp(src, name)) {
2365
2366				dest[name] = src[name];
2367
2368			}
2369
2370		}
2371
2372	}
2373
2374
2375
2376
2377
2378// Copies over certain methods with the same names as Object.prototype methods. Overcomes an IE<=8 bug:
2379
2380// https://developer.mozilla.org/en-US/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
2381
2382	function copyNativeMethods(src, dest) {
2383
2384		var names = [ 'constructor', 'toString', 'valueOf' ];
2385
2386		var i, name;
2387
2388
2389
2390		for (i = 0; i < names.length; i++) {
2391
2392			name = names[i];
2393
2394
2395
2396			if (src[name] !== Object.prototype[name]) {
2397
2398				dest[name] = src[name];
2399
2400			}
2401
2402		}
2403
2404	}
2405
2406
2407
2408
2409
2410	function hasOwnProp(obj, name) {
2411
2412		return hasOwnPropMethod.call(obj, name);
2413
2414	}
2415
2416
2417
2418
2419
2420// Is the given value a non-object non-function value?
2421
2422	function isAtomic(val) {
2423
2424		return /undefined|null|boolean|number|string/.test($.type(val));
2425
2426	}
2427
2428
2429
2430
2431
2432	function applyAll(functions, thisObj, args) {
2433
2434		if ($.isFunction(functions)) {
2435
2436			functions = [ functions ];
2437
2438		}
2439
2440		if (functions) {
2441
2442			var i;
2443
2444			var ret;
2445
2446			for (i=0; i<functions.length; i++) {
2447
2448				ret = functions[i].apply(thisObj, args) || ret;
2449
2450			}
2451
2452			return ret;
2453
2454		}
2455
2456	}
2457
2458
2459
2460
2461
2462	function firstDefined() {
2463
2464		for (var i=0; i<arguments.length; i++) {
2465
2466			if (arguments[i] !== undefined) {
2467
2468				return arguments[i];
2469
2470			}
2471
2472		}
2473
2474	}
2475
2476
2477
2478
2479
2480	function htmlEscape(s) {
2481
2482		return (s + '').replace(/&/g, '&amp;')
2483
2484			.replace(/</g, '&lt;')
2485
2486			.replace(/>/g, '&gt;')
2487
2488			.replace(/'/g, '&#039;')
2489
2490			.replace(/"/g, '&quot;')
2491
2492			.replace(/\n/g, '<br />');
2493
2494	}
2495
2496
2497
2498
2499
2500	function stripHtmlEntities(text) {
2501
2502		return text.replace(/&.*?;/g, '');
2503
2504	}
2505
2506
2507
2508
2509
2510// Given a hash of CSS properties, returns a string of CSS.
2511
2512// Uses property names as-is (no camel-case conversion). Will not make statements for null/undefined values.
2513
2514	function cssToStr(cssProps) {
2515
2516		var statements = [];
2517
2518
2519
2520		$.each(cssProps, function(name, val) {
2521
2522			if (val != null) {
2523
2524				statements.push(name + ':' + val);
2525
2526			}
2527
2528		});
2529
2530
2531
2532		return statements.join(';');
2533
2534	}
2535
2536
2537
2538
2539
2540	function capitaliseFirstLetter(str) {
2541
2542		return str.charAt(0).toUpperCase() + str.slice(1);
2543
2544	}
2545
2546
2547
2548
2549
2550	function compareNumbers(a, b) { // for .sort()
2551
2552		return a - b;
2553
2554	}
2555
2556
2557
2558
2559
2560	function isInt(n) {
2561
2562		return n % 1 === 0;
2563
2564	}
2565
2566
2567
2568
2569
2570// Returns a method bound to the given object context.
2571
2572// Just like one of the jQuery.proxy signatures, but without the undesired behavior of treating the same method with
2573
2574// different contexts as identical when binding/unbinding events.
2575
2576	function proxy(obj, methodName) {
2577
2578		var method = obj[methodName];
2579
2580
2581
2582		return function() {
2583
2584			return method.apply(obj, arguments);
2585
2586		};
2587
2588	}
2589
2590
2591
2592
2593
2594// Returns a function, that, as long as it continues to be invoked, will not
2595
2596// be triggered. The function will be called after it stops being called for
2597
2598// N milliseconds.
2599
2600// https://github.com/jashkenas/underscore/blob/1.6.0/underscore.js#L714
2601
2602	function debounce(func, wait) {
2603
2604		var timeoutId;
2605
2606		var args;
2607
2608		var context;
2609
2610		var timestamp; // of most recent call
2611
2612		var later = function() {
2613
2614			var last = +new Date() - timestamp;
2615
2616			if (last < wait && last > 0) {
2617
2618				timeoutId = setTimeout(later, wait - last);
2619
2620			}
2621
2622			else {
2623
2624				timeoutId = null;
2625
2626				func.apply(context, args);
2627
2628				if (!timeoutId) {
2629
2630					context = args = null;
2631
2632				}
2633
2634			}
2635
2636		};
2637
2638
2639
2640		return function() {
2641
2642			context = this;
2643
2644			args = arguments;
2645
2646			timestamp = +new Date();
2647
2648			if (!timeoutId) {
2649
2650				timeoutId = setTimeout(later, wait);
2651
2652			}
2653
2654		};
2655
2656	}
2657
2658
2659
2660	;;
2661
2662
2663
2664	var ambigDateOfMonthRegex = /^\s*\d{4}-\d\d$/;
2665
2666	var ambigTimeOrZoneRegex =
2667
2668		/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/;
2669
2670	var newMomentProto = moment.fn; // where we will attach our new methods
2671
2672	var oldMomentProto = $.extend({}, newMomentProto); // copy of original moment methods
2673
2674	var allowValueOptimization;
2675
2676	var setUTCValues; // function defined below
2677
2678	var setLocalValues; // function defined below
2679
2680
2681
2682
2683
2684// Creating
2685
2686// -------------------------------------------------------------------------------------------------
2687
2688
2689
2690// Creates a new moment, similar to the vanilla moment(...) constructor, but with
2691
2692// extra features (ambiguous time, enhanced formatting). When given an existing moment,
2693
2694// it will function as a clone (and retain the zone of the moment). Anything else will
2695
2696// result in a moment in the local zone.
2697
2698	FC.moment = function() {
2699
2700		return makeMoment(arguments);
2701
2702	};
2703
2704
2705
2706// Sames as FC.moment, but forces the resulting moment to be in the UTC timezone.
2707
2708	FC.moment.utc = function() {
2709
2710		var mom = makeMoment(arguments, true);
2711
2712
2713
2714		// Force it into UTC because makeMoment doesn't guarantee it
2715
2716		// (if given a pre-existing moment for example)
2717
2718		if (mom.hasTime()) { // don't give ambiguously-timed moments a UTC zone
2719
2720			mom.utc();
2721
2722		}
2723
2724
2725
2726		return mom;
2727
2728	};
2729
2730
2731
2732// Same as FC.moment, but when given an ISO8601 string, the timezone offset is preserved.
2733
2734// ISO8601 strings with no timezone offset will become ambiguously zoned.
2735
2736	FC.moment.parseZone = function() {
2737
2738		return makeMoment(arguments, true, true);
2739
2740	};
2741
2742
2743
2744// Builds an enhanced moment from args. When given an existing moment, it clones. When given a
2745
2746// native Date, or called with no arguments (the current time), the resulting moment will be local.
2747
2748// Anything else needs to be "parsed" (a string or an array), and will be affected by:
2749
2750//    parseAsUTC - if there is no zone information, should we parse the input in UTC?
2751
2752//    parseZone - if there is zone information, should we force the zone of the moment?
2753
2754	function makeMoment(args, parseAsUTC, parseZone) {
2755
2756		var input = args[0];
2757
2758		var isSingleString = args.length == 1 && typeof input === 'string';
2759
2760		var isAmbigTime;
2761
2762		var isAmbigZone;
2763
2764		var ambigMatch;
2765
2766		var mom;
2767
2768
2769
2770		if (moment.isMoment(input)) {
2771
2772			mom = moment.apply(null, args); // clone it
2773
2774			transferAmbigs(input, mom); // the ambig flags weren't transfered with the clone
2775
2776		}
2777
2778		else if (isNativeDate(input) || input === undefined) {
2779
2780			mom = moment.apply(null, args); // will be local
2781
2782		}
2783
2784		else { // "parsing" is required
2785
2786			isAmbigTime = false;
2787
2788			isAmbigZone = false;
2789
2790
2791
2792			if (isSingleString) {
2793
2794				if (ambigDateOfMonthRegex.test(input)) {
2795
2796					// accept strings like '2014-05', but convert to the first of the month
2797
2798					input += '-01';
2799
2800					args = [ input ]; // for when we pass it on to moment's constructor
2801
2802					isAmbigTime = true;
2803
2804					isAmbigZone = true;
2805
2806				}
2807
2808				else if ((ambigMatch = ambigTimeOrZoneRegex.exec(input))) {
2809
2810					isAmbigTime = !ambigMatch[5]; // no time part?
2811
2812					isAmbigZone = true;
2813
2814				}
2815
2816			}
2817
2818			else if ($.isArray(input)) {
2819
2820				// arrays have no timezone information, so assume ambiguous zone
2821
2822				isAmbigZone = true;
2823
2824			}
2825
2826			// otherwise, probably a string with a format
2827
2828
2829
2830			if (parseAsUTC || isAmbigTime) {
2831
2832				mom = moment.utc.apply(moment, args);
2833
2834			}
2835
2836			else {
2837
2838				mom = moment.apply(null, args);
2839
2840			}
2841
2842
2843
2844			if (isAmbigTime) {
2845
2846				mom._ambigTime = true;
2847
2848				mom._ambigZone = true; // ambiguous time always means ambiguous zone
2849
2850			}
2851
2852			else if (parseZone) { // let's record the inputted zone somehow
2853
2854				if (isAmbigZone) {
2855
2856					mom._ambigZone = true;
2857
2858				}
2859
2860				else if (isSingleString) {
2861
2862					if (mom.utcOffset) {
2863
2864						mom.utcOffset(input); // if not a valid zone, will assign UTC
2865
2866					}
2867
2868					else {
2869
2870						mom.zone(input); // for moment-pre-2.9
2871
2872					}
2873
2874				}
2875
2876			}
2877
2878		}
2879
2880
2881
2882		mom._fullCalendar = true; // flag for extended functionality
2883
2884
2885
2886		return mom;
2887
2888	}
2889
2890
2891
2892
2893
2894// A clone method that works with the flags related to our enhanced functionality.
2895
2896// In the future, use moment.momentProperties
2897
2898	newMomentProto.clone = function() {
2899
2900		var mom = oldMomentProto.clone.apply(this, arguments);
2901
2902
2903
2904		// these flags weren't transfered with the clone
2905
2906		transferAmbigs(this, mom);
2907
2908		if (this._fullCalendar) {
2909
2910			mom._fullCalendar = true;
2911
2912		}
2913
2914
2915
2916		return mom;
2917
2918	};
2919
2920
2921
2922
2923
2924// Week Number
2925
2926// -------------------------------------------------------------------------------------------------
2927
2928
2929
2930
2931
2932// Returns the week number, considering the locale's custom week number calcuation
2933
2934// `weeks` is an alias for `week`
2935
2936	newMomentProto.week = newMomentProto.weeks = function(input) {
2937
2938		var weekCalc = (this._locale || this._lang) // works pre-moment-2.8
2939
2940			._fullCalendar_weekCalc;
2941
2942
2943
2944		if (input == null && typeof weekCalc === 'function') { // custom function only works for getter
2945
2946			return weekCalc(this);
2947
2948		}
2949
2950		else if (weekCalc === 'ISO') {
2951
2952			return oldMomentProto.isoWeek.apply(this, arguments); // ISO getter/setter
2953
2954		}
2955
2956
2957
2958		return oldMomentProto.week.apply(this, arguments); // local getter/setter
2959
2960	};
2961
2962
2963
2964
2965
2966// Time-of-day
2967
2968// -------------------------------------------------------------------------------------------------
2969
2970
2971
2972// GETTER
2973
2974// Returns a Duration with the hours/minutes/seconds/ms values of the moment.
2975
2976// If the moment has an ambiguous time, a duration of 00:00 will be returned.
2977
2978//
2979
2980// SETTER
2981
2982// You can supply a Duration, a Moment, or a Duration-like argument.
2983
2984// When setting the time, and the moment has an ambiguous time, it then becomes unambiguous.
2985
2986	newMomentProto.time = function(time) {
2987
2988
2989
2990		// Fallback to the original method (if there is one) if this moment wasn't created via FullCalendar.
2991
2992		// `time` is a generic enough method name where this precaution is necessary to avoid collisions w/ other plugins.
2993
2994		if (!this._fullCalendar) {
2995
2996			return oldMomentProto.time.apply(this, arguments);
2997
2998		}
2999
3000
3001
3002		if (time == null) { // getter
3003
3004			return moment.duration({
3005
3006				hours: this.hours(),
3007
3008				minutes: this.minutes(),
3009
3010				seconds: this.seconds(),
3011
3012				milliseconds: this.milliseconds()
3013
3014			});
3015
3016		}
3017
3018		else { // setter
3019
3020
3021
3022			this._ambigTime = false; // mark that the moment now has a time
3023
3024
3025
3026			if (!moment.isDuration(time) && !moment.isMoment(time)) {
3027
3028				time = moment.duration(time);
3029
3030			}
3031
3032
3033
3034			// The day value should cause overflow (so 24 hours becomes 00:00:00 of next day).
3035
3036			// Only for Duration times, not Moment times.
3037
3038			var dayHours = 0;
3039
3040			if (moment.isDuration(time)) {
3041
3042				dayHours = Math.floor(time.asDays()) * 24;
3043
3044			}
3045
3046
3047
3048			// We need to set the individual fields.
3049
3050			// Can't use startOf('day') then add duration. In case of DST at start of day.
3051
3052			return this.hours(dayHours + time.hours())
3053
3054				.minutes(time.minutes())
3055
3056				.seconds(time.seconds())
3057
3058				.milliseconds(time.milliseconds());
3059
3060		}
3061
3062	};
3063
3064
3065
3066// Converts the moment to UTC, stripping out its time-of-day and timezone offset,
3067
3068// but preserving its YMD. A moment with a stripped time will display no time
3069
3070// nor timezone offset when .format() is called.
3071
3072	newMomentProto.stripTime = function() {
3073
3074		var a;
3075
3076
3077
3078		if (!this._ambigTime) {
3079
3080
3081
3082			// get the values before any conversion happens
3083
3084			a = this.toArray(); // array of y/m/d/h/m/s/ms
3085
3086
3087
3088			// TODO: use keepLocalTime in the future
3089
3090			this.utc(); // set the internal UTC flag (will clear the ambig flags)
3091
3092			setUTCValues(this, a.slice(0, 3)); // set the year/month/date. time will be zero
3093
3094
3095
3096			// Mark the time as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
3097
3098			// which clears all ambig flags. Same with setUTCValues with moment-timezone.
3099
3100			this._ambigTime = true;
3101
3102			this._ambigZone = true; // if ambiguous time, also ambiguous timezone offset
3103
3104		}
3105
3106
3107
3108		return this; // for chaining
3109
3110	};
3111
3112
3113
3114// Returns if the moment has a non-ambiguous time (boolean)
3115
3116	newMomentProto.hasTime = function() {
3117
3118		return !this._ambigTime;
3119
3120	};
3121
3122
3123
3124
3125
3126// Timezone
3127
3128// -------------------------------------------------------------------------------------------------
3129
3130
3131
3132// Converts the moment to UTC, stripping out its timezone offset, but preserving its
3133
3134// YMD and time-of-day. A moment with a stripped timezone offset will display no
3135
3136// timezone offset when .format() is called.
3137
3138// TODO: look into Moment's keepLocalTime functionality
3139
3140	newMomentProto.stripZone = function() {
3141
3142		var a, wasAmbigTime;
3143
3144
3145
3146		if (!this._ambigZone) {
3147
3148
3149
3150			// get the values before any conversion happens
3151
3152			a = this.toArray(); // array of y/m/d/h/m/s/ms
3153
3154			wasAmbigTime = this._ambigTime;
3155
3156
3157
3158			this.utc(); // set the internal UTC flag (might clear the ambig flags, depending on Moment internals)
3159
3160			setUTCValues(this, a); // will set the year/month/date/hours/minutes/seconds/ms
3161
3162
3163
3164			// the above call to .utc()/.utcOffset() unfortunately might clear the ambig flags, so restore
3165
3166			this._ambigTime = wasAmbigTime || false;
3167
3168
3169
3170			// Mark the zone as ambiguous. This needs to happen after the .utc() call, which might call .utcOffset(),
3171
3172			// which clears the ambig flags. Same with setUTCValues with moment-timezone.
3173
3174			this._ambigZone = true;
3175
3176		}
3177
3178
3179
3180		return this; // for chaining
3181
3182	};
3183
3184
3185
3186// Returns of the moment has a non-ambiguous timezone offset (boolean)
3187
3188	newMomentProto.hasZone = function() {
3189
3190		return !this._ambigZone;
3191
3192	};
3193
3194
3195
3196
3197
3198// this method implicitly marks a zone
3199
3200	newMomentProto.local = function() {
3201
3202		var a = this.toArray(); // year,month,date,hours,minutes,seconds,ms as an array
3203
3204		var wasAmbigZone = this._ambigZone;
3205
3206
3207
3208		oldMomentProto.local.apply(this, arguments);
3209
3210
3211
3212		// ensure non-ambiguous
3213
3214		// this probably already happened via local() -> utcOffset(), but don't rely on Moment's internals
3215
3216		this._ambigTime = false;
3217
3218		this._ambigZone = false;
3219
3220
3221
3222		if (wasAmbigZone) {
3223
3224			// If the moment was ambiguously zoned, the date fields were stored as UTC.
3225
3226			// We want to preserve these, but in local time.
3227
3228			// TODO: look into Moment's keepLocalTime functionality
3229
3230			setLocalValues(this, a);
3231
3232		}
3233
3234
3235
3236		return this; // for chaining
3237
3238	};
3239
3240
3241
3242
3243
3244// implicitly marks a zone
3245
3246	newMomentProto.utc = function() {
3247
3248		oldMomentProto.utc.apply(this, arguments);
3249
3250
3251
3252		// ensure non-ambiguous
3253
3254		// this probably already happened via utc() -> utcOffset(), but don't rely on Moment's internals
3255
3256		this._ambigTime = false;
3257
3258		this._ambigZone = false;
3259
3260
3261
3262		return this;
3263
3264	};
3265
3266
3267
3268
3269
3270// methods for arbitrarily manipulating timezone offset.
3271
3272// should clear time/zone ambiguity when called.
3273
3274	$.each([
3275
3276		'zone', // only in moment-pre-2.9. deprecated afterwards
3277
3278		'utcOffset'
3279
3280	], function(i, name) {
3281
3282		if (oldMomentProto[name]) { // original method exists?
3283
3284
3285
3286			// this method implicitly marks a zone (will probably get called upon .utc() and .local())
3287
3288			newMomentProto[name] = function(tzo) {
3289
3290
3291
3292				if (tzo != null) { // setter
3293
3294					// these assignments needs to happen before the original zone method is called.
3295
3296					// I forget why, something to do with a browser crash.
3297
3298					this._ambigTime = false;
3299
3300					this._ambigZone = false;
3301
3302				}
3303
3304
3305
3306				return oldMomentProto[name].apply(this, arguments);
3307
3308			};
3309
3310		}
3311
3312	});
3313
3314
3315
3316
3317
3318// Formatting
3319
3320// -------------------------------------------------------------------------------------------------
3321
3322
3323
3324	newMomentProto.format = function() {
3325
3326		if (this._fullCalendar && arguments[0]) { // an enhanced moment? and a format string provided?
3327
3328			return formatDate(this, arguments[0]); // our extended formatting
3329
3330		}
3331
3332		if (this._ambigTime) {
3333
3334			return oldMomentFormat(this, 'YYYY-MM-DD');
3335
3336		}
3337
3338		if (this._ambigZone) {
3339
3340			return oldMomentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
3341
3342		}
3343
3344		return oldMomentProto.format.apply(this, arguments);
3345
3346	};
3347
3348
3349
3350	newMomentProto.toISOString = function() {
3351
3352		if (this._ambigTime) {
3353
3354			return oldMomentFormat(this, 'YYYY-MM-DD');
3355
3356		}
3357
3358		if (this._ambigZone) {
3359
3360			return oldMomentFormat(this, 'YYYY-MM-DD[T]HH:mm:ss');
3361
3362		}
3363
3364		return oldMomentProto.toISOString.apply(this, arguments);
3365
3366	};
3367
3368
3369
3370
3371
3372// Querying
3373
3374// -------------------------------------------------------------------------------------------------
3375
3376
3377
3378// Is the moment within the specified range? `end` is exclusive.
3379
3380// FYI, this method is not a standard Moment method, so always do our enhanced logic.
3381
3382	newMomentProto.isWithin = function(start, end) {
3383
3384		var a = commonlyAmbiguate([ this, start, end ]);
3385
3386		return a[0] >= a[1] && a[0] < a[2];
3387
3388	};
3389
3390
3391
3392// When isSame is called with units, timezone ambiguity is normalized before the comparison happens.
3393
3394// If no units specified, the two moments must be identically the same, with matching ambig flags.
3395
3396	newMomentProto.isSame = function(input, units) {
3397
3398		var a;
3399
3400
3401
3402		// only do custom logic if this is an enhanced moment
3403
3404		if (!this._fullCalendar) {
3405
3406			return oldMomentProto.isSame.apply(this, arguments);
3407
3408		}
3409
3410
3411
3412		if (units) {
3413
3414			a = commonlyAmbiguate([ this, input ], true); // normalize timezones but don't erase times
3415
3416			return oldMomentProto.isSame.call(a[0], a[1], units);
3417
3418		}
3419
3420		else {
3421
3422			input = FC.moment.parseZone(input); // normalize input
3423
3424			return oldMomentProto.isSame.call(this, input) &&
3425
3426				Boolean(this._ambigTime) === Boolean(input._ambigTime) &&
3427
3428				Boolean(this._ambigZone) === Boolean(input._ambigZone);
3429
3430		}
3431
3432	};
3433
3434
3435
3436// Make these query methods work with ambiguous moments
3437
3438	$.each([
3439
3440		'isBefore',
3441
3442		'isAfter'
3443
3444	], function(i, methodName) {
3445
3446		newMomentProto[methodName] = function(input, units) {
3447
3448			var a;
3449
3450
3451
3452			// only do custom logic if this is an enhanced moment
3453
3454			if (!this._fullCalendar) {
3455
3456				return oldMomentProto[methodName].apply(this, arguments);
3457
3458			}
3459
3460
3461
3462			a = commonlyAmbiguate([ this, input ]);
3463
3464			return oldMomentProto[methodName].call(a[0], a[1], units);
3465
3466		};
3467
3468	});
3469
3470
3471
3472
3473
3474// Misc Internals
3475
3476// -------------------------------------------------------------------------------------------------
3477
3478
3479
3480// given an array of moment-like inputs, return a parallel array w/ moments similarly ambiguated.
3481
3482// for example, of one moment has ambig time, but not others, all moments will have their time stripped.
3483
3484// set `preserveTime` to `true` to keep times, but only normalize zone ambiguity.
3485
3486// returns the original moments if no modifications are necessary.
3487
3488	function commonlyAmbiguate(inputs, preserveTime) {
3489
3490		var anyAmbigTime = false;
3491
3492		var anyAmbigZone = false;
3493
3494		var len = inputs.length;
3495
3496		var moms = [];
3497
3498		var i, mom;
3499
3500
3501
3502		// parse inputs into real moments and query their ambig flags
3503
3504		for (i = 0; i < len; i++) {
3505
3506			mom = inputs[i];
3507
3508			if (!moment.isMoment(mom)) {
3509
3510				mom = FC.moment.parseZone(mom);
3511
3512			}
3513
3514			anyAmbigTime = anyAmbigTime || mom._ambigTime;
3515
3516			anyAmbigZone = anyAmbigZone || mom._ambigZone;
3517
3518			moms.push(mom);
3519
3520		}
3521
3522
3523
3524		// strip each moment down to lowest common ambiguity
3525
3526		// use clones to avoid modifying the original moments
3527
3528		for (i = 0; i < len; i++) {
3529
3530			mom = moms[i];
3531
3532			if (!preserveTime && anyAmbigTime && !mom._ambigTime) {
3533
3534				moms[i] = mom.clone().stripTime();
3535
3536			}
3537
3538			else if (anyAmbigZone && !mom._ambigZone) {
3539
3540				moms[i] = mom.clone().stripZone();
3541
3542			}
3543
3544		}
3545
3546
3547
3548		return moms;
3549
3550	}
3551
3552
3553
3554// Transfers all the flags related to ambiguous time/zone from the `src` moment to the `dest` moment
3555
3556// TODO: look into moment.momentProperties for this.
3557
3558	function transferAmbigs(src, dest) {
3559
3560		if (src._ambigTime) {
3561
3562			dest._ambigTime = true;
3563
3564		}
3565
3566		else if (dest._ambigTime) {
3567
3568			dest._ambigTime = false;
3569
3570		}
3571
3572
3573
3574		if (src._ambigZone) {
3575
3576			dest._ambigZone = true;
3577
3578		}
3579
3580		else if (dest._ambigZone) {
3581
3582			dest._ambigZone = false;
3583
3584		}
3585
3586	}
3587
3588
3589
3590
3591
3592// Sets the year/month/date/etc values of the moment from the given array.
3593
3594// Inefficient because it calls each individual setter.
3595
3596	function setMomentValues(mom, a) {
3597
3598		mom.year(a[0] || 0)
3599
3600			.month(a[1] || 0)
3601
3602			.date(a[2] || 0)
3603
3604			.hours(a[3] || 0)
3605
3606			.minutes(a[4] || 0)
3607
3608			.seconds(a[5] || 0)
3609
3610			.milliseconds(a[6] || 0);
3611
3612	}
3613
3614
3615
3616// Can we set the moment's internal date directly?
3617
3618	allowValueOptimization = '_d' in moment() && 'updateOffset' in moment;
3619
3620
3621
3622// Utility function. Accepts a moment and an array of the UTC year/month/date/etc values to set.
3623
3624// Assumes the given moment is already in UTC mode.
3625
3626	setUTCValues = allowValueOptimization ? function(mom, a) {
3627
3628		// simlate what moment's accessors do
3629
3630		mom._d.setTime(Date.UTC.apply(Date, a));
3631
3632		moment.updateOffset(mom, false); // keepTime=false
3633
3634	} : setMomentValues;
3635
3636
3637
3638// Utility function. Accepts a moment and an array of the local year/month/date/etc values to set.
3639
3640// Assumes the given moment is already in local mode.
3641
3642	setLocalValues = allowValueOptimization ? function(mom, a) {
3643
3644		// simlate what moment's accessors do
3645
3646		mom._d.setTime(+new Date( // FYI, there is now way to apply an array of args to a constructor
3647
3648			a[0] || 0,
3649
3650			a[1] || 0,
3651
3652			a[2] || 0,
3653
3654			a[3] || 0,
3655
3656			a[4] || 0,
3657
3658			a[5] || 0,
3659
3660			a[6] || 0
3661
3662		));
3663
3664		moment.updateOffset(mom, false); // keepTime=false
3665
3666	} : setMomentValues;
3667
3668
3669
3670	;;
3671
3672
3673
3674// Single Date Formatting
3675
3676// -------------------------------------------------------------------------------------------------
3677
3678
3679
3680
3681
3682// call this if you want Moment's original format method to be used
3683
3684	function oldMomentFormat(mom, formatStr) {
3685
3686		return oldMomentProto.format.call(mom, formatStr); // oldMomentProto defined in moment-ext.js
3687
3688	}
3689
3690
3691
3692
3693
3694// Formats `date` with a Moment formatting string, but allow our non-zero areas and
3695
3696// additional token.
3697
3698	function formatDate(date, formatStr) {
3699
3700		return formatDateWithChunks(date, getFormatStringChunks(formatStr));
3701
3702	}
3703
3704
3705
3706
3707
3708	function formatDateWithChunks(date, chunks) {
3709
3710		var s = '';
3711
3712		var i;
3713
3714
3715
3716		for (i=0; i<chunks.length; i++) {
3717
3718			s += formatDateWithChunk(date, chunks[i]);
3719
3720		}
3721
3722
3723
3724		return s;
3725
3726	}
3727
3728
3729
3730
3731
3732// addition formatting tokens we want recognized
3733
3734	var tokenOverrides = {
3735
3736		t: function(date) { // "a" or "p"
3737
3738			return oldMomentFormat(date, 'a').charAt(0);
3739
3740		},
3741
3742		T: function(date) { // "A" or "P"
3743
3744			return oldMomentFormat(date, 'A').charAt(0);
3745
3746		}
3747
3748	};
3749
3750
3751
3752
3753
3754	function formatDateWithChunk(date, chunk) {
3755
3756		var token;
3757
3758		var maybeStr;
3759
3760
3761
3762		if (typeof chunk === 'string') { // a literal string
3763
3764			return chunk;
3765
3766		}
3767
3768		else if ((token = chunk.token)) { // a token, like "YYYY"
3769
3770			if (tokenOverrides[token]) {
3771
3772				return tokenOverrides[token](date); // use our custom token
3773
3774			}
3775
3776			return oldMomentFormat(date, token);
3777
3778		}
3779
3780		else if (chunk.maybe) { // a grouping of other chunks that must be non-zero
3781
3782			maybeStr = formatDateWithChunks(date, chunk.maybe);
3783
3784			if (maybeStr.match(/[1-9]/)) {
3785
3786				return maybeStr;
3787
3788			}
3789
3790		}
3791
3792
3793
3794		return '';
3795
3796	}
3797
3798
3799
3800
3801
3802// Date Range Formatting
3803
3804// -------------------------------------------------------------------------------------------------
3805
3806// TODO: make it work with timezone offset
3807
3808
3809
3810// Using a formatting string meant for a single date, generate a range str
3810ing, like
3811
3812// "Sep 2 - 9 2013", that intelligently inserts a separator where the dates differ.
3813
3814// If the dates are the same as far as the format string is concerned, just return a single
3815
3816// rendering of one date, without any separator.
3817
3818	function formatRange(date1, date2, formatStr, separator, isRTL) {
3819
3820		var localeData;
3821
3822
3823
3824		date1 = FC.moment.parseZone(date1);
3825
3826		date2 = FC.moment.parseZone(date2);
3827
3828
3829
3830		localeData = (date1.localeData || date1.lang).call(date1); // works with moment-pre-2.8
3831
3832
3833
3834		// Expand localized format strings, like "LL" -> "MMMM D YYYY"
3835
3836		formatStr = localeData.longDateFormat(formatStr) || formatStr;
3837
3838		// BTW, this is not important for `formatDate` because it is impossible to put custom tokens
3839
3840		// or non-zero areas in Moment's localized format strings.
3841
3842
3843
3844		separator = separator || ' - ';
3845
3846
3847
3848		return formatRangeWithChunks(
3849
3850			date1,
3851
3852			date2,
3853
3854			getFormatStringChunks(formatStr),
3855
3856			separator,
3857
3858			isRTL
3859
3860		);
3861
3862	}
3863
3864	FC.formatRange = formatRange; // expose
3865
3866
3867
3868
3869
3870	function formatRangeWithChunks(date1, date2, chunks, separator, isRTL) {
3871
3872		var unzonedDate1 = date1.clone().stripZone(); // for formatSimilarChunk
3873
3874		var unzonedDate2 = date2.clone().stripZone(); // "
3875
3876		var chunkStr; // the rendering of the chunk
3877
3878		var leftI;
3879
3880		var leftStr = '';
3881
3882		var rightI;
3883
3884		var rightStr = '';
3885
3886		var middleI;
3887
3888		var middleStr1 = '';
3889
3890		var middleStr2 = '';
3891
3892		var middleStr = '';
3893
3894
3895
3896		// Start at the leftmost side of the formatting string and continue until you hit a token
3897
3898		// that is not the same between dates.
3899
3900		for (leftI=0; leftI<chunks.length; leftI++) {
3901
3902			chunkStr = formatSimilarChunk(date1, date2, unzonedDate1, unzonedDate2, chunks[leftI]);
3903
3904			if (chunkStr === false) {
3905
3906				break;
3907
3908			}
3909
3910			leftStr += chunkStr;
3911
3912		}
3913
3914
3915
3916		// Similarly, start at the rightmost side of the formatting string and move left
3917
3918		for (rightI=chunks.length-1; rightI>leftI; rightI--) {
3919
3920			chunkStr = formatSimilarChunk(date1, date2, unzonedDate1, unzonedDate2,  chunks[rightI]);
3921
3922			if (chunkStr === false) {
3923
3924				break;
3925
3926			}
3927
3928			rightStr = chunkStr + rightStr;
3929
3930		}
3931
3932
3933
3934		// The area in the middle is different for both of the dates.
3935
3936		// Collect them distinctly so we can jam them together later.
3937
3938		for (middleI=leftI; middleI<=rightI; middleI++) {
3939
3940			middleStr1 += formatDateWithChunk(date1, chunks[middleI]);
3941
3942			middleStr2 += formatDateWithChunk(date2, chunks[middleI]);
3943
3944		}
3945
3946
3947
3948		if (middleStr1 || middleStr2) {
3949
3950			if (isRTL) {
3951
3952				middleStr = middleStr2 + separator + middleStr1;
3953
3954			}
3955
3956			else {
3957
3958				middleStr = middleStr1 + separator + middleStr2;
3959
3960			}
3961
3962		}
3963
3964
3965
3966		return leftStr + middleStr + rightStr;
3967
3968	}
3969
3970
3971
3972
3973
3974	var similarUnitMap = {
3975
3976		Y: 'year',
3977
3978		M: 'month',
3979
3980		D: 'day', // day of month
3981
3982		d: 'day', // day of week
3983
3984		// prevents a separator between anything time-related...
3985
3986		A: 'second', // AM/PM
3987
3988		a: 'second', // am/pm
3989
3990		T: 'second', // A/P
3991
3992		t: 'second', // a/p
3993
3994		H: 'second', // hour (24)
3995
3996		h: 'second', // hour (12)
3997
3998		m: 'second', // minute
3999
4000		s: 'second' // second
4001
4002	};
4003
4004// TODO: week maybe?
4005
4006
4007
4008
4009
4010// Given a formatting chunk, and given that both dates are similar in the regard the
4011
4012// formatting chunk is concerned, format date1 against `chunk`. Otherwise, return `false`.
4013
4014	function formatSimilarChunk(date1, date2, unzonedDate1, unzonedDate2, chunk) {
4015
4016		var token;
4017
4018		var unit;
4019
4020
4021
4022		if (typeof chunk === 'string') { // a literal string
4023
4024			return chunk;
4025
4026		}
4027
4028		else if ((token = chunk.token)) {
4029
4030			unit = similarUnitMap[token.charAt(0)];
4031
4032
4033
4034			// are the dates the same for this unit of measurement?
4035
4036			// use the unzoned dates for this calculation because unreliable when near DST (bug #2396)
4037
4038			if (unit && unzonedDate1.isSame(unzonedDate2, unit)) {
4039
4040				return oldMomentFormat(date1, token); // would be the same if we used `date2`
4041
4042				// BTW, don't support custom tokens
4043
4044			}
4045
4046		}
4047
4048
4049
4050		return false; // the chunk is NOT the same for the two dates
4051
4052		// BTW, don't support splitting on non-zero areas
4053
4054	}
4055
4056
4057
4058
4059
4060// Chunking Utils
4061
4062// -------------------------------------------------------------------------------------------------
4063
4064
4065
4066
4067
4068	var formatStringChunkCache = {};
4069
4070
4071
4072
4073
4074	function getFormatStringChunks(formatStr) {
4075
4076		if (formatStr in formatStringChunkCache) {
4077
4078			return formatStringChunkCache[formatStr];
4079
4080		}
4081
4082		return (formatStringChunkCache[formatStr] = chunkFormatString(formatStr));
4083
4084	}
4085
4086
4087
4088
4089
4090// Break the formatting string into an array of chunks
4091
4092	function chunkFormatString(formatStr) {
4093
4094		var chunks = [];
4095
4096		var chunker = /\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g; // TODO: more descrimination
4097
4098		var match;
4099
4100
4101
4102		while ((match = chunker.exec(formatStr))) {
4103
4104			if (match[1]) { // a literal string inside [ ... ]
4105
4106				chunks.push(match[1]);
4107
4108			}
4109
4110			else if (match[2]) { // non-zero formatting inside ( ... )
4111
4112				chunks.push({ maybe: chunkFormatString(match[2]) });
4113
4114			}
4115
4116			else if (match[3]) { // a formatting token
4117
4118				chunks.push({ token: match[3] });
4119
4120			}
4121
4122			else if (match[5]) { // an unenclosed literal string
4123
4124				chunks.push(match[5]);
4125
4126			}
4127
4128		}
4129
4130
4131
4132		return chunks;
4133
4134	}
4135
4136
4137
4138	;;
4139
4140
4141
4142	FC.Class = Class; // export
4143
4144
4145
4146// Class that all other classes will inherit from
4147
4148	function Class() { }
4149
4150
4151
4152
4153
4154// Called on a class to create a subclass.
4155
4156// Last argument contains instance methods. Any argument before the last are considered mixins.
4157
4158	Class.extend = function() {
4159
4160		var len = arguments.length;
4161
4162		var i;
4163
4164		var members;
4165
4166
4167
4168		for (i = 0; i < len; i++) {
4169
4170			members = arguments[i];
4171
4172			if (i < len - 1) { // not the last argument?
4173
4174				mixIntoClass(this, members);
4175
4176			}
4177
4178		}
4179
4180
4181
4182		return extendClass(this, members || {}); // members will be undefined if no arguments
4183
4184	};
4185
4186
4187
4188
4189
4190// Adds new member variables/methods to the class's prototype.
4191
4192// Can be called with another class, or a plain object hash containing new members.
4193
4194	Class.mixin = function(members) {
4195
4196		mixIntoClass(this, members);
4197
4198	};
4199
4200
4201
4202
4203
4204	function extendClass(superClass, members) {
4205
4206		var subClass;
4207
4208
4209
4210		// ensure a constructor for the subclass, forwarding all arguments to the super-constructor if it doesn't exist
4211
4212		if (hasOwnProp(members, 'constructor')) {
4213
4214			subClass = members.constructor;
4215
4216		}
4217
4218		if (typeof subClass !== 'function') {
4219
4220			subClass = members.constructor = function() {
4221
4222				superClass.apply(this, arguments);
4223
4224			};
4225
4226		}
4227
4228
4229
4230		// build the base prototype for the subclass, which is an new object chained to the superclass's prototype
4231
4232		subClass.prototype = createObject(superClass.prototype);
4233
4234
4235
4236		// copy each member variable/method onto the the subclass's prototype
4237
4238		copyOwnProps(members, subClass.prototype);
4239
4240		copyNativeMethods(members, subClass.prototype); // hack for IE8
4241
4242
4243
4244		// copy over all class variables/methods to the subclass, such as `extend` and `mixin`
4245
4246		copyOwnProps(superClass, subClass);
4247
4248
4249
4250		return subClass;
4251
4252	}
4253
4254
4255
4256
4257
4258	function mixIntoClass(theClass, members) {
4259
4260		copyOwnProps(members.prototype || members, theClass.prototype); // TODO: copyNativeMethods?
4261
4262	}
4263
4264	;;
4265
4266
4267
4268	var Emitter = FC.Emitter = Class.extend({
4269
4270
4271
4272		callbackHash: null,
4273
4274
4275
4276
4277
4278		on: function(name, callback) {
4279
4280			this.getCallbacks(name).add(callback);
4281
4282			return this; // for chaining
4283
4284		},
4285
4286
4287
4288
4289
4290		off: function(name, callback) {
4291
4292			this.getCallbacks(name).remove(callback);
4293
4294			return this; // for chaining
4295
4296		},
4297
4298
4299
4300
4301
4302		trigger: function(name) { // args...
4303
4304			var args = Array.prototype.slice.call(arguments, 1);
4305
4306
4307
4308			this.triggerWith(name, this, args);
4309
4310
4311
4312			return this; // for chaining
4313
4314		},
4315
4316
4317
4318
4319
4320		triggerWith: function(name, context, args) {
4321
4322			var callbacks = this.getCallbacks(name);
4323
4324
4325
4326			callbacks.fireWith(context, args);
4327
4328
4329
4330			return this; // for chaining
4331
4332		},
4333
4334
4335
4336
4337
4338		getCallbacks: function(name) {
4339
4340			var callbacks;
4341
4342
4343
4344			if (!this.callbackHash) {
4345
4346				this.callbackHash = {};
4347
4348			}
4349
4350
4351
4352			callbacks = this.callbackHash[name];
4353
4354			if (!callbacks) {
4355
4356				callbacks = this.callbackHash[name] = $.Callbacks();
4357
4358			}
4359
4360
4361
4362			return callbacks;
4363
4364		}
4365
4366
4367
4368	});
4369
4370	;;
4371
4372
4373
4374	/* A rectangular panel that is absolutely positioned over other content
4375
4376	 ------------------------------------------------------------------------------------------------------------------------
4377
4378	 Options:
4379
4380	 - className (string)
4381
4382	 - content (HTML string or jQuery element set)
4383
4384	 - parentEl
4385
4386	 - top
4387
4388	 - left
4389
4390	 - right (the x coord of where the right edge should be. not a "CSS" right)
4391
4392	 - autoHide (boolean)
4393
4394	 - show (callback)
4395
4396	 - hide (callback)
4397
4398	 */
4399
4400
4401
4402	var Popover = Class.extend({
4403
4404
4405
4406		isHidden: true,
4407
4408		options: null,
4409
4410		el: null, // the container element for the popover. generated by this object
4411
4412		documentMousedownProxy: null, // document mousedown handler bound to `this`
4413
4414		margin: 10, // the space required between the popover and the edges of the scroll container
4415
4416
4417
4418
4419
4420		constructor: function(options) {
4421
4422			this.options = options || {};
4423
4424		},
4425
4426
4427
4428
4429
4430		// Shows the popover on the specified position. Renders it if not already
4431
4432		show: function() {
4433
4434			if (this.isHidden) {
4435
4436				if (!this.el) {
4437
4438					this.render();
4439
4440				}
4441
4442				this.el.show();
4443
4444				this.position();
4445
4446				this.isHidden = false;
4447
4448				this.trigger('show');
4449
4450			}
4451
4452		},
4453
4454
4455
4456
4457
4458		// Hides the popover, through CSS, but does not remove it from the DOM
4459
4460		hide: function() {
4461
4462			if (!this.isHidden) {
4463
4464				this.el.hide();
4465
4466				this.isHidden = true;
4467
4468				this.trigger('hide');
4469
4470			}
4471
4472		},
4473
4474
4475
4476
4477
4478		// Creates `this.el` and renders content inside of it
4479
4480		render: function() {
4481
4482			var _this = this;
4483
4484			var options = this.options;
4485
4486
4487
4488			this.el = $('<div class="fc-popover"/>')
4489
4490				.addClass(options.className || '')
4491
4492				.css({
4493
4494					// position initially to the top left to avoid creating scrollbars
4495
4496					top: 0,
4497
4498					left: 0
4499
4500				})
4501
4502				.append(options.content)
4503
4504				.appendTo(options.parentEl);
4505
4506
4507
4508			// when a click happens on anything inside with a 'fc-close' className, hide the popover
4509
4510			this.el.on('click', '.fc-close', function() {
4511
4512				_this.hide();
4513
4514			});
4515
4516
4517
4518			if (options.autoHide) {
4519
4520				$(document).on('mousedown', this.documentMousedownProxy = proxy(this, 'documentMousedown'));
4521
4522			}
4523
4524		},
4525
4526
4527
4528
4529
4530		// Triggered when the user clicks *anywhere* in the document, for the autoHide feature
4531
4532		documentMousedown: function(ev) {
4533
4534			// only hide the popover if the click happened outside the popover
4535
4536			if (this.el && !$(ev.target).closest(this.el).length) {
4537
4538				this.hide();
4539
4540			}
4541
4542		},
4543
4544
4545
4546
4547
4548		// Hides and unregisters any handlers
4549
4550		removeElement: function() {
4551
4552			this.hide();
4553
4554
4555
4556			if (this.el) {
4557
4558				this.el.remove();
4559
4560				this.el = null;
4561
4562			}
4563
4564
4565
4566			$(document).off('mousedown', this.documentMousedownProxy);
4567
4568		},
4569
4570
4571
4572
4573
4574		// Positions the popover optimally, using the top/left/right options
4575
4576		position: function() {
4577
4578			var options = this.options;
4579
4580			var origin = this.el.offsetParent().offset();
4581
4582			var width = this.el.outerWidth();
4583
4584			var height = this.el.outerHeight();
4585
4586			var windowEl = $(window);
4587
4588			var viewportEl = getScrollParent(this.el);
4589
4590			var viewportTop;
4591
4592			var viewportLeft;
4593
4594			var viewportOffset;
4595
4596			var top; // the "position" (not "offset") values for the popover
4597
4598			var left; //
4599
4600
4601
4602			// compute top and left
4603
4604			top = options.top || 0;
4605
4606			if (options.left !== undefined) {
4607
4608				left = options.left;
4609
4610			}
4611
4612			else if (options.right !== undefined) {
4613
4614				left = options.right - width; // derive the left value from the right value
4615
4616			}
4617
4618			else {
4619
4620				left = 0;
4621
4622			}
4623
4624
4625
4626			if (viewportEl.is(window) || viewportEl.is(document)) { // normalize getScrollParent's result
4627
4628				viewportEl = windowEl;
4629
4630				viewportTop = 0; // the window is always at the top left
4631
4632				viewportLeft = 0; // (and .offset() won't work if called here)
4633
4634			}
4635
4636			else {
4637
4638				viewportOffset = viewportEl.offset();
4639
4640				viewportTop = viewportOffset.top;
4641
4642				viewportLeft = viewportOffset.left;
4643
4644			}
4645
4646
4647
4648			// if the window is scrolled, it causes the visible area to be further down
4649
4650			viewportTop += windowEl.scrollTop();
4651
4652			viewportLeft += windowEl.scrollLeft();
4653
4654
4655
4656			// constrain to the view port. if constrained by two edges, give precedence to top/left
4657
4658			if (options.viewportConstrain !== false) {
4659
4660				top = Math.min(top, viewportTop + viewportEl.outerHeight() - height - this.margin);
4661
4662				top = Math.max(top, viewportTop + this.margin);
4663
4664				left = Math.min(left, viewportLeft + viewportEl.outerWidth() - width - this.margin);
4665
4666				left = Math.max(left, viewportLeft + this.margin);
4667
4668			}
4669
4670
4671
4672			this.el.css({
4673
4674				top: top - origin.top,
4675
4676				left: left - origin.left
4677
4678			});
4679
4680		},
4681
4682
4683
4684
4685
4686		// Triggers a callback. Calls a function in the option hash of the same name.
4687
4688		// Arguments beyond the first `name` are forwarded on.
4689
4690		// TODO: better code reuse for this. Repeat code
4691
4692		trigger: function(name) {
4693
4694			if (this.options[name]) {
4695
4696				this.options[name].apply(this, Array.prototype.slice.call(arguments, 1));
4697
4698			}
4699
4700		}
4701
4702
4703
4704	});
4705
4706
4707
4708	;;
4709
4710
4711
4712	/*
4713
4714	 A cache for the left/right/top/bottom/width/height values for one or more elements.
4715
4716	 Works with both offset (from topleft document) and position (from offsetParent).
4717
4718
4719
4720	 options:
4721
4722	 - els
4723
4724	 - isHorizontal
4725
4726	 - isVertical
4727
4728	 */
4729
4730	var CoordCache = FC.CoordCache = Class.extend({
4731
4732
4733
4734		els: null, // jQuery set (assumed to be siblings)
4735
4736		forcedOffsetParentEl: null, // options can override the natural offsetParent
4737
4738		origin: null, // {left,top} position of offsetParent of els
4739
4740		boundingRect: null, // constrain cordinates to this rectangle. {left,right,top,bottom} or null
4741
4742		isHorizontal: false, // whether to query for left/right/width
4743
4744		isVertical: false, // whether to query for top/bottom/height
4745
4746
4747
4748		// arrays of coordinates (offsets from topleft of document)
4749
4750		lefts: null,
4751
4752		rights: null,
4753
4754		tops: null,
4755
4756		bottoms: null,
4757
4758
4759
4760
4761
4762		constructor: function(options) {
4763
4764			this.els = $(options.els);
4765
4766			this.isHorizontal = options.isHorizontal;
4767
4768			this.isVertical = options.isVertical;
4769
4770			this.forcedOffsetParentEl = options.offsetParent ? $(options.offsetParent) : null;
4771
4772		},
4773
4774
4775
4776
4777
4778		// Queries the els for coordinates and stores them.
4779
4780		// Call this method before using and of the get* methods below.
4781
4782		build: function() {
4783
4784			var offsetParentEl = this.forcedOffsetParentEl || this.els.eq(0).offsetParent();
4785
4786
4787
4788			this.origin = offsetParentEl.offset();
4789
4790			this.boundingRect = this.queryBoundingRect();
4791
4792
4793
4794			if (this.isHorizontal) {
4795
4796				this.buildElHorizontals();
4797
4798			}
4799
4800			if (this.isVertical) {
4801
4802				this.buildElVerticals();
4803
4804			}
4805
4806		},
4807
4808
4809
4810
4811
4812		// Destroys all internal data about coordinates, freeing memory
4813
4814		clear: function() {
4815
4816			this.origin = null;
4817
4818			this.boundingRect = null;
4819
4820			this.lefts = null;
4821
4822			this.rights = null;
4823
4824			this.tops = null;
4825
4826			this.bottoms = null;
4827
4828		},
4829
4830
4831
4832
4833
4834		// Compute and return what the elements' bounding rectangle is, from the user's perspective.
4835
4836		// Right now, only returns a rectangle if constrained by an overflow:scroll element.
4837
4838		queryBoundingRect: function() {
4839
4840			var scrollParentEl = getScrollParent(this.els.eq(0));
4841
4842
4843
4844			if (!scrollParentEl.is(document)) {
4845
4846				return getClientRect(scrollParentEl);
4847
4848			}
4849
4850		},
4851
4852
4853
4854
4855
4856		// Populates the left/right internal coordinate arrays
4857
4858		buildElHorizontals: function() {
4859
4860			var lefts = [];
4861
4862			var rights = [];
4863
4864
4865
4866			this.els.each(function(i, node) {
4867
4868				var el = $(node);
4869
4870				var left = el.offset().left;
4871
4872				var width = el.outerWidth();
4873
4874
4875
4876				lefts.push(left);
4877
4878				rights.push(left + width);
4879
4880			});
4881
4882
4883
4884			this.lefts = lefts;
4885
4886			this.rights = rights;
4887
4888		},
4889
4890
4891
4892
4893
4894		// Populates the top/bottom internal coordinate arrays
4895
4896		buildElVerticals: function() {
4897
4898			var tops = [];
4899
4900			var bottoms = [];
4901
4902
4903
4904			this.els.each(function(i, node) {
4905
4906				var el = $(node);
4907
4908				var top = el.offset().top;
4909
4910				var height = el.outerHeight();
4911
4912
4913
4914				tops.push(top);
4915
4916				bottoms.push(top + height);
4917
4918			});
4919
4920
4921
4922			this.tops = tops;
4923
4924			this.bottoms = bottoms;
4925
4926		},
4927
4928
4929
4930
4931
4932		// Given a left offset (from document left), returns the index of the el that it horizontally intersects.
4933
4934		// If no intersection is made, or outside of the boundingRect, returns undefined.
4935
4936		getHorizontalIndex: function(leftOffset) {
4937
4938			var boundingRect = this.boundingRect;
4939
4940			var lefts = this.lefts;
4941
4942			var rights = this.rights;
4943
4944			var len = lefts.length;
4945
4946			var i;
4947
4948
4949
4950			if (!boundingRect || (leftOffset >= boundingRect.left && leftOffset < boundingRect.right)) {
4951
4952				for (i = 0; i < len; i++) {
4953
4954					if (leftOffset >= lefts[i] && leftOffset < rights[i]) {
4955
4956						return i;
4957
4958					}
4959
4960				}
4961
4962			}
4963
4964		},
4965
4966
4967
4968
4969
4970		// Given a top offset (from document top), returns the index of the el that it vertically intersects.
4971
4972		// If no intersection is made, or outside of the boundingRect, returns undefined.
4973
4974		getVerticalIndex: function(topOffset) {
4975
4976			var boundingRect = this.boundingRect;
4977
4978			var tops = this.tops;
4979
4980			var bottoms = this.bottoms;
4981
4982			var len = tops.length;
4983
4984			var i;
4985
4986
4987
4988			if (!boundingRect || (topOffset >= boundingRect.top && topOffset < boundingRect.bottom)) {
4989
4990				for (i = 0; i < len; i++) {
4991
4992					if (topOffset >= tops[i] && topOffset < bottoms[i]) {
4993
4994						return i;
4995
4996					}
4997
4998				}
4999
5000			}
5001
5002		},
5003
5004
5005
5006
5007
5008		// Gets the left offset (from document left) of the element at the given index
5009
5010		getLeftOffset: function(leftIndex) {
5011
5012			return this.lefts[leftIndex];
5013
5014		},
5015
5016
5017
5018
5019
5020		// Gets the left position (from offsetParent left) of the element at the given index
5021
5022		getLeftPosition: function(leftIndex) {
5023
5024			return this.lefts[leftIndex] - this.origin.left;
5025
5026		},
5027
5028
5029
5030
5031
5032		// Gets the right offset (from document left) of the element at the given index.
5033
5034		// This value is NOT relative to the document's right edge, like the CSS concept of "right" would be.
5035
5036		getRightOffset: function(leftIndex) {
5037
5038			return this.rights[leftIndex];
5039
5040		},
5041
5042
5043
5044
5045
5046		// Gets the right position (from offsetParent left) of the element at the given index.
5047
5048		// This value is NOT relative to the offsetParent's right edge, like the CSS concept of "right" would be.
5049
5050		getRightPosition: function(leftIndex) {
5051
5052			return this.rights[leftIndex] - this.origin.left;
5053
5054		},
5055
5056
5057
5058
5059
5060		// Gets the width of the element at the given index
5061
5062		getWidth: function(leftIndex) {
5063
5064			return this.rights[leftIndex] - this.lefts[leftIndex];
5065
5066		},
5067
5068
5069
5070
5071
5072		// Gets the top offset (from document top) of the element at the given index
5073
5074		getTopOffset: function(topIndex) {
5075
5076			return this.tops[topIndex];
5077
5078		},
5079
5080
5081
5082
5083
5084		// Gets the top position (from offsetParent top) of the element at the given position
5085
5086		getTopPosition: function(topIndex) {
5087
5088			return this.tops[topIndex] - this.origin.top;
5089
5090		},
5091
5092
5093
5094		// Gets the bottom offset (from the document top) of the element at the given index.
5095
5096		// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
5097
5098		getBottomOffset: function(topIndex) {
5099
5100			return this.bottoms[topIndex];
5101
5102		},
5103
5104
5105
5106
5107
5108		// Gets the bottom position (from the offsetParent top) of the element at the given index.
5109
5110		// This value is NOT relative to the offsetParent's bottom edge, like the CSS concept of "bottom" would be.
5111
5112		getBottomPosition: function(topIndex) {
5113
5114			return this.bottoms[topIndex] - this.origin.top;
5115
5116		},
5117
5118
5119
5120
5121
5122		// Gets the height of the element at the given index
5123
5124		getHeight: function(topIndex) {
5125
5126			return this.bottoms[topIndex] - this.tops[topIndex];
5127
5128		}
5129
5130
5131
5132	});
5133
5134
5135
5136	;;
5137
5138
5139
5140	/* Tracks a drag's mouse movement, firing various handlers
5141
5142	 ----------------------------------------------------------------------------------------------------------------------*/
5143
5144// TODO: use Emitter
5145
5146
5147
5148	var DragListener = FC.DragListener = Class.extend({
5149
5150
5151
5152		options: null,
5153
5154
5155
5156		isListening: false,
5157
5158		isDragging: false,
5159
5160
5161
5162		// coordinates of the initial mousedown
5163
5164		originX: null,
5165
5166		originY: null,
5167
5168
5169
5170		// handler attached to the document, bound to the DragListener's `this`
5171
5172		mousemoveProxy: null,
5173
5174		mouseupProxy: null,
5175
5176
5177
5178		// for IE8 bug-fighting behavior, for now
5179
5180		subjectEl: null, // the element being draged. optional
5181
5182		subjectHref: null,
5183
5184
5185
5186		scrollEl: null,
5187
5188		scrollBounds: null, // { top, bottom, left, right }
5189
5190		scrollTopVel: null, // pixels per second
5191
5192		scrollLeftVel: null, // pixels per second
5193
5194		scrollIntervalId: null, // ID of setTimeout for scrolling animation loop
5195
5196		scrollHandlerProxy: null, // this-scoped function for handling when scrollEl is scrolled
5197
5198
5199
5200		scrollSensitivity: 30, // pixels from edge for scrolling to start
5201
5202		scrollSpeed: 200, // pixels per second, at maximum speed
5203
5204		scrollIntervalMs: 50, // millisecond wait between scroll increment
5205
5206
5207
5208
5209
5210		constructor: function(options) {
5211
5212			options = options || {};
5213
5214			this.options = options;
5215
5216			this.subjectEl = options.subjectEl;
5217
5218		},
5219
5220
5221
5222
5223
5224		// Call this when the user does a mousedown. Will probably lead to startListening
5225
5226		mousedown: function(ev) {
5227
5228			if (isPrimaryMouseButton(ev)) {
5229
5230
5231
5232				ev.preventDefault(); // prevents native selection in most browsers
5233
5234
5235
5236				this.startListening(ev);
5237
5238
5239
5240				// start the drag immediately if there is no minimum distance for a drag start
5241
5242				if (!this.options.distance) {
5243
5244					this.startDrag(ev);
5245
5246				}
5247
5248			}
5249
5250		},
5251
5252
5253
5254
5255
5256		// Call this to start tracking mouse movements
5257
5258		startListening: function(ev) {
5259
5260			var scrollParent;
5261
5262
5263
5264			if (!this.isListening) {
5265
5266
5267
5268				// grab scroll container and attach handler
5269
5270				if (ev && this.options.scroll) {
5271
5272					scrollParent = getScrollParent($(ev.target));
5273
5274					if (!scrollParent.is(window) && !scrollParent.is(document)) {
5275
5276						this.scrollEl = scrollParent;
5277
5278
5279
5280						// scope to `this`, and use `debounce` to make sure rapid calls don't happen
5281
5282						this.scrollHandlerProxy = debounce(proxy(this, 'scrollHandler'), 100);
5283
5284						this.scrollEl.on('scroll', this.scrollHandlerProxy);
5285
5286					}
5287
5288				}
5289
5290
5291
5292				$(document)
5293
5294					.on('mousemove', this.mousemoveProxy = proxy(this, 'mousemove'))
5295
5296					.on('mouseup', this.mouseupProxy = proxy(this, 'mouseup'))
5297
5298					.on('selectstart', this.preventDefault); // prevents native selection in IE<=8
5299
5300
5301
5302				if (ev) {
5303
5304					this.originX = ev.pageX;
5305
5306					this.originY = ev.pageY;
5307
5308				}
5309
5310				else {
5311
5312					// if no starting information was given, origin will be the topleft corner of the screen.
5313
5314					// if so, dx/dy in the future will be the absolute coordinates.
5315
5316					this.originX = 0;
5317
5318					this.originY = 0;
5319
5320				}
5321
5322
5323
5324				this.isListening = true;
5325
5326				this.listenStart(ev);
5327
5328			}
5329
5330		},
5331
5332
5333
5334
5335
5336		// Called when drag listening has started (but a real drag has not necessarily began)
5337
5338		listenStart: function(ev) {
5339
5340			this.trigger('listenStart', ev);
5341
5342		},
5343
5344
5345
5346
5347
5348		// Called when the user moves the mouse
5349
5350		mousemove: function(ev) {
5351
5352			var dx = ev.pageX - this.originX;
5353
5354			var dy = ev.pageY - this.originY;
5355
5356			var minDistance;
5357
5358			var distanceSq; // current distance from the origin, squared
5359
5360
5361
5362			if (!this.isDragging) { // if not already dragging...
5363
5364				// then start the drag if the minimum distance criteria is met
5365
5366				minDistance = this.options.distance || 1;
5367
5368				distanceSq = dx * dx + dy * dy;
5369
5370				if (distanceSq >= minDistance * minDistance) { // use pythagorean theorem
5371
5372					this.startDrag(ev);
5373
5374				}
5375
5376			}
5377
5378
5379
5380			if (this.isDragging) {
5381
5382				this.drag(dx, dy, ev); // report a drag, even if this mousemove initiated the drag
5383
5384			}
5385
5386		},
5387
5388
5389
5390
5391
5392		// Call this to initiate a legitimate drag.
5393
5394		// This function is called internally from this class, but can also be called explicitly from outside
5395
5396		startDrag: function(ev) {
5397
5398
5399
5400			if (!this.isListening) { // startDrag must have manually initiated
5401
5402				this.startListening();
5403
5404			}
5405
5406
5407
5408			if (!this.isDragging) {
5409
5410				this.isDragging = true;
5411
5412				this.dragStart(ev);
5413
5414			}
5415
5416		},
5417
5418
5419
5420
5421
5422		// Called when the actual drag has started (went beyond minDistance)
5423
5424		dragStart: function(ev) {
5425
5426			var subjectEl = this.subjectEl;
5427
5428
5429
5430			this.trigger('dragStart', ev);
5431
5432
5433
5434			// remove a mousedown'd <a>'s href so it is not visited (IE8 bug)
5435
5436			if ((this.subjectHref = subjectEl ? subjectEl.attr('href') : null)) {
5437
5438				subjectEl.removeAttr('href');
5439
5440			}
5441
5442		},
5443
5444
5445
5446
5447
5448		// Called while the mouse is being moved and when we know a legitimate drag is taking place
5449
5450		drag: function(dx, dy, ev) {
5451
5452			this.trigger('drag', dx, dy, ev);
5453
5454			this.updateScroll(ev); // will possibly cause scrolling
5455
5456		},
5457
5458
5459
5460
5461
5462		// Called when the user does a mouseup
5463
5464		mouseup: function(ev) {
5465
5466			this.stopListening(ev);
5467
5468		},
5469
5470
5471
5472
5473
5474		// Called when the drag is over. Will not cause listening to stop however.
5475
5476		// A concluding 'cellOut' event will NOT be triggered.
5477
5478		stopDrag: function(ev) {
5479
5480			if (this.isDragging) {
5481
5482				this.stopScrolling();
5483
5484				this.dragStop(ev);
5485
5486				this.isDragging = false;
5487
5488			}
5489
5490		},
5491
5492
5493
5494
5495
5496		// Called when dragging has been stopped
5497
5498		dragStop: function(ev) {
5499
5500			var _this = this;
5501
5502
5503
5504			this.trigger('dragStop', ev);
5505
5506
5507
5508			// restore a mousedown'd <a>'s href (for IE8 bug)
5509
5510			setTimeout(function() { // must be outside of the click's execution
5511
5512				if (_this.subjectHref) {
5513
5514					_this.subjectEl.attr('href', _this.subjectHref);
5515
5516				}
5517
5518			}, 0);
5519
5520		},
5521
5522
5523
5524
5525
5526		// Call this to stop listening to the user's mouse events
5527
5528		stopListening: function(ev) {
5529
5530			this.stopDrag(ev); // if there's a current drag, kill it
5531
5532
5533
5534			if (this.isListening) {
5535
5536
5537
5538				// remove the scroll handler if there is a scrollEl
5539
5540				if (this.scrollEl) {
5541
5542					this.scrollEl.off('scroll', this.scrollHandlerProxy);
5543
5544					this.scrollHandlerProxy = null;
5545
5546				}
5547
5548
5549
5550				$(document)
5551
5552					.off('mousemove', this.mousemoveProxy)
5553
5554					.off('mouseup', this.mouseupProxy)
5555
5556					.off('selectstart', this.preventDefault);
5557
5558
5559
5560				this.mousemoveProxy = null;
5561
5562				this.mouseupProxy = null;
5563
5564
5565
5566				this.isListening = false;
5567
5568				this.listenStop(ev);
5569
5570			}
5571
5572		},
5573
5574
5575
5576
5577
5578		// Called when drag listening has stopped
5579
5580		listenStop: function(ev) {
5581
5582			this.trigger('listenStop', ev);
5583
5584		},
5585
5586
5587
5588
5589
5590		// Triggers a callback. Calls a function in the option hash of the same name.
5591
5592		// Arguments beyond the first `name` are forwarded on.
5593
5594		trigger: function(name) {
5595
5596			if (this.options[name]) {
5597
5598				this.options[name].apply(this, Array.prototype.slice.call(arguments, 1));
5599
5600			}
5601
5602		},
5603
5604
5605
5606
5607
5608		// Stops a given mouse event from doing it's native browser action. In our case, text selection.
5609
5610		preventDefault: function(ev) {
5611
5612			ev.preventDefault();
5613
5614		},
5615
5616
5617
5618
5619
5620		/* Scrolling
5621
5622		 ------------------------------------------------------------------------------------------------------------------*/
5623
5624
5625
5626
5627
5628		// Computes and stores the bounding rectangle of scrollEl
5629
5630		computeScrollBounds: function() {
5631
5632			var el = this.scrollEl;
5633
5634
5635
5636			this.scrollBounds = el ? getOuterRect(el) : null;
5637
5638			// TODO: use getClientRect in future. but prevents auto scrolling when on top of scrollbars
5639
5640		},
5641
5642
5643
5644
5645
5646		// Called when the dragging is in progress and scrolling should be updated
5647
5648		updateScroll: function(ev) {
5649
5650			var sensitivity = this.scrollSensitivity;
5651
5652			var bounds = this.scrollBounds;
5653
5654			var topCloseness, bottomCloseness;
5655
5656			var leftCloseness, rightCloseness;
5657
5658			var topVel = 0;
5659
5660			var leftVel = 0;
5661
5662
5663
5664			if (bounds) { // only scroll if scrollEl exists
5665
5666
5667
5668				// compute closeness to edges. valid range is from 0.0 - 1.0
5669
5670				topCloseness = (sensitivity - (ev.pageY - bounds.top)) / sensitivity;
5671
5672				bottomCloseness = (sensitivity - (bounds.bottom - ev.pageY)) / sensitivity;
5673
5674				leftCloseness = (sensitivity - (ev.pageX - bounds.left)) / sensitivity;
5675
5676				rightCloseness = (sensitivity - (bounds.right - ev.pageX)) / sensitivity;
5677
5678
5679
5680				// translate vertical closeness into velocity.
5681
5682				// mouse must be completely in bounds for velocity to happen.
5683
5684				if (topCloseness >= 0 && topCloseness <= 1) {
5685
5686					topVel = topCloseness * this.scrollSpeed * -1; // negative. for scrolling up
5687
5688				}
5689
5690				else if (bottomCloseness >= 0 && bottomCloseness <= 1) {
5691
5692					topVel = bottomCloseness * this.scrollSpeed;
5693
5694				}
5695
5696
5697
5698				// translate horizontal closeness into velocity
5699
5700				if (leftCloseness >= 0 && leftCloseness <= 1) {
5701
5702					leftVel = leftCloseness * this.scrollSpeed * -1; // negative. for scrolling left
5703
5704				}
5705
5706				else if (rightCloseness >= 0 && rightCloseness <= 1) {
5707
5708					leftVel = rightCloseness * this.scrollSpeed;
5709
5710				}
5711
5712			}
5713
5714
5715
5716			this.setScrollVel(topVel, leftVel);
5717
5718		},
5719
5720
5721
5722
5723
5724		// Sets the speed-of-scrolling for the scrollEl
5725
5726		setScrollVel: function(topVel, leftVel) {
5727
5728
5729
5730			this.scrollTopVel = topVel;
5731
5732			this.scrollLeftVel = leftVel;
5733
5734
5735
5736			this.constrainScrollVel(); // massages into realistic values
5737
5738
5739
5740			// if there is non-zero velocity, and an animation loop hasn't already started, then START
5741
5742			if ((this.scrollTopVel || this.scrollLeftVel) && !this.scrollIntervalId) {
5743
5744				this.scrollIntervalId = setInterval(
5745
5746					proxy(this, 'scrollIntervalFunc'), // scope to `this`
5747
5748					this.scrollIntervalMs
5749
5750				);
5751
5752			}
5753
5754		},
5755
5756
5757
5758
5759
5760		// Forces scrollTopVel and scrollLeftVel to be zero if scrolling has already gone all the way
5761
5762		constrainScrollVel: function() {
5763
5764			var el = this.scrollEl;
5765
5766
5767
5768			if (this.scrollTopVel < 0) { // scrolling up?
5769
5770				if (el.scrollTop() <= 0) { // already scrolled all the way up?
5771
5772					this.scrollTopVel = 0;
5773
5774				}
5775
5776			}
5777
5778			else if (this.scrollTopVel > 0) { // scrolling down?
5779
5780				if (el.scrollTop() + el[0].clientHeight >= el[0].scrollHeight) { // already scrolled all the way down?
5781
5782					this.scrollTopVel = 0;
5783
5784				}
5785
5786			}
5787
5788
5789
5790			if (this.scrollLeftVel < 0) { // scrolling left?
5791
5792				if (el.scrollLeft() <= 0) { // already scrolled all the left?
5793
5794					this.scrollLeftVel = 0;
5795
5796				}
5797
5798			}
5799
5800			else if (this.scrollLeftVel > 0) { // scrolling right?
5801
5802				if (el.scrollLeft() + el[0].clientWidth >= el[0].scrollWidth) { // already scrolled all the way right?
5803
5804					this.scrollLeftVel = 0;
5805
5806				}
5807
5808			}
5809
5810		},
5811
5812
5813
5814
5815
5816		// This function gets called during every iteration of the scrolling animation loop
5817
5818		scrollIntervalFunc: function() {
5819
5820			var el = this.scrollEl;
5821
5822			var frac = this.scrollIntervalMs / 1000; // considering animation frequency, what the vel should be mult'd by
5823
5824
5825
5826			// change the value of scrollEl's scroll
5827
5828			if (this.scrollTopVel) {
5829
5830				el.scrollTop(el.scrollTop() + this.scrollTopVel * frac);
5831
5832			}
5833
5834			if (this.scrollLeftVel) {
5835
5836				el.scrollLeft(el.scrollLeft() + this.scrollLeftVel * frac);
5837
5838			}
5839
5840
5841
5842			this.constrainScrollVel(); // since the scroll values changed, recompute the velocities
5843
5844
5845
5846			// if scrolled all the way, which causes the vels to be zero, stop the animation loop
5847
5848			if (!this.scrollTopVel && !this.scrollLeftVel) {
5849
5850				this.stopScrolling();
5851
5852			}
5853
5854		},
5855
5856
5857
5858
5859
5860		// Kills any existing scrolling animation loop
5861
5862		stopScrolling: function() {
5863
5864			if (this.scrollIntervalId) {
5865
5866				clearInterval(this.scrollIntervalId);
5867
5868				this.scrollIntervalId = null;
5869
5870
5871
5872				// when all done with scrolling, recompute positions since they probably changed
5873
5874				this.scrollStop();
5875
5876			}
5877
5878		},
5879
5880
5881
5882
5883
5884		// Get called when the scrollEl is scrolled (NOTE: this is delayed via debounce)
5885
5886		scrollHandler: function() {
5887
5888			// recompute all coordinates, but *only* if this is *not* part of our scrolling animation
5889
5890			if (!this.scrollIntervalId) {
5891
5892				this.scrollStop();
5893
5894			}
5895
5896		},
5897
5898
5899
5900
5901
5902		// Called when scrolling has stopped, whether through auto scroll, or the user scrolling
5903
5904		scrollStop: function() {
5905
5906		}
5907
5908
5909
5910	});
5911
5912
5913
5914	;;
5915
5916
5917
5918	/* Tracks mouse movements over a component and raises events about which hit the mouse is over.
5919
5920	 ------------------------------------------------------------------------------------------------------------------------
5921
5922	 options:
5923
5924	 - subjectEl
5925
5926	 - subjectCenter
5927
5928	 */
5929
5930
5931
5932	var HitDragListener = DragListener.extend({
5933
5934
5935
5936		component: null, // converts coordinates to hits
5937
5938		// methods: prepareHits, releaseHits, queryHit
5939
5940
5941
5942		origHit: null, // the hit the mouse was over when listening started
5943
5944		hit: null, // the hit the mouse is over
5945
5946		coordAdjust: null, // delta that will be added to the mouse coordinates when computing collisions
5947
5948
5949
5950
5951
5952		constructor: function(component, options) {
5953
5954			DragListener.call(this, options); // call the super-constructor
5955
5956
5957
5958			this.component = component;
5959
5960		},
5961
5962
5963
5964
5965
5966		// Called when drag listening starts (but a real drag has not necessarily began).
5967
5968		// ev might be undefined if dragging was started manually.
5969
5970		listenStart: function(ev) {
5971
5972			var subjectEl = this.subjectEl;
5973
5974			var subjectRect;
5975
5976			var origPoint;
5977
5978			var point;
5979
5980
5981
5982			DragListener.prototype.listenStart.apply(this, arguments); // call the super-method
5983
5984
5985
5986			this.computeCoords();
5987
5988
5989
5990			if (ev) {
5991
5992				origPoint = { left: ev.pageX, top: ev.pageY };
5993
5994				point = origPoint;
5995
5996
5997
5998				// constrain the point to bounds of the element being dragged
5999
6000				if (subjectEl) {
6001
6002					subjectRect = getOuterRect(subjectEl); // used for centering as well
6003
6004					point = constrainPoint(point, subjectRect);
6005
6006				}
6007
6008
6009
6010				this.origHit = this.queryHit(point.left, point.top);
6011
6012
6013
6014				// treat the center of the subject as the collision point?
6015
6016				if (subjectEl && this.options.subjectCenter) {
6017
6018
6019
6020					// only consider the area the subject overlaps the hit. best for large subjects.
6021
6022					// TODO: skip this if hit didn't supply left/right/top/bottom
6023
6024					if (this.origHit) {
6025
6026						subjectRect = intersectRects(this.origHit, subjectRect) ||
6027
6028							subjectRect; // in case there is no intersection
6029
6030					}
6031
6032
6033
6034					point = getRectCenter(subjectRect);
6035
6036				}
6037
6038
6039
6040				this.coordAdjust = diffPoints(point, origPoint); // point - origPoint
6041
6042			}
6043
6044			else {
6045
6046				this.origHit = null;
6047
6048				this.coordAdjust = null;
6049
6050			}
6051
6052		},
6053
6054
6055
6056
6057
6058		// Recomputes the drag-critical positions of elements
6059
6060		computeCoords: function() {
6061
6062			this.component.prepareHits();
6063
6064			this.computeScrollBounds(); // why is this here???
6065
6066		},
6067
6068
6069
6070
6071
6072		// Called when the actual drag has started
6073
6074		dragStart: function(ev) {
6075
6076			var hit;
6077
6078
6079
6080			DragListener.prototype.dragStart.apply(this, arguments); // call the super-method
6081
6082
6083
6084			// might be different from this.origHit if the min-distance is large
6085
6086			hit = this.queryHit(ev.pageX, ev.pageY);
6087
6088
6089
6090			// report the initial hit the mouse is over
6091
6092			// especially important if no min-distance and drag starts immediately
6093
6094			if (hit) {
6095
6096				this.hitOver(hit);
6097
6098			}
6099
6100		},
6101
6102
6103
6104
6105
6106		// Called when the drag moves
6107
6108		drag: function(dx, dy, ev) {
6109
6110			var hit;
6111
6112
6113
6114			DragListener.prototype.drag.apply(this, arguments); // call the super-method
6115
6116
6117
6118			hit = this.queryHit(ev.pageX, ev.pageY);
6119
6120
6121
6122			if (!isHitsEqual(hit, this.hit)) { // a different hit than before?
6123
6124				if (this.hit) {
6125
6126					this.hitOut();
6127
6128				}
6129
6130				if (hit) {
6131
6132					this.hitOver(hit);
6133
6134				}
6135
6136			}
6137
6138		},
6139
6140
6141
6142
6143
6144		// Called when dragging has been stopped
6145
6146		dragStop: function() {
6147
6148			this.hitDone();
6149
6150			DragListener.prototype.dragStop.apply(this, arguments); // call the super-method
6151
6152		},
6153
6154
6155
6156
6157
6158		// Called when a the mouse has just moved over a new hit
6159
6160		hitOver: function(hit) {
6161
6162			var isOrig = isHitsEqual(hit, this.origHit);
6163
6164
6165
6166			this.hit = hit;
6167
6168
6169
6170			this.trigger('hitOver', this.hit, isOrig, this.origHit);
6171
6172		},
6173
6174
6175
6176
6177
6178		// Called when the mouse has just moved out of a hit
6179
6180		hitOut: function() {
6181
6182			if (this.hit) {
6183
6184				this.trigger('hitOut', this.hit);
6185
6186				this.hitDone();
6187
6188				this.hit = null;
6189
6190			}
6191
6192		},
6193
6194
6195
6196
6197
6198		// Called after a hitOut. Also called before a dragStop
6199
6200		hitDone: function() {
6201
6202			if (this.hit) {
6203
6204				this.trigger('hitDone', this.hit);
6205
6206			}
6207
6208		},
6209
6210
6211
6212
6213
6214		// Called when drag listening has stopped
6215
6216		listenStop: function() {
6217
6218			DragListener.prototype.listenStop.apply(this, arguments); // call the super-method
6219
6220
6221
6222			this.origHit = null;
6223
6224			this.hit = null;
6225
6226
6227
6228			this.component.releaseHits();
6229
6230		},
6231
6232
6233
6234
6235
6236		// Called when scrolling has stopped, whether through auto scroll, or the user scrolling
6237
6238		scrollStop: function() {
6239
6240			DragListener.prototype.scrollStop.apply(this, arguments); // call the super-method
6241
6242
6243
6244			this.computeCoords(); // hits' absolute positions will be in new places. recompute
6245
6246		},
6247
6248
6249
6250
6251
6252		// Gets the hit underneath the coordinates for the given mouse event
6253
6254		queryHit: function(left, top) {
6255
6256
6257
6258			if (this.coordAdjust) {
6259
6260				left += this.coordAdjust.left;
6261
6262				top += this.coordAdjust.top;
6263
6264			}
6265
6266
6267
6268			return this.component.queryHit(left, top);
6269
6270		}
6271
6272
6273
6274	});
6275
6276
6277
6278
6279
6280// Returns `true` if the hits are identically equal. `false` otherwise. Must be from the same component.
6281
6282// Two null values will be considered equal, as two "out of the component" states are the same.
6283
6284	function isHitsEqual(hit0, hit1) {
6285
6286
6287
6288		if (!hit0 && !hit1) {
6289
6290			return true;
6291
6292		}
6293
6294
6295
6296		if (hit0 && hit1) {
6297
6298			return hit0.component === hit1.component &&
6299
6300				isHitPropsWithin(hit0, hit1) &&
6301
6302				isHitPropsWithin(hit1, hit0); // ensures all props are identical
6303
6304		}
6305
6306
6307
6308		return false;
6309
6310	}
6311
6312
6313
6314
6315
6316// Returns true if all of subHit's non-standard properties are within superHit
6317
6318	function isHitPropsWithin(subHit, superHit) {
6319
6320		for (var propName in subHit) {
6321
6322			if (!/^(component|left|right|top|bottom)$/.test(propName)) {
6323
6324				if (subHit[propName] !== superHit[propName]) {
6325
6326					return false;
6327
6328				}
6329
6330			}
6331
6332		}
6333
6334		return true;
6335
6336	}
6337
6338
6339
6340	;;
6341
6342
6343
6344	/* Creates a clone of an element and lets it track the mouse as it moves
6345
6346	 ----------------------------------------------------------------------------------------------------------------------*/
6347
6348
6349
6350	var MouseFollower = Class.extend({
6351
6352
6353
6354		options: null,
6355
6356
6357
6358		sourceEl: null, // the element that will be cloned and made to look like it is dragging
6359
6360		el: null, // the clone of `sourceEl` that will track the mouse
6361
6362		parentEl: null, // the element that `el` (the clone) will be attached to
6363
6364
6365
6366		// the initial position of el, relative to the offset parent. made to match the initial offset of sourceEl
6367
6368		top0: null,
6369
6370		left0: null,
6371
6372
6373
6374		// the initial position of the mouse
6375
6376		mouseY0: null,
6377
6378		mouseX0: null,
6379
6380
6381
6382		// the number of pixels the mouse has moved from its initial position
6383
6384		topDelta: null,
6385
6386		leftDelta: null,
6387
6388
6389
6390		mousemoveProxy: null, // document mousemove handler, bound to the MouseFollower's `this`
6391
6392
6393
6394		isFollowing: false,
6395
6396		isHidden: false,
6397
6398		isAnimating: false, // doing the revert animation?
6399
6400
6401
6402		constructor: function(sourceEl, options) {
6403
6404			this.options = options = options || {};
6405
6406			this.sourceEl = sourceEl;
6407
6408			this.parentEl = options.parentEl ? $(options.parentEl) : sourceEl.parent(); // default to sourceEl's parent
6409
6410		},
6411
6412
6413
6414
6415
6416		// Causes the element to start following the mouse
6417
6418		start: function(ev) {
6419
6420			if (!this.isFollowing) {
6421
6422				this.isFollowing = true;
6423
6424
6425
6426				this.mouseY0 = ev.pageY;
6427
6428				this.mouseX0 = ev.pageX;
6429
6430				this.topDelta = 0;
6431
6432				this.leftDelta = 0;
6433
6434
6435
6436				if (!this.isHidden) {
6437
6438					this.updatePosition();
6439
6440				}
6441
6442
6443
6444				$(document).on('mousemove', this.mousemoveProxy = proxy(this, 'mousemove'));
6445
6446			}
6447
6448		},
6449
6450
6451
6452
6453
6454		// Causes the element to stop following the mouse. If shouldRevert is true, will animate back to original position.
6455
6456		// `callback` gets invoked when the animation is complete. If no animation, it is invoked immediately.
6457
6458		stop: function(shouldRevert, callback) {
6459
6460			var _this = this;
6461
6462			var revertDuration = this.options.revertDuration;
6463
6464
6465
6466			function complete() {
6467
6468				this.isAnimating = false;
6469
6470				_this.removeElement();
6471
6472
6473
6474				this.top0 = this.left0 = null; // reset state for future updatePosition calls
6475
6476
6477
6478				if (callback) {
6479
6480					callback();
6481
6482				}
6483
6484			}
6485
6486
6487
6488			if (this.isFollowing && !this.isAnimating) { // disallow more than one stop animation at a time
6489
6490				this.isFollowing = false;
6491
6492
6493
6494				$(document).off('mousemove', this.mousemoveProxy);
6495
6496
6497
6498				if (shouldRevert && revertDuration && !this.isHidden) { // do a revert animation?
6499
6500					this.isAnimating = true;
6501
6502					this.el.animate({
6503
6504						top: this.top0,
6505
6506						left: this.left0
6507
6508					}, {
6509
6510						duration: revertDuration,
6511
6512						complete: complete
6513
6514					});
6515
6516				}
6517
6518				else {
6519
6520					complete();
6521
6522				}
6523
6524			}
6525
6526		},
6527
6528
6529
6530
6531
6532		// Gets the tracking element. Create it if necessary
6533
6534		getEl: function() {
6535
6536			var el = this.el;
6537
6538
6539
6540			if (!el) {
6541
6542				this.sourceEl.width(); // hack to force IE8 to compute correct bounding box
6543
6544				el = this.el = this.sourceEl.clone()
6545
6546					.css({
6547
6548						position: 'absolute',
6549
6550						visibility: '', // in case original element was hidden (commonly through hideEvents())
6551
6552						display: this.isHidden ? 'none' : '', // for when initially hidden
6553
6554						margin: 0,
6555
6556						right: 'auto', // erase and set width instead
6557
6558						bottom: 'auto', // erase and set height instead
6559
6560						width: this.sourceEl.width(), // explicit height in case there was a 'right' value
6561
6562						height: this.sourceEl.height(), // explicit width in case there was a 'bottom' value
6563
6564						opacity: this.options.opacity || '',
6565
6566						zIndex: this.options.zIndex
6567
6568					})
6569
6570					.appendTo(this.parentEl);
6571
6572			}
6573
6574
6575
6576			return el;
6577
6578		},
6579
6580
6581
6582
6583
6584		// Removes the tracking element if it has already been created
6585
6586		removeElement: function() {
6587
6588			if (this.el) {
6589
6590				this.el.remove();
6591
6592				this.el = null;
6593
6594			}
6595
6596		},
6597
6598
6599
6600
6601
6602		// Update the CSS position of the tracking element
6603
6604		updatePosition: function() {
6605
6606			var sourceOffset;
6607
6608			var origin;
6609
6610
6611
6612			this.getEl(); // ensure this.el
6613
6614
6615
6616			// make sure origin info was computed
6617
6618			if (this.top0 === null) {
6619
6620				this.sourceEl.width(); // hack to force IE8 to compute correct bounding box
6621
6622				sourceOffset = this.sourceEl.offset();
6623
6624				origin = this.el.offsetParent().offset();
6625
6626				this.top0 = sourceOffset.top - origin.top;
6627
6628				this.left0 = sourceOffset.left - origin.left;
6629
6630			}
6631
6632
6633
6634			this.el.css({
6635
6636				top: this.top0 + this.topDelta,
6637
6638				left: this.left0 + this.leftDelta
6639
6640			});
6641
6642		},
6643
6644
6645
6646
6647
6648		// Gets called when the user moves the mouse
6649
6650		mousemove: function(ev) {
6651
6652			this.topDelta = ev.pageY - this.mouseY0;
6653
6654			this.leftDelta = ev.pageX - this.mouseX0;
6655
6656
6657
6658			if (!this.isHidden) {
6659
6660				this.updatePosition();
6661
6662			}
6663
6664		},
6665
6666
6667
6668
6669
6670		// Temporarily makes the tracking element invisible. Can be called before following starts
6671
6672		hide: function() {
6673
6674			if (!this.isHidden) {
6675
6676				this.isHidden = true;
6677
6678				if (this.el) {
6679
6680					this.el.hide();
6681
6682				}
6683
6684			}
6685
6686		},
6687
6688
6689
6690
6691
6692		// Show the tracking element after it has been temporarily hidden
6693
6694		show: function() {
6695
6696			if (this.isHidden) {
6697
6698				this.isHidden = false;
6699
6700				this.updatePosition();
6701
6702				this.getEl().show();
6703
6704			}
6705
6706		}
6707
6708
6709
6710	});
6711
6712
6713
6714	;;
6715
6716
6717
6718	/* An abstract class comprised of a "grid" of areas that each represent a specific datetime
6719
6720	 ----------------------------------------------------------------------------------------------------------------------*/
6721
6722
6723
6724	var Grid = FC.Grid = Class.extend({
6725
6726
6727
6728		view: null, // a View object
6729
6730		isRTL: null, // shortcut to the view's isRTL option
6731
6732
6733
6734		start: null,
6735
6736		end: null,
6737
6738
6739
6740		el: null, // the containing element
6741
6742		elsByFill: null, // a hash of jQuery element sets used for rendering each fill. Keyed by fill name.
6743
6744
6745
6746		externalDragStartProxy: null, // binds the Grid's scope to externalDragStart (in DayGrid.events)
6747
6748
6749
6750		// derived from options
6751
6752		eventTimeFormat: null,
6753
6754		displayEventTime: null,
6755
6756		displayEventEnd: null,
6757
6758
6759
6760		minResizeDuration: null, // TODO: hack. set by subclasses. minumum event resize duration
6761
6762
6763
6764		// if defined, holds the unit identified (ex: "year" or "month") that determines the level of granularity
6765
6766		// of the date areas. if not defined, assumes to be day and time granularity.
6767
6768		// TODO: port isTimeScale into same system?
6769
6770		largeUnit: null,
6771
6772
6773
6774
6775
6776		constructor: function(view) {
6777
6778			this.view = view;
6779
6780			this.isRTL = view.opt('isRTL');
6781
6782
6783
6784			this.elsByFill = {};
6785
6786			this.externalDragStartProxy = proxy(this, 'externalDragStart');
6787
6788		},
6789
6790
6791
6792
6793
6794		/* Options
6795
6796		 ------------------------------------------------------------------------------------------------------------------*/
6797
6798
6799
6800
6801
6802		// Generates the format string used for event time text, if not explicitly defined by 'timeFormat'
6803
6804		computeEventTimeFormat: function() {
6805
6806			return this.view.opt('smallTimeFormat');
6807
6808		},
6809
6810
6811
6812
6813
6814		// Determines whether events should have their end times displayed, if not explicitly defined by 'displayEventTime'.
6815
6816		// Only applies to non-all-day events.
6817
6818		computeDisplayEventTime: function() {
6819
6820			return true;
6821
6822		},
6823
6824
6825
6826
6827
6828		// Determines whether events should have their end times displayed, if not explicitly defined by 'displayEventEnd'
6829
6830		computeDisplayEventEnd: function() {
6831
6832			return true;
6833
6834		},
6835
6836
6837
6838
6839
6840		/* Dates
6841
6842		 ------------------------------------------------------------------------------------------------------------------*/
6843
6844
6845
6846
6847
6848		// Tells the grid about what period of time to display.
6849
6850		// Any date-related internal data should be generated.
6851
6852		setRange: function(range) {
6853
6854			this.start = range.start.clone();
6855
6856			this.end = range.end.clone();
6857
6858
6859
6860			this.rangeUpdated();
6861
6862			this.processRangeOptions();
6863
6864		},
6865
6866
6867
6868
6869
6870		// Called when internal variables that rely on the range should be updated
6871
6872		rangeUpdated: function() {
6873
6874		},
6875
6876
6877
6878
6879
6880		// Updates values that rely on options and also relate to range
6881
6882		processRangeOptions: function() {
6883
6884			var view = this.view;
6885
6886			var displayEventTime;
6887
6888			var displayEventEnd;
6889
6890
6891
6892			this.eventTimeFormat =
6893
6894				view.opt('eventTimeFormat') ||
6895
6896				view.opt('timeFormat') || // deprecated
6897
6898				this.computeEventTimeFormat();
6899
6900
6901
6902			displayEventTime = view.opt('displayEventTime');
6903
6904			if (displayEventTime == null) {
6905
6906				displayEventTime = this.computeDisplayEventTime(); // might be based off of range
6907
6908			}
6909
6910
6911
6912			displayEventEnd = view.opt('displayEventEnd');
6913
6914			if (displayEventEnd == null) {
6915
6916				displayEventEnd = this.computeDisplayEventEnd(); // might be based off of range
6917
6918			}
6919
6920
6921
6922			this.displayEventTime = displayEventTime;
6923
6924			this.displayEventEnd = displayEventEnd;
6925
6926		},
6927
6928
6929
6930
6931
6932		// Converts a span (has unzoned start/end and any other grid-specific location information)
6933
6934		// into an array of segments (pieces of events whose format is decided by the grid).
6935
6936		spanToSegs: function(span) {
6937
6938			// subclasses must implement
6939
6940		},
6941
6942
6943
6944
6945
6946		// Diffs the two dates, returning a duration, based on granularity of the grid
6947
6948		// TODO: port isTimeScale into this system?
6949
6950		diffDates: function(a, b) {
6951
6952			if (this.largeUnit) {
6953
6954				return diffByUnit(a, b, this.largeUnit);
6955
6956			}
6957
6958			else {
6959
6960				return diffDayTime(a, b);
6961
6962			}
6963
6964		},
6965
6966
6967
6968
6969
6970		/* Hit Area
6971
6972		 ------------------------------------------------------------------------------------------------------------------*/
6973
6974
6975
6976
6977
6978		// Called before one or more queryHit calls might happen. Should prepare any cached coordinates for queryHit
6979
6980		prepareHits: function() {
6981
6982		},
6983
6984
6985
6986
6987
6988		// Called when queryHit calls have subsided. Good place to clear any coordinate caches.
6989
6990		releaseHits: function() {
6991
6992		},
6993
6994
6995
6996
6997
6998		// Given coordinates from the topleft of the document, return data about the date-related area underneath.
6999
7000		// Can return an object with arbitrary properties (although to
7000p/right/left/bottom are encouraged).
7001
7002		// Must have a `grid` property, a reference to this current grid. TODO: avoid this
7003
7004		// The returned object will be processed by getHitSpan and getHitEl.
7005
7006		queryHit: function(leftOffset, topOffset) {
7007
7008		},
7009
7010
7011
7012
7013
7014		// Given position-level information about a date-related area within the grid,
7015
7016		// should return an object with at least a start/end date. Can provide other information as well.
7017
7018		getHitSpan: function(hit) {
7019
7020		},
7021
7022
7023
7024
7025
7026		// Given position-level information about a date-related area within the grid,
7027
7028		// should return a jQuery element that best represents it. passed to dayClick callback.
7029
7030		getHitEl: function(hit) {
7031
7032		},
7033
7034
7035
7036
7037
7038		/* Rendering
7039
7040		 ------------------------------------------------------------------------------------------------------------------*/
7041
7042
7043
7044
7045
7046		// Sets the container element that the grid should render inside of.
7047
7048		// Does other DOM-related initializations.
7049
7050		setElement: function(el) {
7051
7052			var _this = this;
7053
7054
7055
7056			this.el = el;
7057
7058
7059
7060			// attach a handler to the grid's root element.
7061
7062			// jQuery will take care of unregistering them when removeElement gets called.
7063
7064			el.on('mousedown', function(ev) {
7065
7066				if (
7067
7068					!$(ev.target).is('.fc-event-container *, .fc-more') && // not an an event element, or "more.." link
7069
7070					!$(ev.target).closest('.fc-popover').length // not on a popover (like the "more.." events one)
7071
7072				) {
7073
7074					_this.dayMousedown(ev);
7075
7076				}
7077
7078			});
7079
7080
7081
7082			// attach event-element-related handlers. in Grid.events
7083
7084			// same garbage collection note as above.
7085
7086			this.bindSegHandlers();
7087
7088
7089
7090			this.bindGlobalHandlers();
7091
7092		},
7093
7094
7095
7096
7097
7098		// Removes the grid's container element from the DOM. Undoes any other DOM-related attachments.
7099
7100		// DOES NOT remove any content beforehand (doesn't clear events or call unrenderDates), unlike View
7101
7102		removeElement: function() {
7103
7104			this.unbindGlobalHandlers();
7105
7106
7107
7108			this.el.remove();
7109
7110
7111
7112			// NOTE: we don't null-out this.el for the same reasons we don't do it within View::removeElement
7113
7114		},
7115
7116
7117
7118
7119
7120		// Renders the basic structure of grid view before any content is rendered
7121
7122		renderSkeleton: function() {
7123
7124			// subclasses should implement
7125
7126		},
7127
7128
7129
7130
7131
7132		// Renders the grid's date-related content (like areas that represent days/times).
7133
7134		// Assumes setRange has already been called and the skeleton has already been rendered.
7135
7136		renderDates: function() {
7137
7138			// subclasses should implement
7139
7140		},
7141
7142
7143
7144
7145
7146		// Unrenders the grid's date-related content
7147
7148		unrenderDates: function() {
7149
7150			// subclasses should implement
7151
7152		},
7153
7154
7155
7156
7157
7158		/* Handlers
7159
7160		 ------------------------------------------------------------------------------------------------------------------*/
7161
7162
7163
7164
7165
7166		// Binds DOM handlers to elements that reside outside the grid, such as the document
7167
7168		bindGlobalHandlers: function() {
7169
7170			$(document).on('dragstart sortstart', this.externalDragStartProxy); // jqui
7171
7172		},
7173
7174
7175
7176
7177
7178		// Unbinds DOM handlers from elements that reside outside the grid
7179
7180		unbindGlobalHandlers: function() {
7181
7182			$(document).off('dragstart sortstart', this.externalDragStartProxy); // jqui
7183
7184		},
7185
7186
7187
7188
7189
7190		// Process a mousedown on an element that represents a day. For day clicking and selecting.
7191
7192		dayMousedown: function(ev) {
7193
7194			var _this = this;
7195
7196			var view = this.view;
7197
7198			var isSelectable = view.opt('selectable');
7199
7200			var dayClickHit; // null if invalid dayClick
7201
7202			var selectionSpan; // null if invalid selection
7203
7204
7205
7206			// this listener tracks a mousedown on a day element, and a subsequent drag.
7207
7208			// if the drag ends on the same day, it is a 'dayClick'.
7209
7210			// if 'selectable' is enabled, this listener also detects selections.
7211
7212			var dragListener = new HitDragListener(this, {
7213
7214				//distance: 5, // needs more work if we want dayClick to fire correctly
7215
7216				scroll: view.opt('dragScroll'),
7217
7218				dragStart: function() {
7219
7220					view.unselect(); // since we could be rendering a new selection, we want to clear any old one
7221
7222				},
7223
7224				hitOver: function(hit, isOrig, origHit) {
7225
7226					if (origHit) { // click needs to have started on a hit
7227
7228						dayClickHit = isOrig ? hit : null; // single-hit selection is a day click
7229
7230						if (isSelectable) {
7231
7232							selectionSpan = _this.computeSelection(
7233
7234								_this.getHitSpan(origHit),
7235
7236								_this.getHitSpan(hit)
7237
7238							);
7239
7240							if (selectionSpan) {
7241
7242								_this.renderSelection(selectionSpan);
7243
7244							}
7245
7246							else if (selectionSpan === false) {
7247
7248								disableCursor();
7249
7250							}
7251
7252						}
7253
7254					}
7255
7256				},
7257
7258				hitOut: function() {
7259
7260					dayClickHit = null;
7261
7262					selectionSpan = null;
7263
7264					_this.unrenderSelection();
7265
7266					enableCursor();
7267
7268				},
7269
7270				listenStop: function(ev) {
7271
7272					if (dayClickHit) {
7273
7274						view.triggerDayClick(
7275
7276							_this.getHitSpan(dayClickHit),
7277
7278							_this.getHitEl(dayClickHit),
7279
7280							ev
7281
7282						);
7283
7284					}
7285
7286					if (selectionSpan) {
7287
7288						// the selection will already have been rendered. just report it
7289
7290						view.reportSelection(selectionSpan, ev);
7291
7292					}
7293
7294					enableCursor();
7295
7296				}
7297
7298			});
7299
7300
7301
7302			dragListener.mousedown(ev); // start listening, which will eventually initiate a dragStart
7303
7304		},
7305
7306
7307
7308
7309
7310		/* Event Helper
7311
7312		 ------------------------------------------------------------------------------------------------------------------*/
7313
7314		// TODO: should probably move this to Grid.events, like we did event dragging / resizing
7315
7316
7317
7318
7319
7320		// Renders a mock event at the given event location, which contains zoned start/end properties.
7321
7322		renderEventLocationHelper: function(eventLocation, sourceSeg) {
7323
7324			var fakeEvent = this.fabricateHelperEvent(eventLocation, sourceSeg);
7325
7326
7327
7328			this.renderHelper(fakeEvent, sourceSeg); // do the actual rendering
7329
7330		},
7331
7332
7333
7334
7335
7336		// Builds a fake event given zoned event date properties and a segment is should be inspired from.
7337
7338		// The range's end can be null, in which case the mock event that is rendered will have a null end time.
7339
7340		// `sourceSeg` is the internal segment object involved in the drag. If null, something external is dragging.
7341
7342		fabricateHelperEvent: function(eventLocation, sourceSeg) {
7343
7344			var fakeEvent = sourceSeg ? createObject(sourceSeg.event) : {}; // mask the original event object if possible
7345
7346
7347
7348			fakeEvent.start = eventLocation.start.clone();
7349
7350			fakeEvent.end = eventLocation.end ? eventLocation.end.clone() : null;
7351
7352			fakeEvent.allDay = null; // force it to be freshly computed by normalizeEventDates
7353
7354			this.view.calendar.normalizeEventDates(fakeEvent);
7355
7356
7357
7358			// this extra className will be useful for differentiating real events from mock events in CSS
7359
7360			fakeEvent.className = (fakeEvent.className || []).concat('fc-helper');
7361
7362
7363
7364			// if something external is being dragged in, don't render a resizer
7365
7366			if (!sourceSeg) {
7367
7368				fakeEvent.editable = false;
7369
7370			}
7371
7372
7373
7374			return fakeEvent;
7375
7376		},
7377
7378
7379
7380
7381
7382		// Renders a mock event. Given zoned event date properties.
7383
7384		renderHelper: function(eventLocation, sourceSeg) {
7385
7386			// subclasses must implement
7387
7388		},
7389
7390
7391
7392
7393
7394		// Unrenders a mock event
7395
7396		unrenderHelper: function() {
7397
7398			// subclasses must implement
7399
7400		},
7401
7402
7403
7404
7405
7406		/* Selection
7407
7408		 ------------------------------------------------------------------------------------------------------------------*/
7409
7410
7411
7412
7413
7414		// Renders a visual indication of a selection. Will highlight by default but can be overridden by subclasses.
7415
7416		// Given a span (unzoned start/end and other misc data)
7417
7418		renderSelection: function(span) {
7419
7420			this.renderHighlight(span);
7421
7422		},
7423
7424
7425
7426
7427
7428		// Unrenders any visual indications of a selection. Will unrender a highlight by default.
7429
7430		unrenderSelection: function() {
7431
7432			this.unrenderHighlight();
7433
7434		},
7435
7436
7437
7438
7439
7440		// Given the first and last date-spans of a selection, returns another date-span object.
7441
7442		// Subclasses can override and provide additional data in the span object. Will be passed to renderSelection().
7443
7444		// Will return false if the selection is invalid and this should be indicated to the user.
7445
7446		// Will return null/undefined if a selection invalid but no error should be reported.
7447
7448		computeSelection: function(span0, span1) {
7449
7450			var span = this.computeSelectionSpan(span0, span1);
7451
7452
7453
7454			if (span && !this.view.calendar.isSelectionSpanAllowed(span)) {
7455
7456				return false;
7457
7458			}
7459
7460
7461
7462			return span;
7463
7464		},
7465
7466
7467
7468
7469
7470		// Given two spans, must return the combination of the two.
7471
7472		// TODO: do this separation of concerns (combining VS validation) for event dnd/resize too.
7473
7474		computeSelectionSpan: function(span0, span1) {
7475
7476			var dates = [ span0.start, span0.end, span1.start, span1.end ];
7477
7478
7479
7480			dates.sort(compareNumbers); // sorts chronologically. works with Moments
7481
7482
7483
7484			return { start: dates[0].clone(), end: dates[3].clone() };
7485
7486		},
7487
7488
7489
7490
7491
7492		/* Highlight
7493
7494		 ------------------------------------------------------------------------------------------------------------------*/
7495
7496
7497
7498
7499
7500		// Renders an emphasis on the given date range. Given a span (unzoned start/end and other misc data)
7501
7502		renderHighlight: function(span) {
7503
7504			this.renderFill('highlight', this.spanToSegs(span));
7505
7506		},
7507
7508
7509
7510
7511
7512		// Unrenders the emphasis on a date range
7513
7514		unrenderHighlight: function() {
7515
7516			this.unrenderFill('highlight');
7517
7518		},
7519
7520
7521
7522
7523
7524		// Generates an array of classNames for rendering the highlight. Used by the fill system.
7525
7526		highlightSegClasses: function() {
7527
7528			return [ 'fc-highlight' ];
7529
7530		},
7531
7532
7533
7534
7535
7536		/* Fill System (highlight, background events, business hours)
7537
7538		 ------------------------------------------------------------------------------------------------------------------*/
7539
7540
7541
7542
7543
7544		// Renders a set of rectangles over the given segments of time.
7545
7546		// MUST RETURN a subset of segs, the segs that were actually rendered.
7547
7548		// Responsible for populating this.elsByFill. TODO: better API for expressing this requirement
7549
7550		renderFill: function(type, segs) {
7551
7552			// subclasses must implement
7553
7554		},
7555
7556
7557
7558
7559
7560		// Unrenders a specific type of fill that is currently rendered on the grid
7561
7562		unrenderFill: function(type) {
7563
7564			var el = this.elsByFill[type];
7565
7566
7567
7568			if (el) {
7569
7570				el.remove();
7571
7572				delete this.elsByFill[type];
7573
7574			}
7575
7576		},
7577
7578
7579
7580
7581
7582		// Renders and assigns an `el` property for each fill segment. Generic enough to work with different types.
7583
7584		// Only returns segments that successfully rendered.
7585
7586		// To be harnessed by renderFill (implemented by subclasses).
7587
7588		// Analagous to renderFgSegEls.
7589
7590		renderFillSegEls: function(type, segs) {
7591
7592			var _this = this;
7593
7594			var segElMethod = this[type + 'SegEl'];
7595
7596			var html = '';
7597
7598			var renderedSegs = [];
7599
7600			var i;
7601
7602
7603
7604			if (segs.length) {
7605
7606
7607
7608				// build a large concatenation of segment HTML
7609
7610				for (i = 0; i < segs.length; i++) {
7611
7612					html += this.fillSegHtml(type, segs[i]);
7613
7614				}
7615
7616
7617
7618				// Grab individual elements from the combined HTML string. Use each as the default rendering.
7619
7620				// Then, compute the 'el' for each segment.
7621
7622				$(html).each(function(i, node) {
7623
7624					var seg = segs[i];
7625
7626					var el = $(node);
7627
7628
7629
7630					// allow custom filter methods per-type
7631
7632					if (segElMethod) {
7633
7634						el = segElMethod.call(_this, seg, el);
7635
7636					}
7637
7638
7639
7640					if (el) { // custom filters did not cancel the render
7641
7642						el = $(el); // allow custom filter to return raw DOM node
7643
7644
7645
7646						// correct element type? (would be bad if a non-TD were inserted into a table for example)
7647
7648						if (el.is(_this.fillSegTag)) {
7649
7650							seg.el = el;
7651
7652							renderedSegs.push(seg);
7653
7654						}
7655
7656					}
7657
7658				});
7659
7660			}
7661
7662
7663
7664			return renderedSegs;
7665
7666		},
7667
7668
7669
7670
7671
7672		fillSegTag: 'div', // subclasses can override
7673
7674
7675
7676
7677
7678		// Builds the HTML needed for one fill segment. Generic enought o work with different types.
7679
7680		fillSegHtml: function(type, seg) {
7681
7682
7683
7684			// custom hooks per-type
7685
7686			var classesMethod = this[type + 'SegClasses'];
7687
7688			var cssMethod = this[type + 'SegCss'];
7689
7690
7691
7692			var classes = classesMethod ? classesMethod.call(this, seg) : [];
7693
7694			var css = cssToStr(cssMethod ? cssMethod.call(this, seg) : {});
7695
7696
7697
7698			return '<' + this.fillSegTag +
7699
7700				(classes.length ? ' class="' + classes.join(' ') + '"' : '') +
7701
7702				(css ? ' style="' + css + '"' : '') +
7703
7704				' />';
7705
7706		},
7707
7708
7709
7710
7711
7712
7713
7714		/* Generic rendering utilities for subclasses
7715
7716		 ------------------------------------------------------------------------------------------------------------------*/
7717
7718
7719
7720
7721
7722		// Computes HTML classNames for a single-day element
7723
7724		getDayClasses: function(date) {
7725
7726			var view = this.view;
7727
7728			var today = view.calendar.getNow().stripTime();
7729
7730			var classes = [ 'fc-' + dayIDs[date.day()] ];
7731
7732
7733
7734			if (
7735
7736				view.intervalDuration.as('months') == 1 &&
7737
7738				date.month() != view.intervalStart.month()
7739
7740			) {
7741
7742				classes.push('fc-other-month');
7743
7744			}
7745
7746
7747
7748			if (date.isSame(today, 'day')) {
7749
7750				classes.push(
7751
7752					'fc-today',
7753
7754					view.highlightStateClass
7755
7756				);
7757
7758			}
7759
7760			else if (date < today) {
7761
7762				classes.push('fc-past');
7763
7764			}
7765
7766			else {
7767
7768				classes.push('fc-future');
7769
7770			}
7771
7772
7773
7774			return classes;
7775
7776		}
7777
7778
7779
7780	});
7781
7782
7783
7784	;;
7785
7786
7787
7788	/* Event-rendering and event-interaction methods for the abstract Grid class
7789
7790	 ----------------------------------------------------------------------------------------------------------------------*/
7791
7792
7793
7794	Grid.mixin({
7795
7796
7797
7798		mousedOverSeg: null, // the segment object the user's mouse is over. null if over nothing
7799
7800		isDraggingSeg: false, // is a segment being dragged? boolean
7801
7802		isResizingSeg: false, // is a segment being resized? boolean
7803
7804		isDraggingExternal: false, // jqui-dragging an external element? boolean
7805
7806		segs: null, // the event segments currently rendered in the grid
7807
7808
7809
7810
7811
7812		// Renders the given events onto the grid
7813
7814		renderEvents: function(events) {
7815
7816			var bgEvents = [];
7817
7818			var fgEvents = [];
7819
7820			var i;
7821
7822
7823
7824			for (i = 0; i < events.length; i++) {
7825
7826				(isBgEvent(events[i]) ? bgEvents : fgEvents).push(events[i]);
7827
7828			}
7829
7830
7831
7832			this.segs = [].concat( // record all segs
7833
7834				this.renderBgEvents(bgEvents),
7835
7836				this.renderFgEvents(fgEvents)
7837
7838			);
7839
7840		},
7841
7842
7843
7844
7845
7846		renderBgEvents: function(events) {
7847
7848			var segs = this.eventsToSegs(events);
7849
7850
7851
7852			// renderBgSegs might return a subset of segs, segs that were actually rendered
7853
7854			return this.renderBgSegs(segs) || segs;
7855
7856		},
7857
7858
7859
7860
7861
7862		renderFgEvents: function(events) {
7863
7864			var segs = this.eventsToSegs(events);
7865
7866
7867
7868			// renderFgSegs might return a subset of segs, segs that were actually rendered
7869
7870			return this.renderFgSegs(segs) || segs;
7871
7872		},
7873
7874
7875
7876
7877
7878		// Unrenders all events currently rendered on the grid
7879
7880		unrenderEvents: function() {
7881
7882			this.triggerSegMouseout(); // trigger an eventMouseout if user's mouse is over an event
7883
7884
7885
7886			this.unrenderFgSegs();
7887
7888			this.unrenderBgSegs();
7889
7890
7891
7892			this.segs = null;
7893
7894		},
7895
7896
7897
7898
7899
7900		// Retrieves all rendered segment objects currently rendered on the grid
7901
7902		getEventSegs: function() {
7903
7904			return this.segs || [];
7905
7906		},
7907
7908
7909
7910
7911
7912		/* Foreground Segment Rendering
7913
7914		 ------------------------------------------------------------------------------------------------------------------*/
7915
7916
7917
7918
7919
7920		// Renders foreground event segments onto the grid. May return a subset of segs that were rendered.
7921
7922		renderFgSegs: function(segs) {
7923
7924			// subclasses must implement
7925
7926		},
7927
7928
7929
7930
7931
7932		// Unrenders all currently rendered foreground segments
7933
7934		unrenderFgSegs: function() {
7935
7936			// subclasses must implement
7937
7938		},
7939
7940
7941
7942
7943
7944		// Renders and assigns an `el` property for each foreground event segment.
7945
7946		// Only returns segments that successfully rendered.
7947
7948		// A utility that subclasses may use.
7949
7950		renderFgSegEls: function(segs, disableResizing) {
7951
7952			var view = this.view;
7953
7954			var html = '';
7955
7956			var renderedSegs = [];
7957
7958			var i;
7959
7960
7961
7962			if (segs.length) { // don't build an empty html string
7963
7964
7965
7966				// build a large concatenation of event segment HTML
7967
7968				for (i = 0; i < segs.length; i++) {
7969
7970					html += this.fgSegHtml(segs[i], disableResizing);
7971
7972				}
7973
7974
7975
7976				// Grab individual elements from the combined HTML string. Use each as the default rendering.
7977
7978				// Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false.
7979
7980				$(html).each(function(i, node) {
7981
7982					var seg = segs[i];
7983
7984					var el = view.resolveEventEl(seg.event, $(node));
7985
7986
7987
7988					if (el) {
7989
7990						el.data('fc-seg', seg); // used by handlers
7991
7992						seg.el = el;
7993
7994						renderedSegs.push(seg);
7995
7996					}
7997
7998				});
7999
8000			}
8001
8002
8003
8004			return renderedSegs;
8005
8006		},
8007
8008
8009
8010
8011
8012		// Generates the HTML for the default rendering of a foreground event segment. Used by renderFgSegEls()
8013
8014		fgSegHtml: function(seg, disableResizing) {
8015
8016			// subclasses should implement
8017
8018		},
8019
8020
8021
8022
8023
8024		/* Background Segment Rendering
8025
8026		 ------------------------------------------------------------------------------------------------------------------*/
8027
8028
8029
8030
8031
8032		// Renders the given background event segments onto the grid.
8033
8034		// Returns a subset of the segs that were actually rendered.
8035
8036		renderBgSegs: function(segs) {
8037
8038			return this.renderFill('bgEvent', segs);
8039
8040		},
8041
8042
8043
8044
8045
8046		// Unrenders all the currently rendered background event segments
8047
8048		unrenderBgSegs: function() {
8049
8050			this.unrenderFill('bgEvent');
8051
8052		},
8053
8054
8055
8056
8057
8058		// Renders a background event element, given the default rendering. Called by the fill system.
8059
8060		bgEventSegEl: function(seg, el) {
8061
8062			return this.view.resolveEventEl(seg.event, el); // will filter through eventRender
8063
8064		},
8065
8066
8067
8068
8069
8070		// Generates an array of classNames to be used for the default rendering of a background event.
8071
8072		// Called by the fill system.
8073
8074		bgEventSegClasses: function(seg) {
8075
8076			var event = seg.event;
8077
8078			var source = event.source || {};
8079
8080
8081
8082			return [ 'fc-bgevent' ].concat(
8083
8084				event.className,
8085
8086				source.className || []
8087
8088			);
8089
8090		},
8091
8092
8093
8094
8095
8096		// Generates a semicolon-separated CSS string to be used for the default rendering of a background event.
8097
8098		// Called by the fill system.
8099
8100		// TODO: consolidate with getEventSkinCss?
8101
8102		bgEventSegCss: function(seg) {
8103
8104			var view = this.view;
8105
8106			var event = seg.event;
8107
8108			var source = event.source || {};
8109
8110
8111
8112			return {
8113
8114				'background-color':
8115
8116				event.backgroundColor ||
8117
8118				event.color ||
8119
8120				source.backgroundColor ||
8121
8122				source.color ||
8123
8124				view.opt('eventBackgroundColor') ||
8125
8126				view.opt('eventColor')
8127
8128			};
8129
8130		},
8131
8132
8133
8134
8135
8136		// Generates an array of classNames to be used for the rendering business hours overlay. Called by the fill system.
8137
8138		businessHoursSegClasses: function(seg) {
8139
8140			return [ 'fc-nonbusiness', 'fc-bgevent' ];
8141
8142		},
8143
8144
8145
8146
8147
8148		/* Handlers
8149
8150		 ------------------------------------------------------------------------------------------------------------------*/
8151
8152
8153
8154
8155
8156		// Attaches event-element-related handlers to the container element and leverage bubbling
8157
8158		bindSegHandlers: function() {
8159
8160			var _this = this;
8161
8162			var view = this.view;
8163
8164
8165
8166			$.each(
8167
8168				{
8169
8170					mouseenter: function(seg, ev) {
8171
8172						_this.triggerSegMouseover(seg, ev);
8173
8174					},
8175
8176					mouseleave: function(seg, ev) {
8177
8178						_this.triggerSegMouseout(seg, ev);
8179
8180					},
8181
8182					click: function(seg, ev) {
8183
8184						return view.trigger('eventClick', this, seg.event, ev); // can return `false` to cancel
8185
8186					},
8187
8188					mousedown: function(seg, ev) {
8189
8190						if ($(ev.target).is('.fc-resizer') && view.isEventResizable(seg.event)) {
8191
8192							_this.segResizeMousedown(seg, ev, $(ev.target).is('.fc-start-resizer'));
8193
8194						}
8195
8196						else if (view.isEventDraggable(seg.event)) {
8197
8198							_this.segDragMousedown(seg, ev);
8199
8200						}
8201
8202					}
8203
8204				},
8205
8206				function(name, func) {
8207
8208					// attach the handler to the container element and only listen for real event elements via bubbling
8209
8210					_this.el.on(name, '.fc-event-container > *', function(ev) {
8211
8212						var seg = $(this).data('fc-seg'); // grab segment data. put there by View::renderEvents
8213
8214
8215
8216						// only call the handlers if there is not a drag/resize in progress
8217
8218						if (seg && !_this.isDraggingSeg && !_this.isResizingSeg) {
8219
8220							return func.call(this, seg, ev); // `this` will be the event element
8221
8222						}
8223
8224					});
8225
8226				}
8227
8228			);
8229
8230		},
8231
8232
8233
8234
8235
8236		// Updates internal state and triggers handlers for when an event element is moused over
8237
8238		triggerSegMouseover: function(seg, ev) {
8239
8240			if (!this.mousedOverSeg) {
8241
8242				this.mousedOverSeg = seg;
8243
8244				this.view.trigger('eventMouseover', seg.el[0], seg.event, ev);
8245
8246			}
8247
8248		},
8249
8250
8251
8252
8253
8254		// Updates internal state and triggers handlers for when an event element is moused out.
8255
8256		// Can be given no arguments, in which case it will mouseout the segment that was previously moused over.
8257
8258		triggerSegMouseout: function(seg, ev) {
8259
8260			ev = ev || {}; // if given no args, make a mock mouse event
8261
8262
8263
8264			if (this.mousedOverSeg) {
8265
8266				seg = seg || this.mousedOverSeg; // if given no args, use the currently moused-over segment
8267
8268				this.mousedOverSeg = null;
8269
8270				this.view.trigger('eventMouseout', seg.el[0], seg.event, ev);
8271
8272			}
8273
8274		},
8275
8276
8277
8278
8279
8280		/* Event Dragging
8281
8282		 ------------------------------------------------------------------------------------------------------------------*/
8283
8284
8285
8286
8287
8288		// Called when the user does a mousedown on an event, which might lead to dragging.
8289
8290		// Generic enough to work with any type of Grid.
8291
8292		segDragMousedown: function(seg, ev) {
8293
8294			var _this = this;
8295
8296			var view = this.view;
8297
8298			var calendar = view.calendar;
8299
8300			var el = seg.el;
8301
8302			var event = seg.event;
8303
8304			var dropLocation; // zoned event date properties
8305
8306
8307
8308			// A clone of the original element that will move with the mouse
8309
8310			var mouseFollower = new MouseFollower(seg.el, {
8311
8312				parentEl: view.el,
8313
8314				opacity: view.opt('dragOpacity'),
8315
8316				revertDuration: view.opt('dragRevertDuration'),
8317
8318				zIndex: 2 // one above the .fc-view
8319
8320			});
8321
8322
8323
8324			// Tracks mouse movement over the *view's* coordinate map. Allows dragging and dropping between subcomponents
8325
8326			// of the view.
8327
8328			var dragListener = new HitDragListener(view, {
8329
8330				distance: 5,
8331
8332				scroll: view.opt('dragScroll'),
8333
8334				subjectEl: el,
8335
8336				subjectCenter: true,
8337
8338				listenStart: function(ev) {
8339
8340					mouseFollower.hide(); // don't show until we know this is a real drag
8341
8342					mouseFollower.start(ev);
8343
8344				},
8345
8346				dragStart: function(ev) {
8347
8348					_this.triggerSegMouseout(seg, ev); // ensure a mouseout on the manipulated event has been reported
8349
8350					_this.segDragStart(seg, ev);
8351
8352					view.hideEvent(event);
8352 // hide all event segments. our mouseFollower will take over
8353
8354				},
8355
8356				hitOver: function(hit, isOrig, origHit) {
8357
8358
8359
8360					// starting hit could be forced (DayGrid.limit)
8361
8362					if (seg.hit) {
8363
8364						origHit = seg.hit;
8365
8366					}
8367
8368
8369
8370					// since we are querying the parent view, might not belong to this grid
8371
8372					dropLocation = _this.computeEventDrop(
8373
8374						origHit.component.getHitSpan(origHit),
8375
8376						hit.component.getHitSpan(hit),
8377
8378						event
8379
8380					);
8381
8382
8383
8384					if (dropLocation &&!calendar.isEventSpanAllowed(_this.eventToSpan(dropLocation), event)) {
8385
8386						disableCursor();
8387
8388						dropLocation = null;
8389
8390					}
8391
8392
8393
8394					// if a valid drop location, have the subclass render a visual indication
8395
8396					if (dropLocation && view.renderDrag(dropLocation, seg)) {
8397
8398						mouseFollower.hide(); // if the subclass is already using a mock event "helper", hide our own
8399
8400					}
8401
8402					else {
8403
8404						mouseFollower.show(); // otherwise, have the helper follow the mouse (no snapping)
8405
8406					}
8407
8408
8409
8410					if (isOrig) {
8411
8412						dropLocation = null; // needs to have moved hits to be a valid drop
8413
8414					}
8415
8416				},
8417
8418				hitOut: function() { // called before mouse moves to a different hit OR moved out of all hits
8419
8420					view.unrenderDrag(); // unrender whatever was done in renderDrag
8421
8422					mouseFollower.show(); // show in case we are moving out of all hits
8423
8424					dropLocation = null;
8425
8426				},
8427
8428				hitDone: function() { // Called after a hitOut OR before a dragStop
8429
8430					enableCursor();
8431
8432				},
8433
8434				dragStop: function(ev) {
8435
8436					// do revert animation if hasn't changed. calls a callback when finished (whether animation or not)
8437
8438					mouseFollower.stop(!dropLocation, function() {
8439
8440						view.unrenderDrag();
8441
8442						view.showEvent(event);
8443
8444						_this.segDragStop(seg, ev);
8445
8446
8447
8448						if (dropLocation) {
8449
8450							view.reportEventDrop(event, dropLocation, this.largeUnit, el, ev);
8451
8452						}
8453
8454					});
8455
8456				},
8457
8458				listenStop: function() {
8459
8460					mouseFollower.stop(); // put in listenStop in case there was a mousedown but the drag never started
8461
8462				}
8463
8464			});
8465
8466
8467
8468			dragListener.mousedown(ev); // start listening, which will eventually lead to a dragStart
8469
8470		},
8471
8472
8473
8474
8475
8476		// Called before event segment dragging starts
8477
8478		segDragStart: function(seg, ev) {
8479
8480			this.isDraggingSeg = true;
8481
8482			this.view.trigger('eventDragStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
8483
8484		},
8485
8486
8487
8488
8489
8490		// Called after event segment dragging stops
8491
8492		segDragStop: function(seg, ev) {
8493
8494			this.isDraggingSeg = false;
8495
8496			this.view.trigger('eventDragStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
8497
8498		},
8499
8500
8501
8502
8503
8504		// Given the spans an event drag began, and the span event was dropped, calculates the new zoned start/end/allDay
8505
8506		// values for the event. Subclasses may override and set additional properties to be used by renderDrag.
8507
8508		// A falsy returned value indicates an invalid drop.
8509
8510		computeEventDrop: function(startSpan, endSpan, event) {
8511
8512			var calendar = this.view.calendar;
8513
8514			var dragStart = startSpan.start;
8515
8516			var dragEnd = endSpan.start;
8517
8518			var delta;
8519
8520			var dropLocation; // zoned event date properties
8521
8522
8523
8524			if (dragStart.hasTime() === dragEnd.hasTime()) {
8525
8526				delta = this.diffDates(dragEnd, dragStart);
8527
8528
8529
8530				// if an all-day event was in a timed area and it was dragged to a different time,
8531
8532				// guarantee an end and adjust start/end to have times
8533
8534				if (event.allDay && durationHasTime(delta)) {
8535
8536					dropLocation = {
8537
8538						start: event.start.clone(),
8539
8540						end: calendar.getEventEnd(event), // will be an ambig day
8541
8542						allDay: false // for normalizeEventTimes
8543
8544					};
8545
8546					calendar.normalizeEventTimes(dropLocation);
8547
8548				}
8549
8550				// othewise, work off existing values
8551
8552				else {
8553
8554					dropLocation = {
8555
8556						start: event.start.clone(),
8557
8558						end: event.end ? event.end.clone() : null,
8559
8560						allDay: event.allDay // keep it the same
8561
8562					};
8563
8564				}
8565
8566
8567
8568				dropLocation.start.add(delta);
8569
8570				if (dropLocation.end) {
8571
8572					dropLocation.end.add(delta);
8573
8574				}
8575
8576			}
8577
8578			else {
8579
8580				// if switching from day <-> timed, start should be reset to the dropped date, and the end cleared
8581
8582				dropLocation = {
8583
8584					start: dragEnd.clone(),
8585
8586					end: null, // end should be cleared
8587
8588					allDay: !dragEnd.hasTime()
8589
8590				};
8591
8592			}
8593
8594
8595
8596			return dropLocation;
8597
8598		},
8599
8600
8601
8602
8603
8604		// Utility for apply dragOpacity to a jQuery set
8605
8606		applyDragOpacity: function(els) {
8607
8608			var opacity = this.view.opt('dragOpacity');
8609
8610
8611
8612			if (opacity != null) {
8613
8614				els.each(function(i, node) {
8615
8616					// Don't use jQuery (will set an IE filter), do it the old fashioned way.
8617
8618					// In IE8, a helper element will disappears if there's a filter.
8619
8620					node.style.opacity = opacity;
8621
8622				});
8623
8624			}
8625
8626		},
8627
8628
8629
8630
8631
8632		/* External Element Dragging
8633
8634		 ------------------------------------------------------------------------------------------------------------------*/
8635
8636
8637
8638
8639
8640		// Called when a jQuery UI drag is initiated anywhere in the DOM
8641
8642		externalDragStart: function(ev, ui) {
8643
8644			var view = this.view;
8645
8646			var el;
8647
8648			var accept;
8649
8650
8651
8652			if (view.opt('droppable')) { // only listen if this setting is on
8653
8654				el = $((ui ? ui.item : null) || ev.target);
8655
8656
8657
8658				// Test that the dragged element passes the dropAccept selector or filter function.
8659
8660				// FYI, the default is "*" (matches all)
8661
8662				accept = view.opt('dropAccept');
8663
8664				if ($.isFunction(accept) ? accept.call(el[0], el) : el.is(accept)) {
8665
8666					if (!this.isDraggingExternal) { // prevent double-listening if fired twice
8667
8668						this.listenToExternalDrag(el, ev, ui);
8669
8670					}
8671
8672				}
8673
8674			}
8675
8676		},
8677
8678
8679
8680
8681
8682		// Called when a jQuery UI drag starts and it needs to be monitored for dropping
8683
8684		listenToExternalDrag: function(el, ev, ui) {
8685
8686			var _this = this;
8687
8688			var meta = getDraggedElMeta(el); // extra data about event drop, including possible event to create
8689
8690			var dropLocation; // a null value signals an unsuccessful drag
8691
8692
8693
8694			// listener that tracks mouse movement over date-associated pixel regions
8695
8696			var dragListener = new HitDragListener(this, {
8697
8698				listenStart: function() {
8699
8700					_this.isDraggingExternal = true;
8701
8702				},
8703
8704				hitOver: function(hit) {
8705
8706					dropLocation = _this.computeExternalDrop(
8707
8708						hit.component.getHitSpan(hit), // since we are querying the parent view, might not belong to this grid
8709
8710						meta
8711
8712					);
8713
8714					if (dropLocation) {
8715
8716						_this.renderDrag(dropLocation); // called without a seg parameter
8717
8718					}
8719
8720					else { // invalid hit
8721
8722						disableCursor();
8723
8724					}
8725
8726				},
8727
8728				hitOut: function() {
8729
8730					dropLocation = null; // signal unsuccessful
8731
8732					_this.unrenderDrag();
8733
8734					enableCursor();
8735
8736				},
8737
8738				dragStop: function() {
8739
8740					_this.unrenderDrag();
8741
8742					enableCursor();
8743
8744
8745
8746					if (dropLocation) { // element was dropped on a valid hit
8747
8748						_this.view.reportExternalDrop(meta, dropLocation, el, ev, ui);
8749
8750					}
8751
8752				},
8753
8754				listenStop: function() {
8755
8756					_this.isDraggingExternal = false;
8757
8758				}
8759
8760			});
8761
8762
8763
8764			dragListener.startDrag(ev); // start listening immediately
8765
8766		},
8767
8768
8769
8770
8771
8772		// Given a hit to be dropped upon, and misc data associated with the jqui drag (guaranteed to be a plain object),
8773
8774		// returns the zoned start/end dates for the event that would result from the hypothetical drop. end might be null.
8775
8776		// Returning a null value signals an invalid drop hit.
8777
8778		computeExternalDrop: function(span, meta) {
8779
8780			var calendar = this.view.calendar;
8781
8782			var dropLocation = {
8783
8784				start: calendar.applyTimezone(span.start), // simulate a zoned event start date
8785
8786				end: null
8787
8788			};
8789
8790
8791
8792			// if dropped on an all-day span, and element's metadata specified a time, set it
8793
8794			if (meta.startTime && !dropLocation.start.hasTime()) {
8795
8796				dropLocation.start.time(meta.startTime);
8797
8798			}
8799
8800
8801
8802			if (meta.duration) {
8803
8804				dropLocation.end = dropLocation.start.clone().add(meta.duration);
8805
8806			}
8807
8808
8809
8810			if (!calendar.isExternalSpanAllowed(this.eventToSpan(dropLocation), dropLocation, meta.eventProps)) {
8811
8812				return null;
8813
8814			}
8815
8816
8817
8818			return dropLocation;
8819
8820		},
8821
8822
8823
8824
8825
8826
8827
8828		/* Drag Rendering (for both events and an external elements)
8829
8830		 ------------------------------------------------------------------------------------------------------------------*/
8831
8832
8833
8834
8835
8836		// Renders a visual indication of an event or external element being dragged.
8837
8838		// `dropLocation` contains hypothetical start/end/allDay values the event would have if dropped. end can be null.
8839
8840		// `seg` is the internal segment object that is being dragged. If dragging an external element, `seg` is null.
8841
8842		// A truthy returned value indicates this method has rendered a helper element.
8843
8844		renderDrag: function(dropLocation, seg) {
8845
8846			// subclasses must implement
8847
8848		},
8849
8850
8851
8852
8853
8854		// Unrenders a visual indication of an event or external element being dragged
8855
8856		unrenderDrag: function() {
8857
8858			// subclasses must implement
8859
8860		},
8861
8862
8863
8864
8865
8866		/* Resizing
8867
8868		 ------------------------------------------------------------------------------------------------------------------*/
8869
8870
8871
8872
8873
8874		// Called when the user does a mousedown on an event's resizer, which might lead to resizing.
8875
8876		// Generic enough to work with any type of Grid.
8877
8878		segResizeMousedown: function(seg, ev, isStart) {
8879
8880			var _this = this;
8881
8882			var view = this.view;
8883
8884			var calendar = view.calendar;
8885
8886			var el = seg.el;
8887
8888			var event = seg.event;
8889
8890			var eventEnd = calendar.getEventEnd(event);
8891
8892			var resizeLocation; // zoned event date properties. falsy if invalid resize
8893
8894
8895
8896			// Tracks mouse movement over the *grid's* coordinate map
8897
8898			var dragListener = new HitDragListener(this, {
8899
8900				distance: 5,
8901
8902				scroll: view.opt('dragScroll'),
8903
8904				subjectEl: el,
8905
8906				dragStart: function(ev) {
8907
8908					_this.triggerSegMouseout(seg, ev); // ensure a mouseout on the manipulated event has been reported
8909
8910					_this.segResizeStart(seg, ev);
8911
8912				},
8913
8914				hitOver: function(hit, isOrig, origHit) {
8915
8916					var origHitSpan = _this.getHitSpan(origHit);
8917
8918					var hitSpan = _this.getHitSpan(hit);
8919
8920
8921
8922					resizeLocation = isStart ?
8923
8924						_this.computeEventStartResize(origHitSpan, hitSpan, event) :
8925
8926						_this.computeEventEndResize(origHitSpan, hitSpan, event);
8927
8928
8929
8930					if (resizeLocation) {
8931
8932						if (!calendar.isEventSpanAllowed(_this.eventToSpan(resizeLocation), event)) {
8933
8934							disableCursor();
8935
8936							resizeLocation = null;
8937
8938						}
8939
8940						// no change? (TODO: how does this work with timezones?)
8941
8942						else if (resizeLocation.start.isSame(event.start) && resizeLocation.end.isSame(eventEnd)) {
8943
8944							resizeLocation = null;
8945
8946						}
8947
8948					}
8949
8950
8951
8952					if (resizeLocation) {
8953
8954						view.hideEvent(event);
8955
8956						_this.renderEventResize(resizeLocation, seg);
8957
8958					}
8959
8960				},
8961
8962				hitOut: function() { // called before mouse moves to a different hit OR moved out of all hits
8963
8964					resizeLocation = null;
8965
8966				},
8967
8968				hitDone: function() { // resets the rendering to show the original event
8969
8970					_this.unrenderEventResize();
8971
8972					view.showEvent(event);
8973
8974					enableCursor();
8975
8976				},
8977
8978				dragStop: function(ev) {
8979
8980					_this.segResizeStop(seg, ev);
8981
8982
8983
8984					if (resizeLocation) { // valid date to resize to?
8985
8986						view.reportEventResize(event, resizeLocation, this.largeUnit, el, ev);
8987
8988					}
8989
8990				}
8991
8992			});
8993
8994
8995
8996			dragListener.mousedown(ev); // start listening, which will eventually lead to a dragStart
8997
8998		},
8999
9000
9001
9002
9003
9004		// Called before event segment resizing starts
9005
9006		segResizeStart: function(seg, ev) {
9007
9008			this.isResizingSeg = true;
9009
9010			this.view.trigger('eventResizeStart', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
9011
9012		},
9013
9014
9015
9016
9017
9018		// Called after event segment resizing stops
9019
9020		segResizeStop: function(seg, ev) {
9021
9022			this.isResizingSeg = false;
9023
9024			this.view.trigger('eventResizeStop', seg.el[0], seg.event, ev, {}); // last argument is jqui dummy
9025
9026		},
9027
9028
9029
9030
9031
9032		// Returns new date-information for an event segment being resized from its start
9033
9034		computeEventStartResize: function(startSpan, endSpan, event) {
9035
9036			return this.computeEventResize('start', startSpan, endSpan, event);
9037
9038		},
9039
9040
9041
9042
9043
9044		// Returns new date-information for an event segment being resized from its end
9045
9046		computeEventEndResize: function(startSpan, endSpan, event) {
9047
9048			return this.computeEventResize('end', startSpan, endSpan, event);
9049
9050		},
9051
9052
9053
9054
9055
9056		// Returns new zoned date information for an event segment being resized from its start OR end
9057
9058		// `type` is either 'start' or 'end'
9059
9060		computeEventResize: function(type, startSpan, endSpan, event) {
9061
9062			var calendar = this.view.calendar;
9063
9064			var delta = this.diffDates(endSpan[type], startSpan[type]);
9065
9066			var resizeLocation; // zoned event date properties
9067
9068			var defaultDuration;
9069
9070
9071
9072			// build original values to work from, guaranteeing a start and end
9073
9074			resizeLocation = {
9075
9076				start: event.start.clone(),
9077
9078				end: calendar.getEventEnd(event),
9079
9080				allDay: event.allDay
9081
9082			};
9083
9084
9085
9086			// if an all-day event was in a timed area and was resized to a time, adjust start/end to have times
9087
9088			if (resizeLocation.allDay && durationHasTime(delta)) {
9089
9090				resizeLocation.allDay = false;
9091
9092				calendar.normalizeEventTimes(resizeLocation);
9093
9094			}
9095
9096
9097
9098			resizeLocation[type].add(delta); // apply delta to start or end
9099
9100
9101
9102			// if the event was compressed too small, find a new reasonable duration for it
9103
9104			if (!resizeLocation.start.isBefore(resizeLocation.end)) {
9105
9106
9107
9108				defaultDuration =
9109
9110					this.minResizeDuration || // TODO: hack
9111
9112					(event.allDay ?
9113
9114						calendar.defaultAllDayEventDuration :
9115
9116						calendar.defaultTimedEventDuration);
9117
9118
9119
9120				if (type == 'start') { // resizing the start?
9121
9122					resizeLocation.start = resizeLocation.end.clone().subtract(defaultDuration);
9123
9124				}
9125
9126				else { // resizing the end?
9127
9128					resizeLocation.end = resizeLocation.start.clone().add(defaultDuration);
9129
9130				}
9131
9132			}
9133
9134
9135
9136			return resizeLocation;
9137
9138		},
9139
9140
9141
9142
9143
9144		// Renders a visual indication of an event being resized.
9145
9146		// `range` has the updated dates of the event. `seg` is the original segment object involved in the drag.
9147
9148		renderEventResize: function(range, seg) {
9149
9150			// subclasses must implement
9151
9152		},
9153
9154
9155
9156
9157
9158		// Unrenders a visual indication of an event being resized.
9159
9160		unrenderEventResize: function() {
9161
9162			// subclasses must implement
9163
9164		},
9165
9166
9167
9168
9169
9170		/* Rendering Utils
9171
9172		 ------------------------------------------------------------------------------------------------------------------*/
9173
9174
9175
9176
9177
9178		// Compute the text that should be displayed on an event's element.
9179
9180		// `range` can be the Event object itself, or something range-like, with at least a `start`.
9181
9182		// If event times are disabled, or the event has no time, will return a blank string.
9183
9184		// If not specified, formatStr will default to the eventTimeFormat setting,
9185
9186		// and displayEnd will default to the displayEventEnd setting.
9187
9188		getEventTimeText: function(range, formatStr, displayEnd) {
9189
9190
9191
9192			if (formatStr == null) {
9193
9194				formatStr = this.eventTimeFormat;
9195
9196			}
9197
9198
9199
9200			if (displayEnd == null) {
9201
9202				displayEnd = this.displayEventEnd;
9203
9204			}
9205
9206
9207
9208			if (this.displayEventTime && range.start.hasTime()) {
9209
9210				if (displayEnd && range.end) {
9211
9212					return this.view.formatRange(range, formatStr);
9213
9214				}
9215
9216				else {
9217
9218					return range.start.format(formatStr);
9219
9220				}
9221
9222			}
9223
9224
9225
9226			return '';
9227
9228		},
9229
9230
9231
9232
9233
9234		// Generic utility for generating the HTML classNames for an event segment's element
9235
9236		getSegClasses: function(seg, isDraggable, isResizable) {
9237
9238			var event = seg.event;
9239
9240			var classes = [
9241
9242				'fc-event',
9243
9244				seg.isStart ? 'fc-start' : 'fc-not-start',
9245
9246				seg.isEnd ? 'fc-end' : 'fc-not-end'
9247
9248			].concat(
9249
9250				event.className,
9251
9252				event.source ? event.source.className : []
9253
9254			);
9255
9256
9257
9258			if (isDraggable) {
9259
9260				classes.push('fc-draggable');
9261
9262			}
9263
9264			if (isResizable) {
9265
9266				classes.push('fc-resizable');
9267
9268			}
9269
9270
9271
9272			return classes;
9273
9274		},
9275
9276
9277
9278
9279
9280		// Utility for generating event skin-related CSS properties
9281
9282		getEventSkinCss: function(event) {
9283
9284			var view = this.view;
9285
9286			var source = event.source || {};
9287
9288			var eventColor = event.color;
9289
9290			var sourceColor = source.color;
9291
9292			var optionColor = view.opt('eventColor');
9293
9294
9295
9296			return {
9297
9298				'background-color':
9299
9300				event.backgroundColor ||
9301
9302				eventColor ||
9303
9304				source.backgroundColor ||
9305
9306				sourceColor ||
9307
9308				view.opt('eventBackgroundColor') ||
9309
9310				optionColor,
9311
9312				'border-color':
9313
9314				event.borderColor ||
9315
9316				eventColor ||
9317
9318				source.borderColor ||
9319
9320				sourceColor ||
9321
9322				view.opt('eventBorderColor') ||
9323
9324				optionColor,
9325
9326				color:
9327
9328				event.textColor ||
9329
9330				source.textColor ||
9331
9332				view.opt('eventTextColor')
9333
9334			};
9335
9336		},
9337
9338
9339
9340
9341
9342		/* Converting events -> eventRange -> eventSpan -> eventSegs
9343
9344		 ------------------------------------------------------------------------------------------------------------------*/
9345
9346
9347
9348
9349
9350		// Generates an array of segments for the given single event
9351
9352		eventToSegs: function(event) {
9353
9354			return this.eventsToSegs([ event ]);
9355
9356		},
9357
9358
9359
9360
9361
9362		// Generates a single span (always unzoned) by using the given event's dates.
9363
9364		// Does not do any inverting for inverse-background events.
9365
9366		eventToSpan: function(event) {
9367
9368			var range = this.eventToRange(event);
9369
9370			this.transformEventSpan(range, event); // convert it to a span, in-place
9371
9372			return range;
9373
9374		},
9375
9376
9377
9378
9379
9380		// Converts an array of event objects into an array of event segment objects.
9381
9382		// A custom `segSliceFunc` may be given for arbitrarily slicing up events.
9383
9384		// Doesn't guarantee an order for the resulting array.
9385
9386		eventsToSegs: function(allEvents, segSliceFunc) {
9387
9388			var _this = this;
9389
9390			var eventsById = groupEventsById(allEvents);
9391
9392			var segs = [];
9393
9394
9395
9396			$.each(eventsById, function(id, events) {
9397
9398				var ranges = [];
9399
9400				var i;
9401
9402
9403
9404				for (i = 0; i < events.length; i++) {
9405
9406					ranges.push(_this.eventToRange(events[i]));
9407
9408				}
9409
9410
9411
9412				// inverse-background events (utilize only the first event in calculations)
9413
9414				if (isInverseBgEvent(events[0])) {
9415
9416					ranges = _this.invertRanges(ranges);
9417
9418
9419
9420					for (i = 0; i < ranges.length; i++) {
9421
9422						_this.generateEventSegs(ranges[i], events[0], segSliceFunc, segs);
9423
9424					}
9425
9426				}
9427
9428				// normal event ranges
9429
9430				else {
9431
9432					for (i = 0; i < ranges.length; i++) {
9433
9434						_this.generateEventSegs(ranges[i], events[i], segSliceFunc, segs);
9435
9436					}
9437
9438				}
9439
9440			});
9441
9442
9443
9444			return segs;
9445
9446		},
9447
9448
9449
9450
9451
9452		// Generates the unzoned start/end dates an event appears to occupy
9453
9454		eventToRange: function(event) {
9455
9456			return {
9457
9458				start: event.start.clone().stripZone(),
9459
9460				end: this.view.calendar.getEventEnd(event).stripZone()
9461
9462			};
9463
9464		},
9465
9466
9467
9468
9469
9470		// Given an event's span (unzoned start/end and other misc data), and the event itself,
9471
9472		// slice into segments (using the segSliceFunc function if specified) and append to the `out` array.
9473
9474		// SIDE EFFECT: will mutate the given `range`.
9475
9476		generateEventSegs: function(range, event, segSliceFunc, out) {
9477
9478			var segs;
9479
9480			var i;
9481
9482
9483
9484			this.transformEventSpan(range, event); // converts the range to a span
9485
9486
9487
9488			segs = segSliceFunc ? segSliceFunc(range) : this.spanToSegs(range);
9489
9490
9491
9492			for (i = 0; i < segs.length; i++) {
9493
9494				this.transformEventSeg(segs[i], range, event);
9495
9496				out.push(segs[i]);
9497
9498			}
9499
9500		},
9501
9502
9503
9504
9505
9506		// Given a range (unzoned start/end) that is about to become a span,
9507
9508		// attach any event-derived properties to it.
9509
9510		transformEventSpan: function(range, event) {
9511
9512			// subclasses can implement
9513
9514		},
9515
9516
9517
9518
9519
9520		// Given a segment object, attach any extra properties, based off of its source span and event.
9521
9522		transformEventSeg: function(seg, span, event) {
9523
9524			seg.event = event;
9525
9526			seg.eventStartMS = +span.start; // TODO: not the best name after making spans unzoned
9527
9528			seg.eventDurationMS = span.end - span.start;
9529
9530		},
9531
9532
9533
9534
9535
9536		// Produces a new array of range objects that will cover all the time NOT covered by the given ranges.
9537
9538		// SIDE EFFECT: will mutate the given array and will use its date references.
9539
9540		invertRanges: function(ranges) {
9541
9542			var view = this.view;
9543
9544			var viewStart = view.start.clone(); // need a copy
9545
9546			var viewEnd = view.end.clone(); // need a copy
9547
9548			var inverseRanges = [];
9549
9550			var start = viewStart; // the end of the previous range. the start of the new range
9551
9552			var i, range;
9553
9554
9555
9556			// ranges need to be in order. required for our date-walking algorithm
9557
9558			ranges.sort(compareRanges);
9559
9560
9561
9562			for (i = 0; i < ranges.length; i++) {
9563
9564				range = ranges[i];
9565
9566
9567
9568				// add the span of time before the event (if there is any)
9569
9570				if (range.start > start) { // compare millisecond time (skip any ambig logic)
9571
9572					inverseRanges.push({
9573
9574						start: start,
9575
9576						end: range.start
9577
9578					});
9579
9580				}
9581
9582
9583
9584				start = range.end;
9585
9586			}
9587
9588
9589
9590			// add the span of time after the last event (if there is any)
9591
9592			if (start < viewEnd) { // compare millisecond time (skip any ambig logic)
9593
9594				inverseRanges.push({
9595
9596					start: start,
9597
9598					end: viewEnd
9599
9600				});
9601
9602			}
9603
9604
9605
9606			return inverseRanges;
9607
9608		},
9609
9610
9611
9612
9613
9614		sortEventSegs: function(segs) {
9615
9616			segs.sort(proxy(this, 'compareEventSegs'));
9617
9618		},
9619
9620
9621
9622
9623
9624		// A cmp function for determining which segments should take visual priority
9625
9626		compareEventSegs: function(seg1, seg2) {
9627
9628			return seg1.eventStartMS - seg2.eventStartMS || // earlier events go first
9629
9630				seg2.eventDurationMS - seg1.eventDurationMS || // tie? longer events go first
9631
9632				seg2.event.allDay - seg1.event.allDay || // tie? put all-day events first (booleans cast to 0/1)
9633
9634				compareByFieldSpecs(seg1.event, seg2.event, this.view.eventOrderSpecs);
9635
9636		}
9637
9638
9639
9640	});
9641
9642
9643
9644
9645
9646	/* Utilities
9647
9648	 ----------------------------------------------------------------------------------------------------------------------*/
9649
9650
9651
9652
9653
9654	function isBgEvent(event) { // returns true if background OR inverse-background
9655
9656		var rendering = getEventRendering(event);
9657
9658		return rendering === 'background' || rendering === 'inverse-background';
9659
9660	}
9661
9662
9663
9664
9665
9666	function isInverseBgEvent(event) {
9667
9668		return getEventRendering(event) === 'inverse-background';
9669
9670	}
9671
9672
9673
9674
9675
9676	function getEventRendering(event) {
9677
9678		return firstDefined((event.source || {}).rendering, event.rendering);
9679
9680	}
9681
9682
9683
9684
9685
9686	function groupEventsById(events) {
9687
9688		var eventsById = {};
9689
9690		var i, event;
9691
9692
9693
9694		for (i = 0; i < events.length; i++) {
9695
9696			event = events[i];
9697
9698			(eventsById[event._id] || (eventsById[event._id] = [])).push(event);
9699
9700		}
9701
9702
9703
9704		return eventsById;
9705
9706	}
9707
9708
9709
9710
9711
9712// A cmp function for determining which non-inverted "ranges" (see above) happen earlier
9713
9714	function compareRanges(range1, range2) {
9715
9716		return range1.start - range2.start; // earlier ranges go first
9717
9718	}
9719
9720
9721
9722
9723
9724	/* External-Dragging-Element Data
9725
9726	 ----------------------------------------------------------------------------------------------------------------------*/
9727
9728
9729
9730// Require all HTML5 data-* attributes used by FullCalendar to have this prefix.
9731
9732// A value of '' will query attributes like data-event. A value of 'fc' will query attributes like data-fc-event.
9733
9734	FC.dataAttrPrefix = '';
9735
9736
9737
9738// Given a jQuery element that might represent a dragged FullCalendar event, returns an intermediate data structure
9739
9740// to be used for Event Object creation.
9741
9742// A defined `.eventProps`, even when empty, indicates that an event should be created.
9743
9744	function getDraggedElMeta(el) {
9745
9746		var prefix = FC.dataAttrPrefix;
9747
9748		var eventProps; // properties for creating the event, not related to date/time
9749
9750		var startTime; // a Duration
9751
9752		var duration;
9753
9754		var stick;
9755
9756
9757
9758		if (prefix) { prefix += '-'; }
9759
9760		eventProps = el.data(prefix + 'event') || null;
9761
9762
9763
9764		if (eventProps) {
9765
9766			if (typeof eventProps === 'object') {
9767
9768				eventProps = $.extend({}, eventProps); // make a copy
9769
9770			}
9771
9772			else { // something like 1 or true. still signal event creation
9773
9774				eventProps = {};
9775
9776			}
9777
9778
9779
9780			// pluck special-cased date/time properties
9781
9782			startTime = eventProps.start;
9783
9784			if (startTime == null) { startTime = eventProps.time; } // accept 'time' as well
9785
9786			duration = eventProps.duration;
9787
9788			stick = eventProps.stick;
9789
9790			delete eventProps.start;
9791
9792			delete eventProps.time;
9793
9794			delete eventProps.duration;
9795
9796			delete eventProps.stick;
9797
9798		}
9799
9800
9801
9802		// fallback to standalone attribute values for each of the date/time properties
9803
9804		if (startTime == null) { startTime = el.data(prefix + 'start'); }
9805
9806		if (startTime == null) { startTime = el.data(prefix + 'time'); } // accept 'time' as well
9807
9808		if (duration == null) { duration = el.data(prefix + 'duration'); }
9809
9810		if (stick == null) { stick = el.data(prefix + 'stick'); }
9811
9812
9813
9814		// massage into correct data types
9815
9816		startTime = startTime != null ? moment.duration(startTime) : null;
9817
9818		duration = duration != null ? moment.duration(duration) : null;
9819
9820		stick = Boolean(stick);
9821
9822
9823
9824		return { eventProps: eventProps, startTime: startTime, duration: duration, stick: stick };
9825
9826	}
9827
9828
9829
9830
9831
9832	;;
9833
9834
9835
9836	/*
9837
9838	 A set of rendering and date-related methods for a visual component comprised of one or more rows of day columns.
9839
9840	 Prerequisite: the object being mixed into needs to be a *Grid*
9841
9842	 */
9843
9844	var DayTableMixin = FC.DayTableMixin = {
9845
9846
9847
9848		breakOnWeeks: false, // should create a new row for each week?
9849
9850		dayDates: null, // whole-day dates for each column. left to right
9851
9852		dayIndices: null, // for each day from start, the offset
9853
9854		daysPerRow: null,
9855
9856		rowCnt: null,
9857
9858		colCnt: null,
9859
9860		colHeadFormat: null,
9861
9862
9863
9864
9865
9866		// Populates internal variables used for date calculation and rendering
9867
9868		updateDayTable: function() {
9869
9870			var view = this.view;
9871
9872			var date = this.start.clone();
9873
9874			var dayIndex = -1;
9875
9876			var dayIndices = [];
9877
9878			var dayDates = [];
9879
9880			var daysPerRow;
9881
9882			var firstDay;
9883
9884			var rowCnt;
9885
9886
9887
9888			while (date.isBefore(this.end)) { // loop each day from start to end
9889
9890				if (view.isHiddenDay(date)) {
9891
9892					dayIndices.push(dayIndex + 0.5); // mark that it's between indices
9893
9894				}
9895
9896				else {
9897
9898					dayIndex++;
9899
9900					dayIndices.push(dayIndex);
9901
9902					dayDates.push(date.clone());
9903
9904				}
9905
9906				date.add(1, 'days');
9907
9908			}
9909
9910
9911
9912			if (this.breakOnWeeks) {
9913
9914				// count columns until the day-of-week repeats
9915
9916				firstDay = dayDates[0].day();
9917
9918				for (daysPerRow = 1; daysPerRow < dayDates.length; daysPerRow++) {
9919
9920					if (dayDates[daysPerRow].day() == firstDay) {
9921
9922						break;
9923
9924					}
9925
9926				}
9927
9928				rowCnt = Math.ceil(dayDates.length / daysPerRow);
9929
9930			}
9931
9932			else {
9933
9934				rowCnt = 1;
9935
9936				daysPerRow = dayDates.length;
9937
9938			}
9939
9940
9941
9942			this.dayDates = dayDates;
9943
9944			this.dayIndices = dayIndices;
9945
9946			this.daysPerRow = daysPerRow;
9947
9948			this.rowCnt = rowCnt;
9949
9950
9951
9952			this.updateDayTableCols();
9953
9954		},
9955
9956
9957
9958
9959
9960		// Computes and assigned the colCnt property and updates any options that may be computed from it
9961
9962		updateDayTableCols: function() {
9963
9964			this.colCnt = this.computeColCnt();
9965
9966			this.colHeadFormat = this.view.opt('columnFormat') || this.computeColHeadFormat();
9967
9968		},
9969
9970
9971
9972
9973
9974		// Determines how many columns there should be in the table
9975
9976		computeColCnt: function() {
9977
9978			return this.daysPerRow;
9979
9980		},
9981
9982
9983
9984
9985
9986		// Computes the ambiguously-timed moment for the given cell
9987
9988		getCellDate: function(row, col) {
9989
9990			return this.dayDates[
9991
9992				this.getCellDayIndex(row, col)
9993
9994				].clone();
9995
9996		},
9997
9998
9999
10000
10001
10002		// Computes the ambiguously-timed date range for the given cell
10003
10004		getCellRange: function(row, col) {
10005
10006			var start = this.getCellDate(row, col);
10007
10008			var end = start.clone().add(1, 'days');
10009
10010
10011
10012			return { start: start, end: end };
10013
10014		},
10015
10016
10017
10018
10019
10020		// Returns the number of day cells, chronologically, from the first of the grid (0-based)
10021
10022		getCellDayIndex: function(row, col) {
10023
10024			return row * this.daysPerRow + this.getColDayIndex(col);
10025
10026		},
10027
10028
10029
10030
10031
10032		// Returns the numner of day cells, chronologically, from the first cell in *any given row*
10033
10034		getColDayIndex: function(col) {
10035
10036			if (this.isRTL) {
10037
10038				return this.colCnt - 1 - col;
10039
10040			}
10041
10042			else {
10043
10044				return col;
10045
10046			}
10047
10048		},
10049
10050
10051
10052
10053
10054		// Given a date, returns its chronolocial cell-index from the first cell of the grid.
10055
10056		// If the date lies between cells (because of hiddenDays), returns a floating-point value between offsets.
10057
10058		// If before the first offset, returns a negative number.
10059
10060		// If after the last offset, returns an offset past the last cell offset.
10061
10062		// Only works for *start* dates of cells. Will not work for exclusive end dates for cells.
10063
10064		getDateDayIndex: function(date) {
10065
10066			var dayIndices = this.dayIndices;
10067
10068			var dayOffset = date.diff(this.start, 'days');
10069
10070
10071
10072			if (dayOffset < 0) {
10073
10074				return dayIndices[0] - 1;
10075
10076			}
10077
10078			else if (dayOffset >= dayIndices.length) {
10079
10080				return dayIndices[dayIndices.length - 1] + 1;
10081
10082			}
10083
10084			else {
10085
10086				return dayIndices[dayOffset];
10087
10088			}
10089
10090		},
10091
10092
10093
10094
10095
10096		/* Options
10097
10098		 ------------------------------------------------------------------------------------------------------------------*/
10099
10100
10101
10102
10103
10104		// Computes a default column header formatting string if `colFormat` is not explicitly defined
10105
10106		computeColHeadFormat: function() {
10107
10108			// if more than one week row, or if there are a lot of columns with not much space,
10109
10110			// put just the day numbers will be in each cell
10111
10112			if (this.rowCnt > 1 || this.colCnt > 10) {
10113
10114				return 'ddd'; // "Sat"
10115
10116			}
10117
10118			// multiple days, so full single date string WON'T be in title text
10119
10120			else if (this.colCnt > 1) {
10121
10122				return this.view.opt('dayOfMonthFormat'); // "Sat 12/10"
10123
10124			}
10125
10126			// single day, so full single date string will probably be in title text
10127
10128			else {
10129
10130				return 'dddd'; // "Saturday"
10131
10132			}
10133
10134		},
10135
10136
10137
10138
10139
10140		/* Slicing
10141
10142		 ------------------------------------------------------------------------------------------------------------------*/
10143
10144
10145
10146
10147
10148		// Slices up a date range into a segment for every week-row it intersects with
10149
10150		sliceRangeByRow: function(range) {
10151
10152			var daysPerRow = this.daysPerRow;
10153
10154			var normalRange = this.view.computeDayRange(range); // make whole-day range, considering nextDayThreshold
10155
10156			var rangeFirst = this.getDateDayIndex(normalRange.start); // inclusive first index
10157
10158			var rangeLast = this.getDateDayIndex(normalRange.end.clone().subtract(1, 'days')); // inclusive last index
10159
10160			var segs = [];
10161
10162			var row;
10163
10164			var rowFirst, rowLast; // inclusive day-index range for current row
10165
10166			var segFirst, segLast; // inclusive day-index range for segment
10167
10168
10169
10170			for (row = 0; row < this.rowCnt; row++) {
10171
10172				rowFirst = row * daysPerRow;
10173
10174				rowLast = rowFirst + daysPerRow - 1;
10175
10176
10177
10178				// intersect segment's offset range with the row's
10179
10180				segFirst = Math.max(rangeFirst, rowFirst);
10181
10182				segLast = Math.min(rangeLast, rowLast);
10183
10184
10185
10186				// deal with in-between indices
10187
10188				segFirst = Math.ceil(segFirst); // in-between starts round to next cell
10189
10190				segLast = Math.floor(segLast); // in-between ends round to prev cell
10191
10192
10193
10194				if (segFirst <= segLast) { // was there any intersection with the current row?
10195
10196					segs.push({
10197
10198						row: row,
10199
10200
10201
10202						// normalize to start of row
10203
10204						firstRowDayIndex: segFirst - rowFirst,
10205
10206						lastRowDayIndex: segLast - rowFirst,
10207
10208
10209
10210						// must be matching integers to be the segment's start/end
10211
10212						isStart: segFirst === rangeFirst,
10213
10214						isEnd: segLast === rangeLast
10215
10216					});
10217
10218				}
10219
10220			}
10221
10222
10223
10224			return segs;
10225
10226		},
10227
10228
10229
10230
10231
10232		// Slices up a date range into a segment for every day-cell it intersects with.
10233
10234		// TODO: make more DRY with sliceRangeByRow somehow.
10235
10236		sliceRangeByDay: function(range) {
10237
10238			var daysPerRow = this.daysPerRow;
10239
10240			var normalRange = this.view.computeDayRange(range); // make whole-day range, considering nextDayThreshold
10241
10242			var rangeFirst = this.getDateDayIndex(normalRange.start); // inclusive first index
10243
10244			var rangeLast = this.getDateDayIndex(normalRange.end.clone().subtract(1, 'days')); // inclusive last index
10245
10246			var segs = [];
10247
10248			var row;
10249
10250			var rowFirst, rowLast; // inclusive day-index range for current row
10251
10252			var i;
10253
10254			var segFirst, segLast; // inclusive day-index range for segment
10255
10256
10257
10258			for (row = 0; row < this.rowCnt; row++) {
10259
10260				rowFirst = row * daysPerRow;
10261
10262				rowLast = rowFirst + daysPerRow - 1;
10263
10264
10265
10266				for (i = rowFirst; i <= rowLast; i++) {
10267
10268
10269
10270					// intersect segment's offset range with the row's
10271
10272					segFirst = Math.max(rangeFirst, i);
10273
10274					segLast = Math.min(rangeLast, i);
10275
10276
10277
10278					// deal with in-between indices
10279
10280					segFirst = Math.ceil(segFirst); // in-between starts round to next cell
10281
10282					segLast = Math.floor(segLast); // in-between ends round to prev cell
10283
10284
10285
10286					if (segFirst <= segLast) { // was there any intersection with the current row?
10287
10288						segs.push({
10289
10290							row: row,
10291
10292
10293
10294							// normalize to start of row
10295
10296							firstRowDayIndex: segFirst - rowFirst,
10297
10298							lastRowDayIndex: segLast - rowFirst,
10299
10300
10301
10302							// must be matching integers to be the segment's start/end
10303
10304							isStart: segFirst === rangeFirst,
10305
10306							isEnd: segLast === rangeLast
10307
10308						});
10309
10310					}
10311
10312				}
10313
10314			}
10315
10316
10317
10318			return segs;
10319
10320		},
10321
10322
10323
10324
10325
10326		/* Header Rendering
10327
10328		 ------------------------------------------------------------------------------------------------------------------*/
10329
10330
10331
10332
10333
10334		renderHeadHtml: function() {
10335
10336			var view = this.view;
10337
10338
10339
10340			return '' +
10341
10342				'<div class="fc-row ' + view.widgetHeaderClass + '">' +
10343
10344				'<table>' +
10345
10346				'<thead>' +
10347
10348				this.renderHeadTrHtml() +
10349
10350				'</thead>' +
10351
10352				'</table>' +
10353
10354				'</div>';
10355
10356		},
10357
10358
10359
10360
10361
10362		renderHeadIntroHtml: function() {
10363
10364			return this.renderIntroHtml(); // fall back to generic
10365
10366		},
10367
10368
10369
10370
10371
10372		renderHeadTrHtml: function() {
10373
10374			return '' +
10375
10376				'<tr>' +
10377
10378				(this.isRTL ? '' : this.renderHeadIntroHtml()) +
10379
10380				this.renderHeadDateCellsHtml() +
10381
10382				(this.isRTL ? this.renderHeadIntroHtml() : '') +
10383
10384				'</tr>';
10385
10386		},
10387
10388
10389
10390
10391
10392		renderHeadDateCellsHtml: function() {
10393
10394			var htmls = [];
10395
10396			var col, date;
10397
10398
10399
10400			for (col = 0; col < this.colCnt; col++) {
10401
10402				date = this.getCellDate(0, col);
10403
10404				htmls.push(this.renderHeadDateCellHtml(date));
10405
10406			}
10407
10408
10409
10410			return htmls.join('');
10411
10412		},
10413
10414
10415
10416
10417
10418		renderHeadDateCellHtml: function(date, colspan) {
10419
10420			var view = this.view;
10421
10422
10423
10424			return '' +
10425
10426				'<th class="fc-day-header ' + view.widgetHeaderClass + ' fc-' + dayIDs[date.day()] + '"' +
10427
10428				(colspan > 1 ? ' colspan="' + colspan + '"' : '') +
10429
10430				'>' +
10431
10432				htmlEscape(date.format(this.colHeadFormat)) +
10433
10434				'</th>';
10435
10436		},
10437
10438
10439
10440
10441
10442		/* Background Rendering
10443
10444		 ------------------------------------------------------------------------------------------------------------------*/
10445
10446
10447
10448
10449
10450		renderBgTrHtml: function(row) {
10451
10452			return '' +
10453
10454				'<tr>' +
10455
10456				(this.isRTL ? '' : this.renderBgIntroHtml(row)) +
10457
10458				this.renderBgCellsHtml(row) +
10459
10460				(this.isRTL ? this.renderBgIntroHtml(row) : '') +
10461
10462				'</tr>';
10463
10464		},
10465
10466
10467
10468
10469
10470		renderBgIntroHtml: function(row) {
10471
10472			return this.renderIntroHtml(); // fall back to generic
10473
10474		},
10475
10476
10477
10478
10479
10480		renderBgCellsHtml: function(row) {
10481
10482			var htmls = [];
10483
10484			var col, date;
10485
10486
10487
10488			for (col = 0; col < this.colCnt; col++) {
10489
10490				date = this.getCellDate(row, col);
10491
10492				htmls.push(this.renderBgCellHtml(date));
10493
10494			}
10495
10496
10497
10498			return htmls.join('');
10499
10500		},
10501
10502
10503
10504
10505
10506		renderBgCellHtml: function(date) {
10507
10508			var view = this.view;
10509
10510			var classes = this.getDayClasses(date);
10511
10512
10513
10514			classes.unshift('fc-day', view.widgetContentClass);
10515
10516
10517
10518			return '<td class="' + classes.join(' ') + '"' +
10519
10520				' data-date="' + date.format('YYYY-MM-DD') + '"' + // if date has a time, won't format it
10521
10522				'></td>';
10523
10524		},
10525
10526
10527
10528
10529
10530		/* Generic
10531
10532		 ------------------------------------------------------------------------------------------------------------------*/
10533
10534
10535
10536
10537
10538		// Generates the default HTML intro for any row. User classes should override
10539
10540		renderIntroHtml: function() {
10541
10542		},
10543
10544
10545
10546
10547
10548		/* Utils
10549
10550		 ------------------------------------------------------------------------------------------------------------------*/
10551
10552
10553
10554
10555
10556		// Applies the generic "intro" and "outro" HTML to the given cells.
10557
10558		// Intro means the leftmost cell when the calendar is LTR and the rightmost cell when RTL. Vice-versa for outro.
10559
10560		bookendCells: function(trEl) {
10561
10562			var introHtml = this.renderIntroHtml();
10563
10564
10565
10566			if (introHtml) {
10567
10568				if (this.isRTL) {
10569
10570					trEl.append(introHtml);
10571
10572				}
10573
10574				else {
10575
10576					trEl.prepend(introHtml);
10577
10578				}
10579
10580			}
10581
10582		}
10583
10584
10585
10586	};
10587
10588
10589
10590	;;
10591
10592
10593
10594	/* A component that renders a grid of whole-days that runs horizontally. There can be multiple rows, one per week.
10595
10596	 ----------------------------------------------------------------------------------------------------------------------*/
10597
10598
10599
10600	var DayGrid = FC.DayGrid = Grid.extend(DayTableMixin, {
10601
10602
10603
10604		numbersVisible: false, // should render a row for day/week numbers? set by outside view. TODO: make internal
10605
10606		bottomCoordPadding: 0, // hack for extending the hit area for the last row of the coordinate grid
10607
10608
10609
10610		rowEls: null, // set of fake row elements
10611
10612		cellEls: null, // set of whole-day elements comprising the row's background
10613
10614		helperEls: null, // set of cell skeleton elements for rendering the mock event "helper"
10615
10616
10617
10618		rowCoordCache: null,
10619
10620		colCoordCache: null,
10621
10622
10623
10624
10625
10626		// Renders the rows and columns into the component's `this.el`, which should already be assigned.
10627
10628		// isRigid determins whether the individual rows should ignore the contents and be a constant height.
10629
10630		// Relies on the view's colCnt and rowCnt. In the future, this component should probably be self-sufficient.
10631
10632		renderDates: function(isRigid) {
10633
10634			var view = this.view;
10635
10636			var rowCnt = this.rowCnt;
10637
10638			var colCnt = this.colCnt;
10639
10640			var html = '';
10641
10642			var row;
10643
10644			var col;
10645
10646
10647
10648			for (row = 0; row < rowCnt; row++) {
10649
10650				html += this.renderDayRowHtml(row, isRigid);
10651
10652			}
10653
10654			this.el.html(html);
10655
10656
10657
10658			this.rowEls = this.el.find('.fc-row');
10659
10660			this.cellEls = this.el.find('.fc-day');
10661
10662
10663
10664			this.rowCoordCache = new CoordCache({
10665
10666				els: this.rowEls,
10667
10668				isVertical: true
10669
10670			});
10671
10672			this.colCoordCache = new CoordCache({
10673
10674				els: this.cellEls.slice(0, this.colCnt), // only the first row
10675
10676				isHorizontal: true
10677
10678			});
10679
10680
10681
10682			// trigger dayRender with each cell's element
10683
10684			for (row = 0; row < rowCnt; row++) {
10685
10686				for (col = 0; col < colCnt; col++) {
10687
10688					view.trigger(
10689
10690						'dayRender',
10691
10692						null,
10693
10694						this.getCellDate(row, col),
10695
10696						this.getCellEl(row, col)
10697
10698					);
10699
10700				}
10701
10702			}
10703
10704		},
10705
10706
10707
10708
10709
10710		unrenderDates: function() {
10711
10712			this.removeSegPopover();
10713
10714		},
10715
10716
10717
10718
10719
10720		renderBusinessHours: function() {
10721
10722			var events = this.view.calendar.getBusinessHoursEvents(true); // wholeDay=true
10723
10724			var segs = this.eventsToSegs(events);
10725
10726
10727
10728			this.renderFill('businessHours', segs, 'bgevent');
10729
10730		},
10731
10732
10733
10734
10735
10736		// Generates the HTML for a single row, which is a div that wraps a table.
10737
10738		// `row` is the row number.
10739
10740		renderDayRowHtml: function(row, isRigid) {
10741
10742			var view = this.view;
10743
10744			var classes = [ 'fc-row', 'fc-week', view.widgetContentClass ];
10745
10746
10747
10748			if (isRigid) {
10749
10750				classes.push('fc-rigid');
10751
10752			}
10753
10754
10755
10756			return '' +
10757
10758				'<div class="' + classes.join(' ') + '">' +
10759
10760				'<div class="fc-bg">' +
10761
10762				'<table>' +
10763
10764				this.renderBgTrHtml(row) +
10765
10766				'</table>' +
10767
10768				'</div>' +
10769
10770				'<div class="fc-content-skeleton">' +
10771
10772				'<table>' +
10773
10774				(this.numbersVisible ?
10775
10776					'<thead>' +
10777
10778					this.renderNumberTrHtml(row) +
10779
10780					'</thead>' :
10781
10782						''
10783
10784				) +
10785
10786				'</table>' +
10787
10788				'</div>' +
10789
10790				'</div>';
10791
10792		},
10793
10794
10795
10796
10797
10798		/* Grid Number Rendering
10799
10800		 ------------------------------------------------------------------------------------------------------------------*/
10801
10802
10803
10804
10805
10806		renderNumberTrHtml: function(row) {
10807
10808			return '' +
10809
10810				'<tr>' +
10811
10812				(this.isRTL ? '' : this.renderNumberIntroHtml(row)) +
10813
10814				this.renderNumberCellsHtml(row) +
10815
10816				(this.isRTL ? this.renderNumberIntroHtml(row) : '') +
10817
10818				'</tr>';
10819
10820		},
10821
10822
10823
10824
10825
10826		renderNumberIntroHtml: function(row) {
10827
10828			return this.renderIntroHtml();
10829
10830		},
10831
10832
10833
10834
10835
10836		renderNumberCellsHtml: function(row) {
10837
10838			var htmls = [];
10839
10840			var col, date;
10841
10842
10843
10844			for (col = 0; col < this.colCnt; col++) {
10845
10846				date = this.getCellDate(row, col);
10847
10848				htmls.push(this.renderNumberCellHtml(date));
10849
10850			}
10851
10852
10853
10854			return htmls.join('');
10855
10856		},
10857
10858
10859
10860
10861
10862		// Generates the HTML for the <td>s of the "number" row in the DayGrid's content skeleton.
10863
10864		// The number row will only exist if either day numbers or week numbers are turned on.
10865
10866		renderNumberCellHtml: function(date) {
10867
10868			var classes;
10869
10870
10871
10872			if (!this.view.dayNumbersVisible) { // if there are week numbers but not day numbers
10873
10874				return '<td/>'; //  will create an empty space above events :(
10875
10876			}
10877
10878
10879
10880			classes = this.getDayClasses(date);
10881
10882			classes.unshift('fc-day-number');
10883
10884
10885
10886			return '' +
10887
10888				'<td class="' + classes.join(' ') + '" data-date="' + date.format() + '">' +
10889
10890				date.date() +
10891
10892				'</td>';
10893
10894		},
10895
10896
10897
10898
10899
10900		/* Options
10901
10902		 ------------------------------------------------------------------------------------------------------------------*/
10903
10904
10905
10906
10907
10908		// Computes a default event time formatting string if `timeFormat` is not explicitly defined
10909
10910		computeEventTimeFormat: function() {
10911
10912			return this.view.opt('extraSmallTimeFormat'); // like "6p" or "6:30p"
10913
10914		},
10915
10916
10917
10918
10919
10920		// Computes a default `displayEventEnd` value if one is not expliclty defined
10921
10922		computeDisplayEventEnd: function() {
10923
10924			return this.colCnt == 1; // we'll likely have space if there's only one day
10925
10926		},
10927
10928
10929
10930
10931
10932		/* Dates
10933
10934		 ------------------------------------------------------------------------------------------------------------------*/
10935
10936
10937
10938
10939
10940		rangeUpdated: function() {
10941
10942			this.updateDayTable();
10943
10944		},
10945
10946
10947
10948
10949
10950		// Slices up the given span (unzoned start/end with other misc data) into an array of segments
10951
10952		spanToSegs: function(span) {
10953
10954			var segs = this.sliceRangeByRow(span);
10955
10956			var i, seg;
10957
10958
10959
10960			for (i = 0; i < segs.length; i++) {
10961
10962				seg = segs[i];
10963
10964				if (this.isRTL) {
10965
10966					seg.leftCol = this.daysPerRow - 1 - seg.lastRowDayIndex;
10967
10968					seg.rightCol = this.daysPerRow - 1 - seg.firstRowDayIndex;
10969
10970				}
10971
10972				else {
10973
10974					seg.leftCol = seg.firstRowDayIndex;
10975
10976					seg.rightCol = seg.lastRowDayIndex;
10977
10978				}
10979
10980			}
10981
10982
10983
10984			return segs;
10985
10986		},
10987
10988
10989
10990
10991
10992		/* Hit System
10993
10994		 ------------------------------------------------------------------------------------------------------------------*/
10995
10996
10997
10998
10999
11000		prepareHits: function() {
11001
11002			this.colCoordCache.build();
11003
11004			this.rowCoordCache.build();
11005
11006			this.rowCoordCache.bottoms[this.rowCnt - 1] += this.bottomCoordPadding; // hack
11007
11008		},
11009
11010
11011
11012
11013
11014		releaseHits: function() {
11015
11016			this.colCoordCache.clear();
11017
11018			this.rowCoordCache.clear();
11019
11020		},
11021
11022
11023
11024
11025
11026		queryHit: function(leftOffset, topOffset) {
11027
11028			var col = this.colCoordCache.getHorizontalIndex(leftOffset);
11029
11030			var row = this.rowCoordCache.getVerticalIndex(topOffset);
11031
11032
11033
11034			if (row != null && col != null) {
11035
11036				return this.getCellHit(row, col);
11037
11038			}
11039
11040		},
11041
11042
11043
11044
11045
11046		getHitSpan: function(hit) {
11047
11048			return this.getCellRange(hit.row, hit.col);
11049
11050		},
11051
11052
11053
11054
11055
11056		getHitEl: function(hit) {
11057
11058			return this.getCellEl(hit.row, hit.col);
11059
11060		},
11061
11062
11063
11064
11065
11066		/* Cell System
11067
11068		 ------------------------------------------------------------------------------------------------------------------*/
11069
11070		// FYI: the first column is the leftmost column, regardless of date
11071
11072
11073
11074
11075
11076		getCellHit: function(row, col) {
11077
11078			return {
11079
11080				row: row,
11081
11082				col: col,
11083
11084				component: this, // needed unfortunately :(
11085
11086				left: this.colCoordCache.getLeftOffset(col),
11087
11088				right: this.colCoordCache.getRightOffset(col),
11089
11090				top: this.rowCoordCache.getTopOffset(row),
11091
11092				bottom: this.rowCoordCache.getBottomOffset(row)
11093
11094			};
11095
11096		},
11097
11098
11099
11100
11101
11102		getCellEl: function(row, col) {
11103
11104			return this.cellEls.eq(row * this.colCnt + col);
11105
11106		},
11107
11108
11109
11110
11111
11112		/* Event Drag Visualization
11113
11114		 ------------------------------------------------------------------------------------------------------------------*/
11115
11116		// TODO: move to DayGrid.event, similar to what we did with Grid's drag methods
11117
11118
11119
11120
11121
11122		// Renders a visual indication of an event or external element being dragged.
11123
11124		// `eventLocation` has zoned start and end (optional)
11125
11126		renderDrag: function(eventLocation, seg) {
11127
11128
11129
11130			// always render a highlight underneath
11131
11132			this.renderHighlight(this.eventToSpan(eventLocation));
11133
11134
11135
11136			// if a segment from the same calendar but another component is being dragged, render a helper event
11137
11138			if (seg && !seg.el.closest(this.el).length) {
11139
11140
11141
11142				this.renderEventLocationHelper(eventLocation, seg);
11143
11144				this.applyDragOpacity(this.helperEls);
11145
11146
11147
11148				return true; // a helper has been rendered
11149
11150			}
11151
11152		},
11153
11154
11155
11156
11157
11158		// Unrenders any visual indication of a hovering event
11159
11160		unrenderDrag: function() {
11161
11162			this.unrenderHighlight();
11163
11164			this.unrenderHelper();
11165
11166		},
11167
11168
11169
11170
11171
11172		/* Event Resize Visualization
11173
11174		 ------------------------------------------------------------------------------------------------------------------*/
11175
11176
11177
11178
11179
11180		// Renders a visual indication of an event being resized
11181
11182		renderEventResize: function(eventLocation, seg) {
11183
11184			this.renderHighlight(this.eventToSpan(eventLocation));
11185
11186			this.renderEventLocationHelper(eventLocation, seg);
11187
11188		},
11189
11190
11191
11192
11193
11194		// Unrenders a visual indication of an event being resized
11195
11196		unrenderEventResize: function() {
11197
11198			this.unrenderHighlight();
11199
11200			this.unrenderHelper();
11201
11202		},
11203
11204
11205
11206
11207
11208		/* Event Helper
11209
11210		 ------------------------------------------------------------------------------------------------------------------*/
11211
11212
11213
11214
11215
11216		// Renders a mock "helper" event. `sourceSeg` is the associated internal segment object. It can be null.
11217
11218		renderHelper: function(event, sourceSeg) {
11219
11220			var helperNodes = [];
11221
11222			var segs = this.eventToSegs(event);
11223
11224			var rowStructs;
11225
11226
11227
11228			segs = this.renderFgSegEls(segs); // assigns each seg's el and returns a subset of segs that were rendered
11229
11230			rowStructs = this.renderSegRows(segs);
11231
11232
11233
11234			// inject each new event skeleton into each associated row
11235
11236			this.rowEls.each(function(row, rowNode) {
11237
11238				var rowEl = $(rowNode); // the .fc-row
11239
11240				var skeletonEl = $('<div class="fc-helper-skeleton"><table/></div>'); // will be absolutely positioned
11241
11242				var skeletonTop;
11243
11244
11245
11246				// If there is an original segment, match the top position. Otherwise, put it at the row's top level
11247
11248				if (sourceSeg && sourceSeg.row === row) {
11249
11250					skeletonTop = sourceSeg.el.position().top;
11251
11252				}
11253
11254				else {
11255
11256					skeletonTop = rowEl.find('.fc-content-skeleton tbody').position().top;
11257
11258				}
11259
11260
11261
11262				skeletonEl.css('top', skeletonTop)
11263
11264					.find('table')
11265
11266					.append(rowStructs[row].tbodyEl);
11267
11268
11269
11270				rowEl.append(skeletonEl);
11271
11272				helperNodes.push(skeletonEl[0]);
11273
11274			});
11275
11276
11277
11278			this.helperEls = $(helperNodes); // array -> jQuery set
11279
11280		},
11281
11282
11283
11284
11285
11286		// Unrenders any visual indication of a mock helper event
11287
11288		unrenderHelper: function() {
11289
11290			if (this.helperEls) {
11291
11292				this.helperEls.remove();
11293
11294				this.helperEls = null;
11295
11296			}
11297
11298		},
11299
11300
11301
11302
11303
11304		/* Fill System (highlight, background events, business hours)
11305
11306		 ------------------------------------------------------------------------------------------------------------------*/
11307
11308
11309
11310
11311
11312		fillSegTag: 'td', // override the default tag name
11313
11314
11315
11316
11317
11318		// Renders a set of rectangles over the given segments of days.
11319
11320		// Only returns segments that successfully rendered.
11321
11322		renderFill: function(type, segs, className) {
11323
11324			var nodes = [];
11325
11326			var i, seg;
11327
11328			var skeletonEl;
11329
11330
11331
11332			segs = this.renderFillSegEls(type, segs); // assignes `.el` to each seg. returns successfully rendered segs
11333
11334
11335
11336			for (i = 0; i < segs.length; i++) {
11337
11338				seg = segs[i];
11339
11340				skeletonEl = this.renderFillRow(type, seg, className);
11341
11342				this.rowEls.eq(seg.row).append(skeletonEl);
11343
11344				nodes.push(skeletonEl[0]);
11345
11346			}
11347
11348
11349
11350			this.elsByFill[type] = $(nodes);
11351
11352
11353
11354			return segs;
11355
11356		},
11357
11358
11359
11360
11361
11362		// Generates the HTML needed for one row of a fill. Requires the seg's el to be rendered.
11363
11364		renderFillRow: function(type, seg, className) {
11365
11366			var colCnt = this.colCnt;
11367
11368			var startCol = seg.leftCol;
11369
11370			var endCol = seg.rightCol + 1;
11371
11372			var skeletonEl;
11373
11374			var trEl;
11375
11376
11377
11378			className = className || type.toLowerCase();
11379
11380
11381
11382			skeletonEl = $(
11383
11384				'<div class="fc-' + className + '-skeleton">' +
11385
11386				'<table><tr/></table>' +
11387
11388				'</div>'
11389
11390			);
11391
11392			trEl = skeletonEl.find('tr');
11393
11394
11395
11396			if (startCol > 0) {
11397
11398				trEl.append('<td colspan="' + startCol + '"/>');
11399
11400			}
11401
11402
11403
11404			trEl.append(
11405
11406				seg.el.attr('colspan', endCol - startCol)
11407
11408			);
11409
11410
11411
11412			if (endCol < colCnt) {
11413
11414				trEl.append('<td colspan="' + (colCnt - endCol) + '"/>');
11415
11416			}
11417
11418
11419
11420			this.bookendCells(trEl);
11421
11422
11423
11424			return skeletonEl;
11425
11426		}
11427
11428
11429
11430	});
11431
11432
11433
11434	;;
11435
11436
11437
11438	/* Event-rendering methods for the DayGrid class
11439
11440	 ----------------------------------------------------------------------------------------------------------------------*/
11441
11442
11443
11444	DayGrid.mixin({
11445
11446
11447
11448		rowStructs: null, // an array of objects, each holding information about a row's foreground event-rendering
11449
11450
11451
11452
11453
11454		// Unrenders all events currently rendered on the grid
11455
11456		unrenderEvents: function() {
11457
11458			this.removeSegPopover(); // removes the "more.." events popover
11459
11460			Grid.prototype.unrenderEvents.apply(this, arguments); // calls the super-method
11461
11462		},
11463
11464
11465
11466
11467
11468		// Retrieves all rendered segment objects currently rendered on the grid
11469
11470		getEventSegs: function() {
11471
11472			return Grid.prototype.getEventSegs.call(this) // get the segments from the super-method
11473
11474				.concat(this.popoverSegs || []); // append the segments from the "more..." popover
11475
11476		},
11477
11478
11479
11480
11481
11482		// Renders the given background event segments onto the grid
11483
11484		renderBgSegs: function(segs) {
11485
11486
11487
11488			// don't render timed background events
11489
11490			var allDaySegs = $.grep(segs, function(seg) {
11491
11492				return seg.event.allDay;
11493
11494			});
11495
11496
11497
11498			return Grid.prototype.renderBgSegs.call(this, allDaySegs); // call the super-method
11499
11500		},
11501
11502
11503
11504
11505
11506		// Renders the given foreground event segments onto the grid
11507
11508		renderFgSegs: function(segs) {
11509
11510			var rowStructs;
11511
11512
11513
11514			// render an `.el` on each seg
11515
11516			// returns a subset of the segs. segs that were actually rendered
11517
11518			segs = this.renderFgSegEls(segs);
11519
11520
11521
11522			rowStructs = this.rowStructs = this.renderSegRows(segs);
11523
11524
11525
11526			// append to each row's content skeleton
11527
11528			this.rowEls.each(function(i, rowNode) {
11529
11530				$(rowNode).find('.fc-content-skeleton > table').append(
11531
11532					rowStructs[i].tbodyEl
11533
11534				);
11535
11536			});
11537
11538
11539
11540			return segs; // return only the segs that were actually rendered
11541
11542		},
11543
11544
11545
11546
11547
11548		// Unrenders all currently rendered foreground event segments
11549
11550		unrenderFgSegs: function() {
11551
11552			var rowStructs = this.rowStructs || [];
11553
11554			var rowStruct;
11555
11556
11557
11558			while ((rowStruct = rowStructs.pop())) {
11559
11560				rowStruct.tbodyEl.remove();
11561
11562			}
11563
11564
11565
11566			this.rowStructs = null;
11567
11568		},
11569
11570
11571
11572
11573
11574		// Uses the given events array to generate <tbody> elements that should be appended to each row's content skeleton.
11575
11576		// Returns an array of rowStruct objects (see the bottom of `renderSegRow`).
11577
11578		// PRECONDITION: each segment shoud already have a rendered and assigned `.el`
11579
11580		renderSegRows: function(segs) {
11581
11582			var rowStructs = [];
11583
11584			var segRows;
11585
11586			var row;
11587
11588
11589
11590			segRows = this.groupSegRows(segs); // group into nested arrays
11591
11592
11593
11594			// iterate each row of segment groupings
11595
11596			for (row = 0; row < segRows.length; row++) {
11597
11598				rowStructs.push(
11599
11600					this.renderSegRow(row, segRows[row])
11601
11602				);
11603
11604			}
11605
11606
11607
11608			return rowStructs;
11609
11610		},
11611
11612
11613
11614
11615
11616		// Builds the HTML to be used for the default element for an individual segment
11617
11618		fgSegHtml: function(seg, disableResizing) {
11619
11620			var view = this.view;
11621
11622			var event = seg.event;
11623
11624			var isDraggable = view.isEventDraggable(event);
11625
11626			var isResizableFromStart = !disableResizing && event.allDay &&
11627
11628				seg.isStart && view.isEventResizableFromStart(event);
11629
11630			var isResizableFromEnd = !disableResizing && event.allDay &&
11631
11632				seg.isEnd && view.isEventResizableFromEnd(event);
11633
11634			var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
11635
11636			var skinCss = cssToStr(this.getEventSkinCss(event));
11637
11638			var timeHtml = '';
11639
11640			var timeText;
11641
11642			var titleHtml;
11643
11644
11645
11646			classes.unshift('fc-day-grid-event', 'fc-h-event');
11647
11648
11649
11650			// Only display a timed events time if it is the starting segment
11651
11652			if (seg.isStart) {
11653
11654				timeText = this.getEventTimeText(event);
11655
11656				if (timeText) {
11657
11658					timeHtml = '<span class="fc-time">' + htmlEscape(timeText) + '</span>';
11659
11660				}
11661
11662			}
11663
11664
11665
11666			titleHtml =
11667
11668				'<span class="fc-title" id="'+event.id+'">' +
11669
11670				(htmlEscape(event.title || '') || '&nbsp;') + // we always want one line of height
11671
11672				'</span>';
11673
11674
11675
11676			return '<a class="' + classes.join(' ') + '"' +
11677
11678				(event.url ?
11679
11680					' href="' + htmlEscape(event.url) + '"' :
11681
11682						''
11683
11684				) +
11685
11686				(skinCss ?
11687
11688					' style="' + skinCss + '"' :
11689
11690						''
11691
11692				) +
11693
11694				'>' +
11695
11696				'<div class="fc-content">' +
11697
11698				(this.isRTL ?
11699
11700					titleHtml + ' ' + timeHtml : // put a natural space in between
11701
11702					timeHtml + ' ' + titleHtml   //
11703
11704				) +
11705
11706				'</div>' +
11707
11708				(isResizableFromStart ?
11709
11710						'<div class="fc-resizer fc-start-resizer" />' :
11711
11712						''
11713
11714				) +
11715
11716				(isResizableFromEnd ?
11717
11718						'<div class="fc-resizer fc-end-resizer" />' :
11719
11720						''
11721
11722				) +
11723
11724				'</a>';
11725
11726		},
11727
11728
11729
11730
11731
11732		// Given a row # and an array of segments all in the same row, render a <tbody> element, a skeleton that contains
11733
11734		// the segments. Returns object with a bunch of internal data about how the render was calculated.
11735
11736		// NOTE: modifies rowSegs
11737
11738		renderSegRow: function(row, rowSegs) {
11739
11740			var colCnt = this.colCnt;
11741
11742			var segLevels = this.buildSegLevels(rowSegs); // group into sub-arrays of levels
11743
11744			var levelCnt = Math.max(1, segLevels.length); // ensure at least one level
11745
11746			var tbody = $('<tbody/>');
11747
11748			var segMatrix = []; // lookup for which segments are rendered into which level+col cells
11749
11750			var cellMatrix = []; // lookup for all <td> elements of the level+col matrix
11751
11752			var loneCellMatrix = []; // lookup for <td> elements that only take up a single column
11753
11754			var i, levelSegs;
11755
11756			var col;
11757
11758			var tr;
11759
11760			var j, seg;
11761
11762			var td;
11763
11764
11765
11766			// populates empty cells from the current column (`col`) to `endCol`
11767
11768			function emptyCellsUntil(endCol) {
11769
11770				while (col < endCol) {
11771
11772					// try to grab a cell from the level above and extend its rowspan. otherwise, create a fresh cell
11773
11774					td = (loneCellMatrix[i - 1] || [])[col];
11775
11776					if (td) {
11777
11778						td.attr(
11779
11780							'rowspan',
11781
11782							parseInt(td.attr('rowspan') || 1, 10) + 1
11783
11784						);
11785
11786					}
11787
11788					else {
11789
11790						td = $('<td/>');
11791
11792						tr.append(td);
11793
11794					}
11795
11796					cellMatrix[i][col] = td;
11797
11798					loneCellMatrix[i][col] = td;
11799
11800					col++;
11801
11802				}
11803
11804			}
11805
11806
11807
11808			for (i = 0; i < levelCnt; i++) { // iterate through all levels
11809
11810				levelSegs = segLevels[i];
11811
11812				col = 0;
11813
11814				tr = $('<tr/>');
11815
11816
11817
11818				segMatrix.push([]);
11819
11820				cellMatrix.push([]);
11821
11822				loneCellMatrix.push([]);
11823
11824
11825
11826				// levelCnt might be 1 even though there are no actual levels. protect against this.
11827
11828				// this single empty row is useful for styling.
11829
11830				if (levelSegs) {
11831
11832					for (j = 0; j < levelSegs.length; j++) { // iterate through segments in level
11833
11834						seg = levelSegs[j];
11835
11836
11837
11838						emptyCellsUntil(seg.leftCol);
11839
11840
11841
11842						// create a container that occupies or more columns. append the event element.
11843
11844						td = $('<td class="fc-event-container"/>').append(seg.el);
11845
11846						if (seg.leftCol != seg.rightCol) {
11847
11848							td.attr('colspan', seg.rightCol - seg.leftCol + 1);
11849
11850						}
11851
11852						else { // a single-column segment
11853
11854							loneCellMatrix[i][col] = td;
11855
11856						}
11857
11858
11859
11860						while (col <= seg.rightCol) {
11861
11862							cellMatrix[i][col] = td;
11863
11864							segMatrix[i][col] = seg;
11865
11866							col++;
11867
11868						}
11869
11870
11871
11872						tr.append(td);
11873
11874					}
11875
11876				}
11877
11878
11879
11880				emptyCellsUntil(colCnt); // finish off the row
11881
11882				this.bookendCells(tr);
11883
11884				tbody.append(tr);
11885
11886			}
11887
11888
11889
11890			return { // a "rowStruct"
11891
11892				row: row, // the row number
11893
11894				tbodyEl: tbody,
11895
11896				cellMatrix: cellMatrix,
11897
11898				segMatrix: segMatrix,
11899
11900				segLevels: segLevels,
11901
11902				segs: rowSegs
11903
11904			};
11905
11906		},
11907
11908
11909
11910
11911
11912		// Stacks a flat array of segments, which are all assumed to be in the same row, into subarrays of vertical levels.
11913
11914		// NOTE: modifies segs
11915
11916		buildSegLevels: function(segs) {
11917
11918			var levels = [];
11919
11920			var i, seg;
11921
11922			var j;
11923
11924
11925
11926			// Give preference to elements with certain criteria, so they have
11927
11928			// a chance to be closer to the top.
11929
11930			this.sortEventSegs(segs);
11931
11932
11933
11934			for (i = 0; i < segs.length; i++) {
11935
11936				seg = segs[i];
11937
11938
11939
11940				// loop through levels, starting with the topmost, until the segment doesn't collide with other segments
11941
11942				for (j = 0; j < levels.length; j++) {
11943
11944					if (!isDaySegCollision(seg, levels[j])) {
11945
11946						break;
11947
11948					}
11949
11950				}
11951
11952				// `j` now holds the desired subrow index
11953
11954				seg.level = j;
11955
11956
11957
11958				// create new level array if needed and append segment
11959
11960				(levels[j] || (levels[j] = [])).push(seg);
11961
11962			}
11963
11964
11965
11966			// order segments left-to-right. very important if calendar is RTL
11967
11968			for (j = 0; j < levels.length; j++) {
11969
11970				levels[j].sort(compareDaySegCols);
11971
11972			}
11973
11974
11975
11976			return levels;
11977
11978		},
11979
11980
11981
11982
11983
11984		// Given a flat array of segments, return an array of sub-arrays, grouped by each segment's row
11985
11986		groupSegRows: function(segs) {
11987
11988			var segRows = [];
11989
11990			var i;
11991
11992
11993
11994			for (i = 0; i < this.rowCnt; i++) {
11995
11996				segRows.push([]);
11997
11998			}
11999
12000
12001
12002			for (i = 0; i < segs.length; i++) {
12003
12004				segRows[segs[i].row].push(segs[i]);
12005
12006			}
12007
12008
12009
12010			return segRows;
12011
12012		}
12013
12014
12015
12016	});
12017
12018
12019
12020
12021
12022// Computes whether two segments' columns collide. They are assumed to be in the same row.
12023
12024	function isDaySegCollision(seg, otherSegs) {
12025
12026		var i, otherSeg;
12027
12028
12029
12030		for (i = 0; i < otherSegs.length; i++) {
12031
12032			otherSeg = otherSegs[i];
12033
12034
12035
12036			if (
12037
12038				otherSeg.leftCol <= seg.rightCol &&
12039
12040				otherSeg.rightCol >= seg.leftCol
12041
12042			) {
12043
12044				return true;
12045
12046			}
12047
12048		}
12049
12050
12051
12052		return false;
12053
12054	}
12055
12056
12057
12058
12059
12060// A cmp function for determining the leftmost event
12061
12062	function compareDaySegCols(a, b) {
12063
12064		return a.leftCol - b.leftCol;
12065
12066	}
12067
12068
12069
12070	;;
12071
12072
12073
12074	/* Methods relate to limiting the number events for a given day on a DayGrid
12075
12076	 ----------------------------------------------------------------------------------------------------------------------*/
12077
12078// NOTE: all the segs being passed around in here are foreground segs
12079
12080
12081
12082	DayGrid.mixin({
12083
12084
12085
12086		segPopover: null, // the Popover that holds events that can't fit in a cell. null when not visible
12087
12088		popoverSegs: null, // an array of segment objects that the segPopover holds. null when not visible
12089
12090
12091
12092
12093
12094		removeSegPopover: function() {
12095
12096			if (this.segPopover) {
12097
12098				this.segPopover.hide(); // in handler, will call segPopover's removeElement
12099
12100			}
12101
12102		},
12103
12104
12105
12106
12107
12108		// Limits the number of "levels" (vertically stacking layers of events) for each row of the grid.
12109
12110		// `levelLimit` can be false (don't limit), a number, or true (should be computed).
12111
12112		limitRows: function(levelLimit) {
12113
12114			var rowStructs = this.rowStructs || [];
12115
12116			var row; // row #
12117
12118			var rowLevelLimit;
12119
12120
12121
12122			for (row = 0; row < rowStructs.length; row++) {
12123
12124				this.unlimitRow(row);
12125
12126
12127
12128				if (!levelLimit) {
12129
12130					rowLevelLimit = false;
12131
12132				}
12133
12134				else if (typeof levelLimit === 'number') {
12135
12136					rowLevelLimit = levelLimit;
12137
12138				}
12139
12140				else {
12141
12142					rowLevelLimit = this.computeRowLevelLimit(row);
12143
12144				}
12145
12146
12147
12148				if (rowLevelLimit !== false) {
12149
12150					this.limitRow(row, rowLevelLimit);
12151
12152				}
12153
12154			}
12155
12156		},
12157
12158
12159
12160
12161
12162		// Computes the number of levels a row will accomodate without going outside its bounds.
12163
12164		// Assumes the row is "rigid" (maintains a constant height regardless of what is inside).
12165
12166		// `row` is the row number.
12167
12168		computeRowLevelLimit: function(row) {
12169
12170			var rowEl = this.rowEls.eq(row); // the containing "fake" row div
12171
12172			var rowHeight = rowEl.height(); // TODO: cache somehow?
12173
12174			var trEls = this.rowStructs[row].tbodyEl.children();
12175
12176			var i, trEl;
12177
12178			var trHeight;
12179
12180
12181
12182			function iterInnerHeights(i, childNode) {
12183
12184				trHeight = Math.max(trHeight, $(childNode).outerHeight());
12185
12186			}
12187
12188
12189
12190			// Reveal one level <tr> at a time and stop when we find one out of bounds
12191
12192			for (i = 0; i < trEls.length; i++) {
12193
12194				trEl = trEls.eq(i).removeClass('fc-limited'); // reset to original state (reveal)
12195
12196
12197
12198				// with rowspans>1 and IE8, trEl.outerHeight() would return the height of the largest cell,
12199
12200				// so instead, find the tallest inner content element.
12201
12202				trHeight = 0;
12203
12204				trEl.find('> td > :first-child').each(iterInnerHeights);
12205
12206
12207
12208				if (trEl.position().top + trHeight > rowHeight) {
12209
12210					return i;
12211
12212				}
12213
12214			}
12215
12216
12217
12218			return false; // should not limit at all
12219
12220		},
12221
12222
12223
12224
12225
12226		// Limits the given grid row to the maximum number of levels and injects "more" links if necessary.
12227
12228		// `row` is the row number.
12229
12230		// `levelLimit` is a number for the maximum (inclusive) number of levels allowed.
12231
12232		limitRow: function(row, levelLimit) {
12233
12234			var _this = this;
12235
12236			var rowStruct = this.rowStructs[row];
12237
12238			var moreNodes = []; // array of "more" <a> links and <td> DOM nodes
12239
12240			var col = 0; // col #, left-to-right (not chronologically)
12241
12242			var levelSegs; // array of segment objects in the last allowable level, ordered left-to-right
12243
12244			var cellMatrix; // a matrix (by level, then column) of all <td> jQuery elements in the row
12245
12246			var limitedNodes; // array of temporarily hidden level <tr> and segment <td> DOM nodes
12247
12248			var i, seg;
12249
12250			var segsBelow; // array of segment objects below `seg` in the current `col`
12251
12252			var totalSegsBelow; // total number of segments below `seg` in any of the columns `seg` occupies
12253
12254			var colSegsBelow; // array of segment arrays, below seg, one for each column (offset from segs's first column)
12255
12256			var td, rowspan;
12257
12258			var segMoreNodes; // array of "more" <td> cells that will stand-in for the current seg's cell
12259
12260			var j;
12261
12262			var moreTd, moreWrap, moreLink;
12263
12264
12265
12266			// Iterates through empty level cells and places "more" links inside if need be
12267
12268			function emptyCellsUntil(endCol) { // goes from current `col` to `endCol`
12269
12270				while (col < endCol) {
12271
12272					segsBelow = _this.getCellSegs(row, col, levelLimit);
12273
12274					if (segsBelow.length) {
12275
12276						td = cellMatrix[levelLimit - 1][col];
12277
12278						moreLink = _this.renderMoreLink(row, col, segsBelow);
12279
12280						moreWrap = $('<div/>').append(moreLink);
12281
12282						td.append(moreWrap);
12283
12284						moreNodes.push(moreWrap[0]);
12285
12286					}
12287
12288					col++;
12289
12290				}
12291
12292			}
12293
12294
12295
12296			if (levelLimit && levelLimit < rowStruct.segLevels.length) { // is it actually over the limit?
12297
12298				levelSegs = rowStruct.segLevels[levelLimit - 1];
12299
12300				cellMatrix = rowStruct.cellMatrix;
12301
12302
12303
12304				limitedNodes = rowStruct.tbodyEl.children().slice(levelLimit) // get level <tr> elements past the limit
12305
12306					.addClass('fc-limited').get(); // hide elements and get a simple DOM-nodes array
12307
12308
12309
12310				// iterate though segments in the last allowable level
12311
12312				for (i = 0; i < levelSegs.length; i++) {
12313
12314					seg = levelSegs[i];
12315
12316					emptyCellsUntil(seg.leftCol); // process empty cells before the segment
12317
12318
12319
12320					// determine *all* segments below `seg` that occupy the same columns
12321
12322					colSegsBelow = [];
12323
12324					totalSegsBelow = 0;
12325
12326					while (col <= seg.rightCol) {
12327
12328						segsBelow = this.getCellSegs(row, col, levelLimit);
12329
12330						colSegsBelow.push(segsBelow);
12331
12332						totalSegsBelow += segsBelow.length;
12333
12334						col++;
12335
12336					}
12337
12338
12339
12340					if (totalSegsBelow) { // do we need to replace this segment with one or many "more" links?
12341
12342						td = cellMatrix[levelLimit - 1][seg.leftCol]; // the segment's parent cell
12343
12344						rowspan = td.attr('rowspan') || 1;
12345
12346						segMoreNodes = [];
12347
12348
12349
12350						// make a replacement <td> for each column the segment occupies. will be one for each colspan
12351
12352						for (j = 0; j < colSegsBelow.length; j++) {
12353
12354							moreTd = $('<td class="fc-more-cell"/>').attr('rowspan', rowspan);
12355
12356							segsBelow = colSegsBelow[j];
12357
12358							moreLink = this.renderMoreLink(
12359
12360								row,
12361
12362								seg.leftCol + j,
12363
12364								[ seg ].concat(segsBelow) // count seg as hidden too
12365
12366							);
12367
12368							moreWrap = $('<div/>').append(moreLink);
12369
12370							moreTd.append(moreWrap);
12371
12372							segMoreNodes.push(moreTd[0]);
12373
12374							moreNodes.push(moreTd[0]);
12375
12376						}
12377
12378
12379
12380						td.addClass('fc-limited').after($(segMoreNodes)); // hide original <td> and inject replacements
12381
12382						limitedNodes.push(td[0]);
12383
12384					}
12385
12386				}
12387
12388
12389
12390				emptyCellsUntil(this.colCnt); // finish off the level
12391
12392				rowStruct.moreEls = $(moreNodes); // for easy undoing later
12393
12394				rowStruct.limitedEls = $(limitedNodes); // for easy undoing later
12395
12396			}
12397
12398		},
12399
12400
12401
12402
12403
12404		// Reveals all levels and removes all "more"-related elements for a grid's row.
12405
12406		// `row` is a row number.
12407
12408		unlimitRow: function(row) {
12409
12410			var rowStruct = this.rowStructs[row];
12411
12412
12413
12414			if (rowStruct.moreEls) {
12415
12416				rowStruct.moreEls.remove();
12417
12418				rowStruct.moreEls = null;
12419
12420			}
12421
12422
12423
12424			if (rowStruct.limitedEls) {
12425
12426				rowStruct.limitedEls.removeClass('fc-limited');
12427
12428				rowStruct.limitedEls = null;
12429
12430			}
12431
12432		},
12433
12434
12435
12436
12437
12438		// Renders an <a> element that represents hidden event element for a cell.
12439
12440		// Responsible for attaching click handler as well.
12441
12442		renderMoreLink: function(row, col, hiddenSegs) {
12443
12444			var _this = this;
12445
12446			var view = this.view;
12447
12448
12449
12450			return $('<a class="fc-more"/>')
12451
12452				.text(
12453
12454					this.getMoreLinkText(hiddenSegs.length)
12455
12456				)
12457
12458				.on('click', function(ev) {
12459
12460					var clickOption = view.opt('eventLimitClick');
12461
12462					var date = _this.getCellDate(row, col);
12463
12464					var moreEl = $(this);
12465
12466					var dayEl = _this.getCellEl(row, col);
12467
12468					var allSegs = _this.getCellSegs(row, col);
12469
12470
12471
12472					// rescope the segments to be within the cell's date
12473
12474					var reslicedAllSegs = _this.resliceDaySegs(allSegs, date);
12475
12476					var reslicedHiddenSegs = _this.resliceDaySegs(hiddenSegs, date);
12477
12478
12479
12480					if (typeof clickOption === 'function') {
12481
12482						// the returned value can be an atomic option
12483
12484						clickOption = view.trigger('eventLimitClick', null, {
12485
12486							date: date,
12487
12488							dayEl: dayEl,
12489
12490							moreEl: moreEl,
12491
12492							segs: reslicedAllSegs,
12493
12494							hiddenSegs: reslicedHiddenSegs
12495
12496						}, ev);
12497
12498					}
12499
12500
12501
12502					if (clickOption === 'popover') {
12503
12504						_this.showSegPopover(row, col, moreEl, reslicedAllSegs);
12505
12506					}
12507
12508					else if (typeof clickOption === 'string') { // a view name
12509
12510						view.calendar.zoomTo(date, clickOption);
12511
12512					}
12513
12514				});
12515
12516		},
12517
12518
12519
12520
12521
12522		// Reveals the popover that displays all events within a cell
12523
12524		showSegPopover: function(row, col, moreLink, segs) {
12525
12526			var _this = this;
12527
12528			var view = this.view;
12529
12530			var moreWrap = moreLink.parent(); // the <div> wrapper around the <a>
12531
12532			var topEl; // the element we want to match the top coordinate of
12533
12534			var options;
12535
12536
12537
12538			if (this.rowCnt == 1) {
12539
12540				topEl = view.el; // will cause the popover to cover any sort of header
12541
12542			}
12543
12544			else {
12545
12546				topEl = this.rowEls.eq(row); // will align with top of row
12547
12548			}
12549
12550
12551
12552			options = {
12553
12554				className: 'fc-more-popover',
12555
12556				content: this.renderSegPopoverContent(row, col, segs),
12557
12558				parentEl: this.el,
12559
12560				top: topEl.offset().top,
12561
12562				autoHide: true, // when the user clicks elsewhere, hide the popover
12563
12564				viewportConstrain: view.opt('popoverViewportConstrain'),
12565
12566				hide: function() {
12567
12568					// kill everything when the popover is hidden
12569
12570					_this.segPopover.removeElement();
12571
12572					_this.segPopover = null;
12573
12574					_this.popoverSegs = null;
12575
12576				}
12577
12578			};
12579
12580
12581
12582			// Determine horizontal coordinate.
12583
12584			// We use the moreWrap instead of the <td> to avoid border confusion.
12585
12586			if (this.isRTL) {
12587
12588				options.right = moreWrap.offset().left + moreWrap.outerWidth() + 1; // +1 to be over cell border
12589
12590			}
12591
12592			else {
12593
12594				options.left = moreWrap.offset().left - 1; // -1 to be over cell border
12595
12596			}
12597
12598
12599
12600			this.segPopover = new Popover(options);
12601
12602			this.segPopover.show();
12603
12604		},
12605
12606
12607
12608
12609
12610		// Builds the inner DOM contents of the segment popover
12611
12612		renderSegPopoverContent: function(row, col, segs) {
12613
12614			var view = this.view;
12615
12616			var isTheme = view.opt('theme');
12617
12618			var title = this.getCellDate(row, col).format(view.opt('dayPopoverFormat'));
12619
12620			var content = $(
12621
12622				'<div class="fc-header ' + view.widgetHeaderClass + '">' +
12623
12624				'<span class="fc-close ' +
12625
12626				(isTheme ? 'ui-icon ui-icon-closethick' : 'fc-icon fc-icon-x') +
12627
12628				'"></span>' +
12629
12630				'<span class="fc-title">' +
12631
12632				htmlEscape(title) +
12633
12634				'</span>' +
12635
12636				'<div class="fc-clear"/>' +
12637
12638				'</div>' +
12639
12640				'<div class="fc-body ' + view.widgetContentClass + '">' +
12641
12642				'<div class="fc-event-container"></div>' +
12643
12644				'</div>'
12645
12646			);
12647
12648			var segContainer = content.find('.fc-event-container');
12649
12650			var i;
12651
12652
12653
12654			// render each seg's `el` and only return the visible segs
12655
12656			segs = this.renderFgSegEls(segs, true); // disableResizing=true
12657
12658			this.popoverSegs = segs;
12659
12660
12661
12662			for (i = 0; i < segs.length; i++) {
12663
12664
12665
12666				// because segments in the popover are not part of a grid coordinate system, provide a hint to any
12667
12668				// grids that want to do drag-n-drop about which cell it came from
12669
12670				this.prepareHits();
12671
12672				segs[i].hit = this.getCellHit(row, col);
12673
12674				this.releaseHits();
12675
12676
12677
12678				segContainer.append(segs[i].el);
12679
12680			}
12681
12682
12683
12684			return content;
12685
12686		},
12687
12688
12689
12690
12691
12692		// Given the events within an array of segment objects, reslice them to be in a single day
12693
12694		resliceDaySegs: function(segs, dayDate) {
12695
12696
12697
12698			// build an array of the original events
12699
12700			var events = $.map(segs, function(seg) {
12701
12702				return seg.event;
12703
12704			});
12705
12706
12707
12708			var dayStart = dayDate.clone();
12709
12710			var dayEnd = dayStart.clone().add(1, 'days');
12711
12712			var dayRange = { start: dayStart, end: dayEnd };
12713
12714
12715
12716			// slice the events with a custom slicing function
12717
12718			segs = this.eventsToSegs(
12719
12720				events,
12721
12722				function(range) {
12723
12724					var seg = intersectRanges(range, dayRange); // undefind if no intersection
12725
12726					return seg ? [ seg ] : []; // must return an array of segments
12727
12728				}
12729
12730			);
12731
12732
12733
12734			// force an order because eventsToSegs doesn't guarantee one
12735
12736			this.sortEventSegs(segs);
12737
12738
12739
12740			return segs;
12741
12742		},
12743
12744
12745
12746
12747
12748		// Generates the text that should be inside a "more" link, given the number of events it represents
12749
12750		getMoreLinkText: function(num) {
12751
12752			var opt = this.view.opt('eventLimitText');
12753
12754
12755
12756			if (typeof opt === 'function') {
12757
12758				return opt(num);
12759
12760			}
12761
12762			else {
12763
12764				return '+' + num + ' ' + opt;
12765
12766			}
12767
12768		},
12769
12770
12771
12772
12773
12774		// Returns segments within a given cell.
12775
12776		// If `startLevel` is specified, returns only events including and below that level. Otherwise returns all segs.
12777
12778		getCellSegs: function(row, col, startLevel) {
12779
12780			var segMatrix = this.rowStructs[row].segMatrix;
12781
12782			var level = startLevel || 0;
12783
12784			var segs = [];
12785
12786			var seg;
12787
12788
12789
12790			while (level < segMatrix.length) {
12791
12792				seg = segMatrix[level][col];
12793
12794				if (seg) {
12795
12796					segs.push(seg);
12797
12798				}
12799
12800				level++;
12801
12802			}
12803
12804
12805
12806			return segs;
12807
12808		}
12809
12810
12811
12812	});
12813
12814
12815
12816	;;
12817
12818
12819
12820	/* A component that renders one or more columns of vertical time slots
12821
12822	 ----------------------------------------------------------------------------------------------------------------------*/
12823
12824// We mixin DayTable, even though there is only a single row of days
12825
12826
12827
12828	var TimeGrid = FC.TimeGrid = Grid.extend(DayTableMixin, {
12829
12830
12831
12832		slotDuration: null, // duration of a "slot", a distinct time segment on given day, visualized by lines
12833
12834		snapDuration: null, // granularity of time for dragging and selecting
12835
12836		snapsPerSlot: null,
12837
12838		minTime: null, // Duration object that denotes the first visible time of any given day
12839
12840		maxTime: null, // Duration object that denotes the exclusive visible end time of any given day
12841
12842		labelFormat: null, // formatting string for times running along vertical axis
12843
12844		labelInterval: null, // duration of how often a label should be displayed for a slot
12845
12846
12847
12848		colEls: null, // cells elements in the day-row background
12849
12850		slatEls: null, // elements running horizontally across all columns
12851
12852		helperEl: null, // cell skeleton element for rendering the mock event "helper"
12853
12854
12855
12856		colCoordCache: null,
12857
12858		slatCoordCache: null,
12859
12860
12861
12862		businessHourSegs: null,
12863
12864
12865
12866
12867
12868		constructor: function() {
12869
12870			Grid.apply(this, arguments); // call the super-constructor
12871
12872
12873
12874			this.processOptions();
12875
12876		},
12877
12878
12879
12880
12881
12882		// Renders the time grid into `this.el`, which should already be assigned.
12883
12884		// Relies on the view's colCnt. In the future, this component should probably be self-sufficient.
12885
12886		renderDates: function() {
12887
12888			this.el.html(this.renderHtml());
12889
12890			this.colEls = this.el.find('.fc-day');
12891
12892			this.slatEls = this.el.find('.fc-slats tr');
12893
12894
12895
12896			this.colCoordCache = new CoordCache({
12897
12898				els: this.colEls,
12899
12900				isHorizontal: true
12901
12902			});
12903
12904			this.slatCoordCache = new CoordCache({
12905
12906				els: this.slatEls,
12907
12908				isVertical: true
12909
12910			});
12911
12912		},
12913
12914
12915
12916
12917
12918		renderBusinessHours: function() {
12919
12920			var events = this.view.calendar.getBusinessHoursEvents();
12921
12922			this.businessHourSegs = this.renderFill('businessHours', this.eventsToSegs(events), 'bgevent');
12923
12924		},
12925
12926
12927
12928
12929
12930		// Renders the basic HTML skeleton for the grid
12931
12932		renderHtml: function() {
12933
12934			return '' +
12935
12936				'<div class="fc-bg">' +
12937
12938				'<table>' +
12939
12940				this.renderBgTrHtml(0) + // row=0
12941
12942				'</table>' +
12943
12944				'</div>' +
12945
12946				'<div class="fc-slats">' +
12947
12948				'<table>' +
12949
12950				this.renderSlatRowHtml() +
12951
12952				'</table>' +
12953
12954				'</div>';
12955
12956		},
12957
12958
12959
12960
12961
12962		// Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
12963
12964		renderSlatRowHtml: function() {
12965
12966			var view = this.view;
12967
12968			var isRTL = this.isRTL;
12969
12970			var html = '';
12971
12972			var slotTime = moment.duration(+this.minTime); // wish there was .clone() for durations
12973
12974			var slotDate; // will be on the view's first day, but we only care about its time
12975
12976			var isLabeled;
12977
12978			var axisHtml;
12979
12980
12981
12982			// Calculate the time for each slot
12983
12984			while (slotTime < this.maxTime) {
12985
12986				slotDate = this.start.clone().time(slotTime);
12987
12988				isLabeled = isInt(divideDurationByDuration(slotTime, this.labelInterval));
12989
12990
12991
12992				axisHtml =
12993
12994					'<td class="fc-axis fc-time ' + view.widgetContentClass + '" ' + view.axisStyleAttr() + '>' +
12995
12996					(isLabeled ?
12997
12998						'<span>' + // for matchCellWidths
12999
13000						htmlEscape(slotDate.format(this.labelFormat)) +
13001
13002						'</span>' :
13003
13004							''
13005
13006					) +
13007
13008					'</td>';
13009
13010
13011
13012				html +=
13013
13014					'<tr ' + (isLabeled ? '' : 'class="fc-minor"') + '>' +
13015
13016					(!isRTL ? axisHtml : '') +
13017
13018					'<td class="' + view.widgetContentClass + '"/>' +
13019
13020					(isRTL ? axisHtml : '') +
13021
13022					"</tr>";
13023
13024
13025
13026				slotTime.add(this.slotDuration);
13027
13028			}
13029
13030
13031
13032			return html;
13033
13034		},
13035
13036
13037
13038
13039
13040		/* Options
13041
13042		 ------------------------------------------------------------------------------------------------------------------*/
13043
13044
13045
13046
13047
13048		// Parses various options into properties of this object
13049
13050		processOptions: function() {
13051
13052			var view = this.view;
13053
13054			var slotDuration = view.opt('slotDuration');
13055
13056			var snapDuration = view.opt('snapDuration');
13057
13058			var input;
13059
13060
13061
13062			slotDuration = moment.duration(slotDuration);
13063
13064			snapDuration = snapDuration ? moment.duration(snapDuration) : slotDuration;
13065
13066
13067
13068			this.slotDuration = slotDuration;
13069
13070			this.snapDuration = snapDuration;
13071
13072			this.snapsPerSlot = slotDuration / snapDuration; // TODO: ensure an integer multiple?
13073
13074
13075
13076			this.minResizeDuration = snapDuration; // hack
13077
13078
13079
13080			this.minTime = moment.duration(view.opt('minTime'));
13081
13082			this.maxTime = moment.duration(view.opt('maxTime'));
13083
13084
13085
13086			// might be an array value (for TimelineView).
13087
13088			// if so, getting the most granular entry (the last one probably).
13089
13090			input = view.opt('slotLabelFormat');
13091
13092			if ($.isArray(input)) {
13093
13094				input = input[input.length - 1];
13095
13096			}
13097
13098
13099
13100			this.labelFormat =
13101
13102				input ||
13103
13104				view.opt('axisFormat') || // deprecated
13105
13106				view.opt('smallTimeFormat'); // the computed default
13107
13108
13109
13110			input = view.opt('slotLabelInterval');
13111
13112			this.labelInterval = input ?
13113
13114				moment.duration(input) :
13115
13116				this.computeLabelInterval(slotDuration);
13117
13118		},
13119
13120
13121
13122
13123
13124		// Computes an automatic value for slotLabelInterval
13125
13126		computeLabelInterval: function(slotDuration) {
13127
13128			var i;
13129
13130			var labelInterval;
13131
13132			var slotsPerLabel;
13133
13134
13135
13136			// find the smallest stock label interval that results in more than one slots-per-label
13137
13138			for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
13139
13140				labelInterval = moment.duration(AGENDA_STOCK_SUB_DURATIONS[i]);
13141
13142				slotsPerLabel = divideDurationByDuration(labelInterval, slotDuration);
13143
13144				if (isInt(slotsPerLabel) && slotsPerLabel > 1) {
13145
13146					return labelInterval;
13147
13148				}
13149
13150			}
13151
13152
13153
13154			return moment.duration(slotDuration); // fall back. clone
13155
13156		},
13157
13158
13159
13160
13161
13162		// Computes a default event time formatting string if `timeFormat` is not explicitly defined
13163
13164		computeEventTimeFormat: function() {
13165
13166			return this.view.opt('noMeridiemTimeFormat'); // like "6:30" (no AM/PM)
13167
13168		},
13169
13170
13171
13172
13173
13174		// Computes a default `displayEventEnd` value if one is not expliclty defined
13175
13176		computeDisplayEventEnd: function() {
13177
13178			return true;
13179
13180		},
13181
13182
13183
13184
13185
13186		/* Hit System
13187
13188		 ------------------------------------------------------------------------------------------------------------------*/
13189
13190
13191
13192
13193
13194		prepareHits: function() {
13195
13196			this.colCoordCache.build();
13197
13198			this.slatCoordCache.build();
13199
13200		},
13201
13202
13203
13204
13205
13206		releaseHits: function() {
13207
13208			this.colCoordCache.clear();
13209
13210			// NOTE: don't clear slatCoordCache because we rely on it for computeTimeTop
13211
13212		},
13213
13214
13215
13216
13217
13218		queryHit: function(leftOffset, topOffset) {
13219
13220			var snapsPerSlot = this.snapsPerSlot;
13221
13222			var colCoordCache = this.colCoordCache;
13223
13224			var slatCoordCache = this.slatCoordCache;
13225
13226			var colIndex = colCoordCache.getHorizontalIndex(leftOffset);
13227
13228			var slatIndex = slatCoordCache.getVerticalIndex(topOffset);
13229
13230
13231
13232			if (colIndex != null && slatIndex != null) {
13233
13234				var slatTop = slatCoordCache.getTopOffset(slatIndex);
13235
13236				var slatHeight = slatCoordCache.getHeight(slatIndex);
13237
13238				var partial = (topOffset - slatTop) / slatHeight; // floating point number between 0 and 1
13239
13240				var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat
13241
13242				var snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
13243
13244				var snapTop = slatTop + (localSnapIndex / snapsPerSlot) * slatHeight;
13245
13246				var snapBottom = slatTop + ((localSnapIndex + 1) / snapsPerSlot) * slatHeight;
13247
13248
13249
13250				return {
13251
13252					col: colIndex,
13253
13254					snap: snapIndex,
13255
13256					component: this, // needed unfortunately :(
13257
13258					left: colCoordCache.getLeftOffset(colIndex),
13259
13260					right: colCoordCache.getRightOffset(colIndex),
13261
13262					top: snapTop,
13263
13264					bottom: snapBottom
13265
13266				};
13267
13268			}
13269
13270		},
13271
13272
13273
13274
13275
13276		getHitSpan: function(hit) {
13277
13278			var start = this.getCellDate(0, hit.col); // row=0
13279
13280			var time = this.computeSnapTime(hit.snap); // pass in the snap-index
13281
13282			var end;
13283
13284
13285
13286			start.time(time);
13287
13288			end = start.clone().add(this.snapDuration);
13289
13290
13291
13292			return { start: start, end: end };
13293
13294		},
13295
13296
13297
13298
13299
13300		getHitEl: function(hit) {
13301
13302			return this.colEls.eq(hit.col);
13303
13304		},
13305
13306
13307
13308
13309
13310		/* Dates
13311
13312		 ------------------------------------------------------------------------------------------------------------------*/
13313
13314
13315
13316
13317
13318		rangeUpdated: function() {
13319
13320			this.updateDayTable();
13321
13322		},
13323
13324
13325
13326
13327
13328		// Given a row number of the grid, representing a "snap", returns a time (Duration) from its start-of-day
13329
13330		computeSnapTime: function(snapIndex) {
13331
13332			return moment.duration(this.minTime + this.snapDuration * snapIndex);
13333
13334		},
13335
13336
13337
13338
13339
13340		// Slices up the given span (unzoned start/end with other misc data) into an array of segments
13341
13342		spanToSegs: function(span) {
13343
13344			var segs = this.sliceRangeByTimes(span);
13345
13346			var i;
13347
13348
13349
13350			for (i = 0; i < segs.length; i++) {
13351
13352				if (this.isRTL) {
13353
13354					segs[i].col = this.daysPerRow - 1 - segs[i].dayIndex;
13355
13356				}
13357
13358				else {
13359
13360					segs[i].col = segs[i].dayIndex;
13361
13362				}
13363
13364			}
13365
13366
13367
13368			return segs;
13369
13370		},
13371
13372
13373
13374
13375
13376		sliceRangeByTimes: function(range) {
13377
13378			var segs = [];
13379
13380			var seg;
13381
13382			var dayIndex;
13383
13384			var dayDate;
13385
13386			var dayRange;
13387
13388
13389
13390			for (dayIndex = 0; dayIndex < this.daysPerRow; dayIndex++) {
13391
13392				dayDate = this.dayDates[dayIndex].clone(); // TODO: better API for this?
13393
13394				dayRange = {
13395
13396					start: dayDate.clone().time(this.minTime),
13397
13398					end: dayDate.clone().time(this.maxTime)
13399
13400				};
13401
13402				seg = intersectRanges(range, dayRange); // both will be ambig timezone
13403
13404				if (seg) {
13405
13406					seg.dayIndex = dayIndex;
13407
13408					segs.push(seg);
13409
13410				}
13411
13412			}
13413
13414
13415
13416			return segs;
13417
13418		},
13419
13420
13421
13422
13423
13424		/* Coordinates
13425
13426		 ------------------------------------------------------------------------------------------------------------------*/
13427
13428
13429
13430
13431
13432		updateSize: function(isResize) { // NOT a standard Grid method
13433
13434			this.slatCoordCache.build();
13435
13436
13437
13438			if (isResize) {
13439
13440				this.updateSegVerticals();
13441
13442			}
13443
13444		},
13445
13446
13447
13448
13449
13450		// Computes the top coordinate, relative to the bounds of the grid, of the given date.
13451
13452		// A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
13453
13454		computeDateTop: function(date, startOfDayDate) {
13455
13456			return this.computeTimeTop(
13457
13458				moment.duration(
13459
13460					date - startOfDayDate.clone().stripTime()
13461
13462				)
13463
13464			);
13465
13466		},
13467
13468
13469
13470
13471
13472		// Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
13473
13474		computeTimeTop: function(time) {
13475
13476			var len = this.slatEls.length;
13477
13478			var slatCoverage = (time - this.minTime) / this.slotDuration; // floating-point value of # of slots covered
13479
13480			var slatIndex;
13481
13482			var slatRemainder;
13483
13484
13485
13486			// compute a floating-point number for how many slats should be progressed through.
13487
13488			// from 0 to number of slats (inclusive)
13489
13490			// constrained because minTime/maxTime might be customized.
13491
13492			slatCoverage = Math.max(0, slatCoverage);
13493
13494			slatCoverage = Math.min(len, slatCoverage);
13495
13496
13497
13498			// an integer index of the furthest whole slat
13499
13500			// from 0 to number slats (*exclusive*, so len-1)
13501
13502			slatIndex = Math.floor(slatCoverage);
13503
13504			slatIndex = Math.min(slatIndex, len - 1);
13505
13506
13507
13508			// how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
13509
13510			// could be 1.0 if slatCoverage is covering *all* the slots
13511
13512			slatRemainder = slatCoverage - slatIndex;
13513
13514
13515
13516			return this.slatCoordCache.getTopPosition(slatIndex) +
13517
13518				this.slatCoordCache.getHeight(slatIndex) * slatRemainder;
13519
13520		},
13521
13522
13523
13524
13525
13526
13527
13528		/* Event Drag Visualization
13529
13530		 ------------------------------------------------------------------------------------------------------------------*/
13531
13532
13533
13534
13535
13536		// Renders a visual indication of an event being dragged over the specified date(s).
13537
13538		// A returned value of `true` signals that a mock "helper" event has been rendered.
13539
13540		renderDrag: function(eventLocation, seg) {
13541
13542
13543
13544			if (seg) { // if there is event information for this drag, render a helper event
13545
13546				this.renderEventLocationHelper(eventLocation, seg);
13547
13548				this.applyDragOpacity(this.helperEl);
13549
13550
13551
13552				return true; // signal that a helper has been rendered
13553
13554			}
13555
13556			else {
13557
13558				// otherwise, just render a highlight
13559
13560				this.renderHighlight(this.eventToSpan(eventLocation));
13561
13562			}
13563
13564		},
13565
13566
13567
13568
13569
13570		// Unrenders any visual indication of an event being dragged
13571
13572		unrenderDrag: function() {
13573
13574			this.unrenderHelper();
13575
13576			this.unrenderHighlight();
13577
13578		},
13579
13580
13581
13582
13583
13584		/* Event Resize Visualization
13585
13586		 ------------------------------------------------------------------------------------------------------------------*/
13587
13588
13589
13590
13591
13592		// Renders a visual indication of an event being resized
13593
13594		renderEventResize: function(eventLocation, seg) {
13595
13596			this.renderEventLocationHelper(eventLocation, seg);
13597
13598		},
13599
13600
13601
13602
13603
13604		// Unrenders any visual indication of an event being resized
13605
13606		unrenderEventResize: function() {
13607
13608			this.unrenderHelper();
13609
13610		},
13611
13612
13613
13614
13615
13616		/* Event Helper
13617
13618		 ------------------------------------------------------------------------------------------------------------------*/
13619
13620
13621
13622
13623
13624		// Renders a mock "helper" event. `sourceSeg` is the original segment object and might be null (an external drag)
13625
13626		renderHelper: function(event, sourceSeg) {
13627
13628			var segs = this.eventToSegs(event);
13629
13630			var tableEl;
13631
13632			var i, seg;
13633
13634			var sourceEl;
13635
13636
13637
13638			segs = this.renderFgSegEls(segs); // assigns each seg's el and returns a subset of segs that were rendered
13639
13640			tableEl = this.renderSegTable(segs);
13641
13642
13643
13644			// Try to make the segment that is in the same row as sourceSeg look the same
13645
13646			for (i = 0; i < segs.length; i++) {
13647
13648				seg = segs[i];
13649
13650				if (sourceSeg && sourceSeg.col === seg.col) {
13651
13652					sourceEl = sourceSeg.el;
13653
13654					seg.el.css({
13655
13656						left: sourceEl.css('left'),
13657
13658						right: sourceEl.css('right'),
13659
13660						'margin-left': sourceEl.css('margin-left'),
13661
13662						'margin-right': sourceEl.css('margin-right')
13663
13664					});
13665
13666				}
13667
13668			}
13669
13670
13671
13672			this.helperEl = $('<div class="fc-helper-skeleton"/>')
13673
13674				.append(tableEl)
13675
13676				.appendTo(this.el);
13677
13678		},
13679
13680
13681
13682
13683
13684		// Unrenders any mock helper event
13685
13686		unrenderHelper: function() {
13687
13688			if (this.helperEl) {
13689
13690				this.helperEl.remove();
13691
13692				this.helperEl = null;
13693
13694			}
13695
13696		},
13697
13698
13699
13700
13701
13702		/* Selection
13703
13704		 ------------------------------------------------------------------------------------------------------------------*/
13705
13706
13707
13708
13709
13710		// Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight.
13711
13712		renderSelection: function(span) {
13713
13714			if (this.view.opt('selectHelper')) { // this setting signals that a mock helper event should be rendered
13715
13716
13717
13718				// normally acceps an eventLocation, span has a start/end, which is good enough
13719
13720				this.renderEventLocationHelper(span);
13721
13722			}
13723
13724			else {
13725
13726				this.renderHighlight(span);
13727
13728			}
13729
13730		},
13731
13732
13733
13734
13735
13736		// Unrenders any visual indication of a selection
13737
13738		unrenderSelection: function() {
13739
13740			this.unrenderHelper();
13741
13742			this.unrenderHighlight();
13743
13744		},
13745
13746
13747
13748
13749
13750		/* Fill System (highlight, background events, business hours)
13751
13752		 ------------------------------------------------------------------------------------------------------------------*/
13753
13754
13755
13756
13757
13758		// Renders a set of rectangles over the given time segments.
13759
13760		// Only returns segments that successfully rendered.
13761
13762		renderFill: function(type, segs, className) {
13763
13764			var segCols;
13765
13766			var skeletonEl;
13767
13768			var trEl;
13769
13770			var col, colSegs;
13771
13772			var tdEl;
13773
13774			var containerEl;
13775
13776			var dayDate;
13777
13778			var i, seg;
13779
13780
13781
13782			if (segs.length) {
13783
13784
13785
13786				segs = this.renderFillSegEls(type, segs); // assignes `.el` to each seg. returns successfully rendered segs
13787
13788				segCols = this.groupSegCols(segs); // group into sub-arrays, and assigns 'col' to each seg
13789
13790
13791
13792				className = className || type.toLowerCase();
13793
13794				skeletonEl = $(
13795
13796					'<div class="fc-' + className + '-skeleton">' +
13797
13798					'<table><tr/></table>' +
13799
13800					'</div>'
13801
13802				);
13803
13804				trEl = skeletonEl.find('tr');
13805
13806
13807
13808				for (col = 0; col < segCols.length; col++) {
13809
13810					colSegs = segCols[col];
13811
13812					tdEl = $('<td/>').appendTo(trEl);
13813
13814
13815
13816					if (colSegs.length) {
13817
13818						containerEl = $('<div class="fc-' + className + '-container"/>').appendTo(tdEl);
13819
13820						dayDate = this.getCellDate(0, col); // row=0
13821
13822
13823
13824						for (i = 0; i < colSegs.length; i++) {
13825
13826							seg = colSegs[i];
13827
13828							containerEl.append(
13829
13830								seg.el.css({
13831
13832									top: this.computeDateTop(seg.start, dayDate),
13833
13834									bottom: -this.computeDateTop(seg.end, dayDate) // the y position of the bottom edge
13835
13836								})
13837
13838							);
13839
13840						}
13841
13842					}
13843
13844				}
13845
13846
13847
13848				this.bookendCells(trEl);
13849
13850
13851
13852				this.el.append(skeletonEl);
13853
13854				this.elsByFill[type] = skeletonEl;
13855
13856			}
13857
13858
13859
13860			return segs;
13861
13862		}
13863
13864
13865
13866	});
13867
13868
13869
13870	;;
13871
13872
13873
13874	/* Event-rendering methods for the TimeGrid class
13875
13876	 ----------------------------------------------------------------------------------------------------------------------*/
13877
13878
13879
13880	TimeGrid.mixin({
13881
13882
13883
13884		eventSkeletonEl: null, // has cells with event-containers, which contain absolutely positioned event elements
13885
13886
13887
13888
13889
13890		// Renders the given foreground event segments onto the grid
13891
13892		renderFgSegs: function(segs) {
13893
13894			segs = this.renderFgSegEls(segs); // returns a subset of the segs. segs that were actually rendered
13895
13896
13897
13898			this.el.append(
13899
13900				this.eventSkeletonEl = $('<div class="fc-content-skeleton"/>')
13901
13902					.append(this.renderSegTable(segs))
13903
13904			);
13905
13906
13907
13908			return segs; // return only the segs that were actually rendered
13909
13910		},
13911
13912
13913
13914
13915
13916		// Unrenders all currently rendered foreground event segments
13917
13918		unrenderFgSegs: function(segs) {
13919
13920			if (this.eventSkeletonEl) {
13921
13922				this.eventSkeletonEl.remove();
13923
13924				this.eventSkeletonEl = null;
13925
13926			}
13927
13928		},
13929
13930
13931
13932
13933
13934		// Renders and returns the <table> portion of the event-skeleton.
13935
13936		// Returns an object with properties 'tbodyEl' and 'segs'.
13937
13938		renderSegTable: function(segs) {
13939
13940			var tableEl = $('<table><tr/></table>');
13941
13942			var trEl = tableEl.find('tr');
13943
13944			var segCols;
13945
13946			var i, seg;
13947
13948			var col, colSegs;
13949
13950			var containerEl;
13951
13952
13953
13954			segCols = this.groupSegCols(segs); // group into sub-arrays, and assigns 'col' to each seg
13955
13956
13957
13958			this.computeSegVerticals(segs); // compute and assign top/bottom
13959
13960
13961
13962			for (col = 0; col < segCols.length; col++) { // iterate each column grouping
13963
13964				colSegs = segCols[col];
13965
13966				this.placeSlotSegs(colSegs); // compute horizontal coordinates, z-index's, and reorder the array
13967
13968
13969
13970				containerEl = $('<div class="fc-event-container"/>');
13971
13972
13973
13974				// assign positioning CSS and insert into container
13975
13976				for (i = 0; i < colSegs.length; i++) {
13977
13978					seg = colSegs[i];
13979
13980					seg.el.css(this.generateSegPositionCss(seg));
13981
13982
13983
13984					// if the height is short, add a className for alternate styling
13985
13986					if (seg.bottom - seg.top < 30) {
13987
13988						seg.el.addClass('fc-short');
13989
13990					}
13991
13992
13993
13994					containerEl.append(seg.el);
13995
13996				}
13997
13998
13999
14000				trEl.append($('<td/>').append(containerEl));
14001
14002			}
14003
14004
14005
14006			this.bookendCells(trEl);
14007
14008
14009
14010			return tableEl;
14011
14012		},
14013
14014
14015
14016
14017
14018		// Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
14019
14020		// NOTE: Also reorders the given array by date!
14021
14022		placeSlotSegs: function(segs) {
14023
14024			var levels;
14025
14026			var level0;
14027
14028			var i;
14029
14030
14031
14032			this.sortEventSegs(segs); // order by certain criteria
14033
14034			levels = buildSlotSegLevels(segs);
14035
14036			computeForwardSlotSegs(levels);
14037
14038
14039
14040			if ((level0 = levels[0])) {
14041
14042
14043
14044				for (i = 0; i < level0.length; i++) {
14045
14046					computeSlotSegPressures(level0[i]);
14047
14048				}
14049
14050
14051
14052				for (i = 0; i < level0.length; i++) {
14053
14054					this.computeSlotSegCoords(level0[i], 0, 0);
14055
14056				}
14057
14058			}
14059
14060		},
14061
14062
14063
14064
14065
14066		// Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
14067
14068		// from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
14069
14070		// seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
14071
14072		//
14073
14074		// The segment might be part of a "series", which means consecutive segments with the same pressure
14075
14076		// who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
14077
14078		// segments behind this one in the current series, and `seriesBackwardCoord` is the starting
14079
14080		// coordinate of the first segment in the series.
14081
14082		computeSlotSegCoords: function(seg, seriesBackwardPressure, seriesBackwardCoord) {
14083
14084			var forwardSegs = seg.forwardSegs;
14085
14086			var i;
14087
14088
14089
14090			if (seg.forwardCoord === undefined) { // not already computed
14091
14092
14093
14094				if (!forwardSegs.length) {
14095
14096
14097
14098					// if there are no forward segments, this segment should butt up against the edge
14099
14100					seg.forwardCoord = 1;
14101
14102				}
14103
14104				else {
14105
14106
14107
14108					// sort highest pressure first
14109
14110					this.sortForwardSlotSegs(forwardSegs);
14111
14112
14113
14114					// this segment's forwardCoord will be calculated from the backwardCoord of the
14115
14116					// highest-pressure forward segment.
14117
14118					this.computeSlotSegCoords(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);
14119
14120					seg.forwardCoord = forwardSegs[0].backwardCoord;
14121
14122				}
14123
14124
14125
14126				// calculate the backwardCoord from the forwardCoord. consider the series
14127
14128				seg.backwardCoord = seg.forwardCoord -
14129
14130					(seg.forwardCoord - seriesBackwardCoord) / // available width for series
14131
14132					(seriesBackwardPressure + 1); // # of segments in the series
14133
14134
14135
14136				// use this segment's coordinates to computed the coordinates of the less-pressurized
14137
14138				// forward segments
14139
14140				for (i=0; i<forwardSegs.length; i++) {
14141
14142					this.computeSlotSegCoords(forwardSegs[i], 0, seg.forwardCoord);
14143
14144				}
14145
14146			}
14147
14148		},
14149
14150
14151
14152
14153
14154		// Refreshes the CSS top/bottom coordinates for each segment element. Probably after a window resize/zoom.
14155
14156		// Repositions business hours segs too, so not just for events. Maybe shouldn't be here.
14157
14158		updateSegVerticals: function() {
14159
14160			var allSegs = (this.segs || []).concat(this.businessHourSegs || []);
14161
14162			var i;
14163
14164
14165
14166			this.computeSegVerticals(allSegs);
14167
14168
14169
14170			for (i = 0; i < allSegs.length; i++) {
14171
14172				allSegs[i].el.css(
14173
14174					this.generateSegVerticalCss(allSegs[i])
14175
14176				);
14177
14178			}
14179
14180		},
14181
14182
14183
14184
14185
14186		// For each segment in an array, computes and assigns its top and bottom properties
14187
14188		computeSegVerticals: function(segs) {
14189
14190			var i, seg;
14191
14192
14193
14194			for (i = 0; i < segs.length; i++) {
14195
14196				seg = segs[i];
14197
14198				seg.top = this.computeDateTop(seg.start, seg.start);
14199
14200				seg.bottom = this.computeDateTop(seg.end, seg.start);
14201
14202			}
14203
14204		},
14205
14206
14207
14208
14209
14210		// Renders the HTML for a single event segment's default rendering
14211
14212		fgSegHtml: function(seg, disableResizing) {
14213
14214			var view = this.view;
14215
14216			var event = seg.event;
14217
14218			var isDraggable = view.isEventDraggable(event);
14219
14220			var isResizableFromStart = !disableResizing && seg.isStart && view.isEventResizableFromStart(event);
14221
14222			var isResizableFromEnd = !disableResizing && seg.isEnd && view.isEventResizableFromEnd(event);
14223
14224			var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd);
14225
14226			var skinCss = cssToStr(this.getEventSkinCss(event));
14227
14228			var timeText;
14229
14230			var fullTimeText; // more verbose time text. for the print stylesheet
14231
14232			var startTimeText; // just the start time text
14233
14234
14235
14236			classes.unshift('fc-time-grid-event', 'fc-v-event');
14237
14238
14239
14240			if (view.isMultiDayEvent(event)) { // if the event appears to span more than one day...
14241
14242				// Don't display time text on segments that run entirely through a day.
14243
14244				// That would appear as midnight-midnight and would look dumb.
14245
14246				// Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am)
14247
14248				if (seg.isStart || seg.isEnd) {
14249
14250					timeText = this.getEventTimeText(seg);
14251
14252					fullTimeText = this.getEventTimeText(seg, 'LT');
14253
14254					startTimeText = this.getEventTimeText(seg, null, false); // displayEnd=false
14255
14256				}
14257
14258			} else {
14259
14260				// Display the normal time text for the *event's* times
14261
14262				timeText = this.getEventTimeText(event);
14263
14264				fullTimeText = this.getEventTimeText(event, 'LT');
14265
14266				startTimeText = this.getEventTimeText(event, null, false); // displayEnd=false
14267
14268			}
14269
14270
14271
14272			return '<a class="' + classes.join(' ') + '"' +
14273
14274				(event.url ?
14275
14276					' href="' + htmlEscape(event.url) + '"' :
14277
14278						''
14279
14280				) +
14281
14282				(skinCss ?
14283
14284					' style="' + skinCss + '"' :
14285
14286						''
14287
14288				) +
14289
14290				'>' +
14291
14292				'<div class="fc-content">' +
14293
14294				(timeText ?
14295
14296					'<div class="fc-time"' +
14297
14298					' data-start="' + htmlEscape(startTimeText) + '"' +
14299
14300					' data-full="' + htmlEscape(fullTimeText) + '"' +
14301
14302					'>' +
14303
14304					'<span>' + htmlEscape(timeText) + '</span>' +
14305
14306					'</div>' :
14307
14308						''
14309
14310				) +
14311
14312				(event.title ?
14313
14314					'<div class="fc-title">' +
14315
14316					htmlEscape(event.title) +
14317
14318					'</div>' :
14319
14320						''
14321
14322				) +
14323
14324				'</div>' +
14325
14326				'<div class="fc-bg"/>' +
14327
14328					/* TODO: write CSS for this
14329
14330					 (isResizableFromStart ?
14331
14332					 '<div class="fc-resizer fc-start-resizer" />' :
14333
14334					 ''
14335
14336					 ) +
14337
14338					 */
14339
14340				(isResizableFromEnd ?
14341
14342						'<div class="fc-resizer fc-end-resizer" />' :
14343
14344						''
14345
14346				) +
14347
14348				'</a>';
14349
14350		},
14351
14352
14353
14354
14355
14356		// Generates an object with CSS properties/values that should be applied to an event segment element.
14357
14358		// Contains important positioning-related properties that should be applied to any event element, customized or not.
14359
14360		generateSegPositionCss: function(seg) {
14361
14362			var shouldOverlap = this.view.opt('slotEventOverlap');
14363
14364			var backwardCoord = seg.backwardCoord; // the left side if LTR. the right side if RTL. floating-point
14365
14366			var forwardCoord = seg.forwardCoord; // the right side if LTR. the left side if RTL. floating-point
14367
14368			var props = this.generateSegVerticalCss(seg); // get top/bottom first
14369
14370			var left; // amount of space from left edge, a fraction of the total width
14371
14372			var right; // amount of space from right edge, a fraction of the total width
14373
14374
14375
14376			if (shouldOverlap) {
14377
14378				// double the width, but don't go beyond the maximum forward coordinate (1.0)
14379
14380				forwardCoord = Math.min(1, backwardCoord + (forwardCoord - backwardCoord) * 2);
14381
14382			}
14383
14384
14385
14386			if (this.isRTL) {
14387
14388				left = 1 - forwardCoord;
14389
14390				right = backwardCoord;
14391
14392			}
14393
14394			else {
14395
14396				left = backwardCoord;
14397
14398				right = 1 - forwardCoord;
14399
14400			}
14401
14402
14403
14404			props.zIndex = seg.level + 1; // convert from 0-base to 1-based
14405
14406			props.left = left * 100 + '%';
14407
14408			props.right = right * 100 + '%';
14409
14410
14411
14412			if (shouldOverlap && seg.forwardPressure) {
14413
14414				// add padding to the edge so that forward stacked events don't cover the resizer's icon
14415
14416				props[this.isRTL ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width
14417
14418			}
14419
14420
14421
14422			return props;
14423
14424		},
14425
14426
14427
14428
14429
14430		// Generates an object with CSS properties for the top/bottom coordinates of a segment element
14431
14432		generateSegVerticalCss: function(seg) {
14433
14434			return {
14435
14436				top: seg.top,
14437
14438				bottom: -seg.bottom // flipped because needs to be space beyond bottom edge of event container
14439
14440			};
14441
14442		},
14443
14444
14445
14446
14447
14448		// Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col
14449
14450		groupSegCols: function(segs) {
14451
14452			var segCols = [];
14453
14454			var i;
14455
14456
14457
14458			for (i = 0; i < this.colCnt; i++) {
14459
14460				segCols.push([]);
14461
14462			}
14463
14464
14465
14466			for (i = 0; i < segs.length; i++) {
14467
14468				segCols[segs[i].col].push(segs[i]);
14469
14470			}
14471
14472
14473
14474			return segCols;
14475
14476		},
14477
14478
14479
14480
14481
14482		sortForwardSlotSegs: function(forwardSegs) {
14483
14484			forwardSegs.sort(proxy(this, 'compareForwardSlotSegs'));
14485
14486		},
14487
14488
14489
14490
14491
14492		// A cmp function for determining which forward segment to rely on more when computing coordinates.
14493
14494		compareForwardSlotSegs: function(seg1, seg2) {
14495
14496			// put higher-pressure first
14497
14498			return seg2.forwardPressure - seg1.forwardPressure ||
14499
14500					// put segments that are closer to initial edge first (and favor ones with no coords yet)
14501
14502				(seg1.backwardCoord || 0) - (seg2.backwardCoord || 0) ||
14503
14504					// do normal sorting...
14505
14506				this.compareEventSegs(seg1, seg2);
14507
14508		}
14509
14510
14511
14512	});
14513
14514
14515
14516
14517
14518// Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is
14519
14520// left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date.
14521
14522	function buildSlotSegLevels(segs) {
14523
14524		var levels = [];
14525
14526		var i, seg;
14527
14528		var j;
14529
14530
14531
14532		for (i=0; i<segs.length; i++) {
14533
14534			seg = segs[i];
14535
14536
14537
14538			// go through all the levels and stop on the first level where there are no collisions
14539
14540			for (j=0; j<levels.length; j++) {
14541
14542				if (!computeSlotSegCollisions(seg, levels[j]).length) {
14543
14544					break;
14545
14546				}
14547
14548			}
14549
14550
14551
14552			seg.level = j;
14553
14554
14555
14556			(levels[j] || (levels[j] = [])).push(seg);
14557
14558		}
14559
14560
14561
14562		return levels;
14563
14564	}
14565
14566
14567
14568
14569
14570// For every segment, figure out the other segments that are in subsequent
14571
14572// levels that also occupy the same vertical space. Accumulate in seg.forwardSegs
14573
14574	function computeForwardSlotSegs(levels) {
14575
14576		var i, level;
14577
14578		var j, seg;
14579
14580		var k;
14581
14582
14583
14584		for (i=0; i<levels.length; i++) {
14585
14586			level = levels[i];
14587
14588
14589
14590			for (j=0; j<level.length; j++) {
14591
14592				seg = level[j];
14593
14594
14595
14596				seg.forwardSegs = [];
14597
14598				for (k=i+1; k<levels.length; k++) {
14599
14600					computeSlotSegCollisions(seg, levels[k], seg.forwardSegs);
14601
14602				}
14603
14604			}
14605
14606		}
14607
14608	}
14609
14610
14611
14612
14613
14614// Figure out which path forward (via seg.forwardSegs) results in the longest path until
14615
14616// the furthest edge is reached. The number of segments in this path will be seg.forwardPressure
14617
14618	function computeSlotSegPressures(seg) {
14619
14620		var forwardSegs = seg.forwardSegs;
14621
14622		var forwardPressure = 0;
14623
14624		var i, forwardSeg;
14625
14626
14627
14628		if (seg.forwardPressure === undefined) { // not already computed
14629
14630
14631
14632			for (i=0; i<forwardSegs.length; i++) {
14633
14634				forwardSeg = forwardSegs[i];
14635
14636
14637
14638				// figure out the child's maximum forward path
14639
14640				computeSlotSegPressures(forwardSeg);
14641
14642
14643
14644				// either use the existing maximum, or use the child's forward pressure
14645
14646				// plus one (for the forwardSeg itself)
14647
14648				forwardPressure = Math.max(
14649
14650					forwardPressure,
14651
14652					1 + forwardSeg.forwardPressure
14653
14654				);
14655
14656			}
14657
14658
14659
14660			seg.forwardPressure = forwardPressure;
14661
14662		}
14663
14664	}
14665
14666
14667
14668
14669
14670// Find all the segments in `otherSegs` that vertically collide with `seg`.
14671
14672// Append into an optionally-supplied `results` array and return.
14673
14674	function computeSlotSegCollisions(seg, otherSegs, results) {
14675
14676		results = results || [];
14677
14678
14679
14680		for (var i=0; i<otherSegs.length; i++) {
14681
14682			if (isSlotSegCollision(seg, otherSegs[i])) {
14683
14684				results.push(otherSegs[i]);
14685
14686			}
14687
14688		}
14689
14690
14691
14692		return results;
14693
14694	}
14695
14696
14697
14698
14699
14700// Do these segments occupy the same vertical space?
14701
14702	function isSlotSegCollision(seg1, seg2) {
14703
14704		return seg1.bottom > seg2.top && seg1.top < seg2.bottom;
14705
14706	}
14707
14708
14709
14710	;;
14711
14712
14713
14714	/* An abstract class from which other views inherit from
14715
14716	 ----------------------------------------------------------------------------------------------------------------------*/
14717
14718
14719
14720	var View = FC.View = Class.extend({
14721
14722
14723
14724		type: null, // subclass' view name (string)
14725
14726		name: null, // deprecated. use `type` instead
14727
14728		title: null, // the text that will be displayed in the header's title
14729
14730
14731
14732		calendar: null, // owner Calendar object
14733
14734		options: null, // hash containing all options. already merged with view-specific-options
14735
14736		el: null, // the view's containing element. set by Calendar
14737
14738
14739
14740		displaying: null, // a promise representing the state of rendering. null if no render requested
14741
14742		isSkeletonRendered: false,
14743
14744		isEventsRendered: false,
14745
14746
14747
14748		// range the view is actually displaying (moments)
14749
14750		start: null,
14751
14752		end: null, // exclusive
14753
14754
14755
14756		// range the view is formally responsible for (moments)
14757
14758		// may be different from start/end. for example, a month view might have 1st-31st, excluding padded dates
14759
14760		intervalStart: null,
14761
14762		intervalEnd: null, // exclusive
14763
14764		intervalDuration: null,
14765
14766		intervalUnit: null, // name of largest unit being displayed, like "month" or "week"
14767
14768
14769
14770		isRTL: false,
14771
14772		isSelected: false, // boolean whether a range of time is user-selected or not
14773
14774
14775
14776		eventOrderSpecs: null, // criteria for ordering events when they have same date/time
14777
14778
14779
14780		// subclasses can optionally use a scroll container
14781
14782		scrollerEl: null, // the element that will most likely scroll when content is too tall
14783
14784		scrollTop: null, // cached vertical scroll value
14785
14786
14787
14788		// classNames styled by jqui themes
14789
14790		widgetHeaderClass: null,
14791
14792		widgetContentClass: null,
14793
14794		highlightStateClass: null,
14795
14796
14797
14798		// for date utils, computed from options
14799
14800		nextDayThreshold: null,
14801
14802		isHiddenDayHash: null,
14803
14804
14805
14806		// document handlers, bound to `this` object
14807
14808		documentMousedownProxy: null, // TODO: doesn't work with touch
14809
14810
14811
14812
14813
14814		constructor: function(calendar, type, options, intervalDuration) {
14815
14816
14817
14818			this.calendar = calendar;
14819
14820			this.type = this.name = type; // .name is deprecated
14821
14822			this.options = options;
14823
14824			this.intervalDuration = intervalDuration || moment.duration(1, 'day');
14825
14826
14827
14828			this.nextDayThreshold = moment.duration(this.opt('nextDayThreshold'));
14829
14830			this.initThemingProps();
14831
14832			this.initHiddenDays();
14833
14834			this.isRTL = this.opt('isRTL');
14835
14836
14837
14838			this.eventOrderSpecs = parseFieldSpecs(this.opt('eventOrder'));
14839
14840
14841
14842			this.documentMousedownProxy = proxy(this, 'documentMousedown');
14843
14844
14845
14846			this.initialize();
14847
14848		},
14849
14850
14851
14852
14853
14854		// A good place for subclasses to initialize member variables
14855
14856		initialize: function() {
14857
14858			// subclasses can implement
14859
14860		},
14861
14862
14863
14864
14865
14866		// Retrieves an option with the given name
14867
14868		opt: function(name) {
14869
14870			return this.options[name];
14871
14872		},
14873
14874
14875
14876
14877
14878		// Triggers handlers that are view-related. Modifies args before passing to calendar.
14879
14880		trigger: function(name, thisObj) { // arguments beyond thisObj are passed along
14881
14882			var calendar = this.calendar;
14883
14884
14885
14886			return calendar.trigger.apply(
14887
14888				calendar,
14889
14890				[name, thisObj || this].concat(
14891
14892					Array.prototype.slice.call(arguments, 2), // arguments beyond thisObj
14893
14894					[ this ] // always make the last argument a reference to the view. TODO: deprecate
14895
14896				)
14897
14898			);
14899
14900		},
14901
14902
14903
14904
14905
14906		/* Dates
14907
14908		 ------------------------------------------------------------------------------------------------------------------*/
14909
14910
14911
14912
14913
14914		// Updates all internal dates to center around the given current unzoned date.
14915
14916		setDate: function(date) {
14917
14918			this.setRange(this.computeRange(date));
14919
14920		},
14921
14922
14923
14924
14925
14926		// Updates all internal dates for displaying the given unzoned range.
14927
14928		setRange: function(range) {
14929
14930			$.extend(this, range); // assigns every property to this object's member variables
14931
14932			this.updateTitle();
14933
14934		},
14935
14936
14937
14938
14939
14940		// Given a single current unzoned date, produce information about what range to display.
14941
14942		// Subclasses can override. Must return all properties.
14943
14944		computeRange: function(date) {
14945
14946			var intervalUnit = computeIntervalUnit(this.intervalDuration);
14947
14948			var intervalStart = date.clone().startOf(intervalUnit);
14949
14950			var intervalEnd = intervalStart.clone().add(this.intervalDuration);
14951
14952			var start, end;
14953
14954
14955
14956			// normalize the range's time-ambiguity
14957
14958			if (/year|month|week|day/.test(intervalUnit)) { // whole-days?
14959
14960				intervalStart.stripTime();
14961
14962				intervalEnd.stripTime();
14963
14964			}
14965
14966			else { // needs to have a time?
14967
14968				if (!intervalStart.hasTime()) {
14969
14970					intervalStart = this.calendar.time(0); // give 00:00 time
14971
14972				}
14973
14974				if (!intervalEnd.hasTime()) {
14975
14976					intervalEnd = this.calendar.time(0); // give 00:00 time
14977
14978				}
14979
14980			}
14981
14982
14983
14984			start = intervalStart.clone();
14985
14986			start = this.skipHiddenDays(start);
14987
14988			end = intervalEnd.clone();
14989
14990			end = this.skipHiddenDays(end, -1, true); // exclusively move backwards
14991
14992
14993
14994			return {
14995
14996				intervalUnit: intervalUnit,
14997
14998				intervalStart: intervalStart,
14999
15000				intervalEnd: intervalEnd,
15001
15002				start: start,
15003
15004				end: end
15005
15006			};
15007
15008		},
15009
15010
15011
15012
15013
15014		// Computes the new date when the user hits the prev button, given the current date
15015
15016		computePrevDate: function(date) {
15017
15018			return this.massageCurrentDate(
15019
15020				date.clone().startOf(this.intervalUnit).subtract(this.intervalDuration), -1
15021
15022			);
15023
15024		},
15025
15026
15027
15028
15029
15030		// Computes the new date when the user hits the next button, given the current date
15031
15032		computeNextDate: function(date) {
15033
15034			return this.massageCurrentDate(
15035
15036				date.clone().startOf(this.intervalUnit).add(this.intervalDuration)
15037
15038			);
15039
15040		},
15041
15042
15043
15044
15045
15046		// Given an arbitrarily calculated current date of the calendar, returns a date that is ensured to be completely
15047
15048		// visible. `direction` is optional and indicates which direction the current date was being
15049
15050		// incremented or decremented (1 or -1).
15051
15052		massageCurrentDate: function(date, direction) {
15053
15054			if (this.intervalDuration.as('days') <= 1) { // if the view displays a single day or smaller
15055
15056				if (this.isHiddenDay(date)) {
15057
15058					date = this.skipHiddenDays(date, direction);
15059
15060					date.startOf('day');
15061
15062				}
15063
15064			}
15065
15066
15067
15068			return date;
15069
15070		},
15071
15072
15073
15074
15075
15076		/* Title and Date Formatting
15077
15078		 ------------------------------------------------------------------------------------------------------------------*/
15079
15080
15081
15082
15083
15084		// Sets the view's title property to the most updated computed value
15085
15086		updateTitle: function() {
15087
15088			this.title = this.computeTitle();
15089
15090		},
15091
15092
15093
15094
15095
15096		// Computes what the title at the top of the calendar should be for this view
15097
15098		computeTitle: function() {
15099
15100			return this.formatRange(
15101
15102				{
15103
15104					// in case intervalStart/End has a time, make sure timezone is correct
15105
15106					start: this.calendar.applyTimezone(this.intervalStart),
15107
15108					end: this.calendar.applyTimezone(this.intervalEnd)
15109
15110				},
15111
15112				this.opt('titleFormat') || this.computeTitleFormat(),
15113
15114				this.opt('titleRangeSeparator')
15115
15116			);
15117
15118		},
15119
15120
15121
15122
15123
15124		// Generates the format string that should be used to generate the title for the current date range.
15125
15126		// Attempts to compute the most appropriate format if not explicitly specified with `titleFormat`.
15127
15128		computeTitleFormat: function() {
15129
15130			if (this.intervalUnit == 'year') {
15131
15132				return 'YYYY';
15133
15134			}
15135
15136			else if (this.intervalUnit == 'month') {
15137
15138				return this.opt('monthYearFormat'); // like "September 2014"
15139
15140			}
15141
15142			else if (this.intervalDuration.as('days') > 1) {
15143
15144				return 'll'; // multi-day range. shorter, like "Sep 9 - 10 2014"
15145
15146			}
15147
15148			else {
15149
15150				return 'LL'; // one day. longer, like "September 9 2014"
15151
15152			}
15153
15154		},
15155
15156
15157
15158
15159
15160		// Utility for formatting a range. Accepts a range object, formatting string, and optional separator.
15161
15162		// Displays all-day ranges naturally, with an inclusive end. Takes the current isRTL into account.
15163
15164		// The timezones of the dates within `range` will be respected.
15165
15166		formatRange: function(range, formatStr, separator) {
15167
15168			var end = range.end;
15169
15170
15171
15172			if (!end.hasTime()) { // all-day?
15173
15174				end = end.clone().subtract(1); // convert to inclusive. last ms of previous day
15175
15176			}
15177
15178
15179
15180			return formatRange(range.start, end, formatStr, separator, this.opt('isRTL'));
15181
15182		},
15183
15184
15185
15186
15187
15188		/* Rendering
15189
15190		 ------------------------------------------------------------------------------------------------------------------*/
15191
15192
15193
15194
15195
15196		// Sets the container element that the view should render inside of.
15197
15198		// Does other DOM-related initializations.
15199
15200		setElement: function(el) {
15201
15202			this.el = el;
15203
15204			this.bindGlobalHandlers();
15205
15206		},
15207
15208
15209
15210
15211
15212		// Removes the view's container element from the DOM, clearing any content beforehand.
15213
15214		// Undoes any other DOM-related attachments.
15215
15216		removeElement: function() {
15217
15218			this.clear(); // clears all content
15219
15220
15221
15222			// clean up the skeleton
15223
15224			if (this.isSkeletonRendered) {
15225
15226				this.unrenderSkeleton();
15227
15228				this.isSkeletonRendered = false;
15229
15230			}
15231
15232
15233
15234			this.unbindGlobalHandlers();
15235
15236
15237
15238			this.el.remove();
15239
15240
15241
15242			// NOTE: don't null-out this.el in case the View was destroyed within an API callback.
15243
15244			// We don't null-out the View's other jQuery element references upon destroy,
15245
15246			//  so we shouldn't kill this.el either.
15247
15248		},
15249
15250
15251
15252
15253
15254		// Does everything necessary to display the view centered around the given unzoned date.
15255
15256		// Does every type of rendering EXCEPT rendering events.
15257
15258		// Is asychronous and returns a promise.
15259
15260		display: function(date) {
15261
15262			var _this = this;
15263
15264			var scrollState = null;
15265
15266
15267
15268			if (this.displaying) {
15269
15270				scrollState = this.queryScroll();
15271
15272			}
15273
15274
15275
15276			this.calendar.freezeContentHeight();
15277
15278
15279
15280			return this.clear().then(function() { // clear the content first (async)
15281
15282				return (
15283
15284					_this.displaying =
15285
15286						$.when(_this.displayView(date)) // displayView might return a promise
15287
15288							.then(function() {
15289
15290								_this.forceScroll(_this.computeInitialScroll(scrollState));
15291
15292								_this.calendar.unfreezeContentHeight();
15293
15294								_this.triggerRender();
15295
15296							})
15297
15298				);
15299
15300			});
15301
15302		},
15303
15304
15305
15306
15307
15308		// Does everything necessary to clear the content of the view.
15309
15310		// Clears dates and events. Does not clear the skeleton.
15311
15312		// Is asychronous and returns a promise.
15313
15314		clear: function() {
15315
15316			var _this = this;
15317
15318			var displaying = this.displaying;
15319
15320
15321
15322			if (displaying) { // previously displayed, or in the process of being displayed?
15323
15324				return displaying.then(function() { // wait for the display to finish
15325
15326					_this.displaying = null;
15327
15328					_this.clearEvents();
15329
15330					return _this.clearView(); // might return a promise. chain it
15331
15332				});
15333
15334			}
15335
15336			else {
15337
15338				return $.when(); // an immediately-resolved promise
15339
15340			}
15341
15342		},
15343
15344
15345
15346
15347
15348		// If the view has already been displayed, tears it down and displays it again.
15349
15350		// Will re-render the events if necessary, which display/clear DO NOT do.
15351
15352		// TODO: make behavior more consistent.
15353
15354		redisplay: function() {
15355
15356			if (this.isSkeletonRendered) {
15357
15358				var wasEventsRendered = this.isEventsRendered;
15359
15360				this.clearEvents(); // won't trigger handlers if events never rendered
15361
15362				this.clearView();
15363
15364				this.displayView();
15365
15366				if (wasEventsRendered) { // only render and trigger handlers if events previously rendered
15367
15368					this.displayEvents();
15369
15370				}
15371
15372			}
15373
15374		},
15375
15376
15377
15378
15379
15380		// Displays the view's non-event content, such as date-related content or anything required by events.
15381
15382		// Renders the view's non-content skeleton if necessary.
15383
15384		// Can be asynchronous and return a promise.
15385
15386		displayView: function(date) {
15387
15388			if (!this.isSkeletonRendered) {
15389
15390				this.renderSkeleton();
15391
15392				this.isSkeletonRendered = true;
15393
15394			}
15395
15396			if (date) {
15397
15398				this.setDate(date);
15399
15400			}
15401
15402			if (this.render) {
15403
15404				this.render(); // TODO: deprecate
15405
15406			}
15407
15408			this.renderDates();
15409
15410			this.updateSize();
15411
15412			this.renderBusinessHours(); // might need coordinates, so should go after updateSize()
15413
15414		},
15415
15416
15417
15418
15419
15420		// Unrenders the view content that was rendered in displayView.
15421
15422		// Can be asynchronous and return a promise.
15423
15424		clearView: function() {
15425
15426			this.unselect();
15427
15428			this.triggerUnrender();
15429
15430			this.unrenderBusinessHours();
15431
15432			this.unrenderDates();
15433
15434			if (this.destroy) {
15435
15436				this.destroy(); // TODO: deprecate
15437
15438			}
15439
15440		},
15441
15442
15443
15444
15445
15446		// Renders the basic structure of the view before any content is rendered
15447
15448		renderSkeleton: function() {
15449
15450			// subclasses should implement
15451
15452		},
15453
15454
15455
15456
15457
15458		// Unrenders the basic structure of the view
15459
15460		unrenderSkeleton: function() {
15461
15462			// subclasses should implement
15463
15464		},
15465
15466
15467
15468
15469
15470		// Renders the view's date-related content.
15471
15472		// Assumes setRange has already been called and the skeleton has already been rendered.
15473
15474		renderDates: function() {
15475
15476			// subclasses should implement
15477
15478		},
15479
15480
15481
15482
15483
15484		// Unrenders the view's date-related content
15485
15486		unrenderDates: function() {
15487
15488			// subclasses should override
15489
15490		},
15491
15492
15493
15494
15495
15496		// Renders business-hours onto the view. Assumes updateSize has already been called.
15497
15498		renderBusinessHours: function() {
15499
15500			// subclasses should implement
15501
15502		},
15503
15504
15505
15506
15507
15508		// Unrenders previously-rendered business-hours
15509
15510		unrenderBusinessHours: function() {
15511
15512			// subclasses should implement
15513
15514		},
15515
15516
15517
15518
15519
15520		// Signals that the view's content has been rendered
15521
15522		triggerRender: function() {
15523
15524			this.trigger('viewRender', this, this, this.el);
15525
15526		},
15527
15528
15529
15530
15531
15532		// Signals that the view's content is about to be unrendered
15533
15534		triggerUnrender: function() {
15535
15536			this.trigger('viewDestroy', this, this, this.el);
15537
15538		},
15539
15540
15541
15542
15543
15544		// Binds DOM handlers to elements that reside outside the view container, such as the document
15545
15546		bindGlobalHandlers: function() {
15547
15548			$(document).on('mousedown', this.documentMousedownProxy);
15549
15550		},
15551
15552
15553
15554
15555
15556		// Unbinds DOM handlers from elements that reside outside the view container
15557
15558		unbindGlobalHandlers: function() {
15559
15560			$(document).off('mousedown', this.documentMousedownProxy);
15561
15562		},
15563
15564
15565
15566
15567
15568		// Initializes internal variables related to theming
15569
15570		initThemingProps: function() {
15571
15572			var tm = this.opt('theme') ? 'ui' : 'fc';
15573
15574
15575
15576			this.widgetHeaderClass = tm + '-widget-header';
15577
15578			this.widgetContentClass = tm + '-widget-content';
15579
15580			this.highlightStateClass = tm + '-state-highlight';
15581
15582		},
15583
15584
15585
15586
15587
15588		/* Dimensions
15589
15590		 ------------------------------------------------------------------------------------------------------------------*/
15591
15592
15593
15594
15595
15596		// Refreshes anything dependant upon sizing of the container element of the grid
15597
15598		updateSize: function(isResize) {
15599
15600			var scrollState;
15601
15602
15603
15604			if (isResize) {
15605
15606				scrollState = this.queryScroll();
15607
15608			}
15609
15610
15611
15612			this.updateHeight(isResize);
15613
15614			this.updateWidth(isResize);
15615
15616
15617
15618			if (isResize) {
15619
15620				this.setScroll(scrollState);
15621
15622			}
15623
15624		},
15625
15626
15627
15628
15629
15630		// Refreshes the horizontal dimensions of the calendar
15631
15632		updateWidth: function(isResize) {
15633
15634			// subclasses should implement
15635
15636		},
15637
15638
15639
15640
15641
15642		// Refreshes the vertical dimensions of the calendar
15643
15644		updateHeight: function(isResize) {
15645
15646			var calendar = this.calendar; // we poll the calendar for height information
15647
15648
15649
15650			this.setHeight(
15651
15652				calendar.getSuggestedViewHeight(),
15653
15654				calendar.isHeightAuto()
15655
15656			);
15657
15658		},
15659
15660
15661
15662
15663
15664		// Updates the vertical dimensions of the calendar to the specified height.
15665
15666		// if `isAuto` is set to true, height becomes merely a suggestion and the view should use its "natural" height.
15667
15668		setHeight: function(height, isAuto) {
15669
15670			// subclasses should implement
15671
15672		},
15673
15674
15675
15676
15677
15678		/* Scroller
15679
15680		 ------------------------------------------------------------------------------------------------------------------*/
15681
15682
15683
15684
15685
15686		// Given the total height of the view, return the number of pixels that should be used for the scroller.
15687
15688		// Utility for subclasses.
15689
15690		computeScrollerHeight: function(totalHeight) {
15691
15692			var scrollerEl = this.scrollerEl;
15693
15694			var both;
15695
15696			var otherHeight; // cumulative height of everything that is not the scrollerEl in the view (header+borders)
15697
15698
15699
15700			both = this.el.add(scrollerEl);
15701
15702
15703
15704			// fuckin IE8/9/10/11 sometimes returns 0 for dimensions. this weird hack was the only thing that worked
15705
15706			both.css({
15707
15708				position: 'relative', // cause a reflow, which will force fresh dimension recalculation
15709
15710				left: -1 // ensure reflow in case the el was already relative. negative is less likely to cause new scroll
15711
15712			});
15713
15714			otherHeight = this.el.outerHeight() - scrollerEl.height(); // grab the dimensions
15715
15716			both.css({ position: '', left: '' }); // undo hack
15717
15718
15719
15720			return totalHeight - otherHeight;
15721
15722		},
15723
15724
15725
15726
15727
15728		// Computes the initial pre-configured scroll state prior to allowing the user to change it.
15729
15730		// Given the scroll state from the previous rendering. If first time rendering, given null.
15731
15732		computeInitialScroll: function(previousScrollState) {
15733
15734			return 0;
15735
15736		},
15737
15738
15739
15740
15741
15742		// Retrieves the view's current natural scroll state. Can return an arbitrary format.
15743
15744		queryScroll: function() {
15745
15746			if (this.scrollerEl) {
15747
15748				return this.scrollerEl.scrollTop(); // operates on scrollerEl by default
15749
15750			}
15751
15752		},
15753
15754
15755
15756
15757
15758		// Sets the view's scroll state. Will accept the same format computeInitialScroll and queryScroll produce.
15759
15760		setScroll: function(scrollState) {
15761
15762			if (this.scrollerEl) {
15763
15764				return this.scrollerEl.scrollTop(scrollState); // operates on scrollerEl by default
15765
15766			}
15767
15768		},
15769
15770
15771
15772
15773
15774		// Sets the scroll state, making sure to overcome any predefined scroll value the browser has in mind
15775
15776		forceScroll: function(scrollState) {
15777
15778			var _this = this;
15779
15780
15781
15782			this.setScroll(scrollState);
15783
15784			setTimeout(function() {
15785
15786				_this.setScroll(scrollState);
15787
15788			}, 0);
15789
15790		},
15791
15792
15793
15794
15795
15796		/* Event Elements / Segments
15797
15798		 ------------------------------------------------------------------------------------------------------------------*/
15799
15800
15801
15802
15803
15804		// Does everything necessary to display the given events onto the current view
15805
15806		displayEvents: function(events) {
15807
15808			var scrollState = this.queryScroll();
15809
15810
15811
15812			this.clearEvents();
15813
15814			this.renderEvents(events);
15815
15816			this.isEventsRendered = true;
15817
15818			this.setScroll(scrollState);
15819
15820			this.triggerEventRender();
15821
15822		},
15823
15824
15825
15826
15827
15828		// Does everything necessary to clear the view's currently-rendered events
15829
15830		clearEvents: function() {
15831
15832			if (this.isEventsRendered) {
15833
15834				this.triggerEventUnrender();
15835
15836				if (this.destroyEvents) {
15837
15838					this.destroyEvents(); // TODO: deprecate
15839
15840				}
15841
15842				this.unrenderEvents();
15843
15844				this.isEventsRendered = false;
15845
15846			}
15847
15848		},
15849
15850
15851
15852
15853
15854		// Renders the events onto the view.
15855
15856		renderEvents: function(events) {
15857
15858			// subclasses should implement
15859
15860		},
15861
15862
15863
15864
15865
15866		// Removes event elements from the view.
15867
15868		unrenderEvents: function() {
15869
15870			// subclasses should implement
15871
15872		},
15873
15874
15875
15876
15877
15878		// Signals that all events have been rendered
15879
15880		triggerEventRender: function() {
15881
15882			this.renderedEventSegEach(function(seg) {
15883
15884				this.trigger('eventAfterRender', seg.event, seg.event, seg.el);
15885
15886			});
15887
15888			this.trigger('eventAfterAllRender');
15889
15890		},
15891
15892
15893
15894
15895
15896		// Signals that all event elements are about to be removed
15897
15898		triggerEventUnrender: function() {
15899
15900			this.renderedEventSegEach(function(seg) {
15901
15902				this.trigger('eventDestroy', seg.event, seg.event, seg.el);
15903
15904			});
15905
15906		},
15907
15908
15909
15910
15911
15912		// Given an event and the default element used for rendering, returns the element that should actually be used.
15913
15914		// Basically runs events and elements through the eventRender hook.
15915
15916		resolveEventEl: function(event, el) {
15917
15918			var custom = this.trigger('eventRender', event, event, el);
15919
15920
15921
15922			if (custom === false) { // means don't render at all
15923
15924				el = null;
15925
15926			}
15927
15928			else if (custom && custom !== true) {
15929
15930				el = $(custom);
15931
15932			}
15933
15934
15935
15936			return el;
15937
15938		},
15939
15940
15941
15942
15943
15944		// Hides all rendered event segments linked to the given event
15945
15946		showEvent: function(event) {
15947
15948			this.renderedEventSegEach(function(seg) {
15949
15950				seg.el.css('visibility', '');
15951
15952			}, event);
15953
15954		},
15955
15956
15957
15958
15959
15960		// Shows all rendered event segments linked to the given event
15961
15962		hideEvent: function(event) {
15963
15964			this.renderedEventSegEach(function(seg) {
15965
15966				seg.el.css('visibility', 'hidden');
15967
15968			}, event);
15969
15970		},
15971
15972
15973
15974
15975
15976		// Iterates through event segments that have been rendered (have an el). Goes through all by default.
15977
15978		// If the optional `event` argument is specified, only iterates through segments linked to that event.
15979
15980		// The `this` value of the callback function will be the view.
15981
15982		renderedEventSegEach: function(func, event) {
15983
15984			var segs = this.getEventSegs();
15985
15986			var i;
15987
15988
15989
15990			for (i = 0; i < segs.length; i++) {
15991
15992				if (!event || segs[i].event._id === event._id) {
15993
15994					if (segs[i].el) {
15995
15996						func.call(this, segs[i]);
15997
15998					}
15999
16000				}
16001
16002			}
16003
16004		},
16005
16006
16007
16008
16009
16010		// Retrieves all the rendered segment objects for the view
16011
16012		getEventSegs: function() {
16013
16014			// subclasses must implement
16015
16016			return [];
16017
16018		},
16019
16020
16021
16022
16023
16024		/* Event Drag-n-Drop
16025
16026		 ------------------------------------------------------------------------------------------------------------------*/
16027
16028
16029
16030
16031
16032		// Computes if the given event is allowed to be dragged by the user
16033
16034		isEventDraggable: function(event) {
16035
16036			var source = event.source || {};
16037
16038
16039
16040			return firstDefined(
16041
16042				event.startEditable,
16043
16044				source.startEditable,
16045
16046				this.opt('eventStartEditable'),
16047
16048				event.editable,
16049
16050				source.editable,
16051
16052				this.opt('editable')
16053
16054			);
16055
16056		},
16057
16058
16059
16060
16061
16062		// Must be called when an event in the view is dropped onto new location.
16063
16064		// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
16065
16066		reportEventDrop: function(event, dropLocation, largeUnit, el, ev) {
16067
16068			var calendar = this.calendar;
16069
16070			var mutateResult = calendar.mutateEvent(event, dropLocation, largeUnit);
16071
16072			var undoFunc = function() {
16073
16074				mutateResult.undo();
16075
16076				calendar.reportEventChange();
16077
16078			};
16079
16080
16081
16082			this.triggerEventDrop(event, mutateResult.dateDelta, undoFunc, el, ev);
16083
16084			calendar.reportEventChange(); // will rerender events
16085
16086		},
16087
16088
16089
16090
16091
16092		// Triggers event-drop handlers that have subscribed via the API
16093
16094		triggerEventDrop: function(event, dateDelta, undoFunc, el, ev) {
16095
16096			this.trigger('eventDrop', el[0], event, dateDelta, undoFunc, ev, {}); // {} = jqui dummy
16097
16098		},
16099
16100
16101
16102
16103
16104		/* External Element Drag-n-Drop
16105
16106		 ------------------------------------------------------------------------------------------------------------------*/
16107
16108
16109
16110
16111
16112		// Must be called when an external element, via jQuery UI, has been dropped onto the calendar.
16113
16114		// `meta` is the parsed data that has been embedded into the dragging event.
16115
16116		// `dropLocation` is an object that contains the new zoned start/end/allDay values for the event.
16117
16118		reportExternalDrop: function(meta, dropLocation, el, ev, ui) {
16119
16120			var eventProps = meta.eventProps;
16121
16122			var eventInput;
16123
16124			var event;
16125
16126
16127
16128			// Try to build an event object and render it. TODO: decouple the two
16129
16130			if (eventProps) {
16131
16132				eventInput = $.extend({}, eventProps, dropLocation);
16133
16134				event = this.calendar.renderEvent(eventInput, meta.stick)[0]; // renderEvent returns an array
16135
16136			}
16137
16138
16139
16140			this.triggerExternalDrop(event, dropLocation, el, ev, ui);
16141
16142		},
16143
16144
16145
16146
16147
16148		// Triggers external-drop handlers that have subscribed via the API
16149
16150		triggerExternalDrop: function(event, dropLocation, el, ev, ui) {
16151
16152
16153
16154			// trigger 'drop' regardless of whether element represents an event
16155
16156			this.trigger('drop', el[0], dropLocation.start, ev, ui);
16157
16158
16159
16160			if (event) {
16161
16162				this.trigger('eventReceive', null, event); // signal an external event landed
16163
16164			}
16165
16166		},
16167
16168
16169
16170
16171
16172		/* Drag-n-Drop Rendering (for both events and external elements)
16173
16174		 ------------------------------------------------------------------------------------------------------------------*/
16175
16176
16177
16178
16179
16180		// Renders a visual indication of a event or external-element drag over the given drop zone.
16181
16182		// If an external-element, seg will be `null`
16183
16184		renderDrag: function(dropLocation, seg) {
16185
16186			// subclasses must implement
16187
16188		},
16189
16190
16191
16192
16193
16194		// Unrenders a visual indication of an event or external-element being dragged.
16195
16196		unrenderDrag: function() {
16197
16198			// subclasses must implement
16199
16200		},
16201
16202
16203
16204
16205
16206		/* Event Resizing
16207
16208		 ------------------------------------------------------------------------------------------------------------------*/
16209
16210
16211
16212
16213
16214		// Computes if the given event is allowed to be resized from its starting edge
16215
16216		isEventResizableFromStart: function(event) {
16217
16218			return this.opt('eventResizableFromStart') && this.isEventResizable(event);
16219
16220		},
16221
16222
16223
16224
16225
16226		// Computes if the given event is allowed to be resized from its ending edge
16227
16228		isEventResizableFromEnd: function(event) {
16229
16230			return this.isEventResizable(event);
16231
16232		},
16233
16234
16235
16236
16237
16238		// Computes if the given event is allowed to be resized by the user at all
16239
16240		isEventResizable: function(event) {
16241
16242			var source = event.source || {};
16243
16244
16245
16246			return firstDefined(
16247
16248				event.durationEditable,
16249
16250				source.durationEditable,
16251
16252				this.opt('eventDurationEditable'),
16253
16254				event.editable,
16255
16256				source.editable,
16257
16258				this.opt('editable')
16259
16260			);
16261
16262		},
16263
16264
16265
16266
16267
16268		// Must be called when an event in the view has been resized to a new length
16269
16270		reportEventResize: function(event, resizeLocation, largeUnit, el, ev) {
16271
16272			var calendar = this.calendar;
16273
16274			var mutateResult = calendar.mutateEvent(event, resizeLocation, largeUnit);
16275
16276			var undoFunc = function() {
16277
16278				mutateResult.undo();
16279
16280				calendar.reportEventChange();
16281
16282			};
16283
16284
16285
16286			this.triggerEventResize(event, mutateResult.durationDelta, undoFunc, el, ev);
16287
16288			calendar.reportEventChange(); // will rerender events
16289
16290		},
16291
16292
16293
16294
16295
16296		// Triggers event-resize handlers that have subscribed via the API
16297
16298		triggerEventResize: function(event, durationDelta, undoFunc, el, ev) {
16299
16300			this.trigger('eventResize', el[0], event, durationDelta, undoFunc, ev, {}); // {} = jqui dummy
16301
16302		},
16303
16304
16305
16306
16307
16308		/* Selection
16309
16310		 ------------------------------------------------------------------------------------------------------------------*/
16311
16312
16313
16314
16315
16316		// Selects a date span on the view. `start` and `end` are both Moments.
16317
16318		// `ev` is the native mouse event that begin the interaction.
16319
16320		select: function(span, ev) {
16321
16322			this.unselect(ev);
16323
16324			this.renderSelection(span);
16325
16326			this.reportSelection(span, ev);
16327
16328		},
16329
16330
16331
16332
16333
16334		// Renders a visual indication of the selection
16335
16336		renderSelection: function(span) {
16337
16338			// subclasses should implement
16339
16340		},
16341
16342
16343
16344
16345
16346		// Called when a new selection is made. Updates internal state and triggers handlers.
16347
16348		reportSelection: function(span, ev) {
16349
16350			this.isSelected = true;
16351
16352			this.triggerSelect(span, ev);
16353
16354		},
16355
16356
16357
16358
16359
16360		// Triggers handlers to 'select'
16361
16362		triggerSelect: function(span, ev) {
16363
16364			this.trigger(
16365
16366				'select',
16367
16368				null,
16369
16370				this.calendar.applyTimezone(span.start), // convert to calendar's tz for external API
16371
16372				this.calendar.applyTimezone(span.end), // "
16373
16374				ev
16375
16376			);
16377
16378		},
16379
16380
16381
16382
16383
16384		// Undoes a selection. updates in the internal state and triggers handlers.
16385
16386		// `ev` is the native mouse event that began the interaction.
16387
16388		unselect: function(ev) {
16389
16390			if (this.isSelected) {
16391
16392				this.isSelected = false;
16393
16394				if (this.destroySelection) {
16395
16396					this.destroySelection(); // TODO: deprecate
16397
16398				}
16399
16400				this.unrenderSelection();
16401
16402				this.trigger('unselect', null, ev);
16403
16404			}
16405
16406		},
16407
16408
16409
16410
16411
16412		// Unrenders a visual indication of selection
16413
16414		unrenderSelection: function() {
16415
16416			// subclasses should implement
16417
16418		},
16419
16420
16421
16422
16423
16424		// Handler for unselecting when the user clicks something and the 'unselectAuto' setting is on
16425
16426		documentMousedown: function(ev) {
16427
16428			var ignore;
16429
16430
16431
16432			// is there a selection, and has the user made a proper left click?
16433
16434			if (this.isSelected && this.opt('unselectAuto') && isPrimaryMouseButton(ev)) {
16435
16436
16437
16438				// only unselect if the clicked element is not identical to or inside of an 'unselectCancel' element
16439
16440				ignore = this.opt('unselectCancel');
16441
16442				if (!ignore || !$(ev.target).closest(ignore).length) {
16443
16444					this.unselect(ev);
16445
16446				}
16447
16448			}
16449
16450		},
16451
16452
16453
16454
16455
16456		/* Day Click
16457
16458		 ------------------------------------------------------------------------------------------------------------------*/
16459
16460
16461
16462
16463
16464		// Triggers handlers to 'dayClick'
16465
16466		// Span has start/end of the clicked area. Only the start is useful.
16467
16468		triggerDayClick: function(span, dayEl, ev) {
16469
16470			this.trigger(
16471
16472				'dayClick',
16473
16474				dayEl,
16475
16476				this.calendar.applyTimezone(span.start), // convert to calendar's timezone for external API
16477
16478				ev
16479
16480			);
16481
16482		},
16483
16484
16485
16486
16487
16488		/* Date Utils
16489
16490		 ------------------------------------------------------------------------------------------------------------------*/
16491
16492
16493
16494
16495
16496		// Initializes internal variables related to calculating hidden days-of-week
16497
16498		initHiddenDays: function() {
16499
16500			var hiddenDays = this.opt('hiddenDays') || []; // array of day-of-week indices that are hidden
16501
16502			var isHiddenDayHash = []; // is the day-of-week hidden? (hash with day-of-week-index -> bool)
16503
16504			var dayCnt = 0;
16505
16506			var i;
16507
16508
16509
16510			if (this.opt('weekends') === false) {
16511
16512				hiddenDays.push(0, 6); // 0=sunday, 6=saturday
16513
16514			}
16515
16516
16517
16518			for (i = 0; i < 7; i++) {
16519
16520				if (
16521
16522					!(isHiddenDayHash[i] = $.inArray(i, hiddenDays) !== -1)
16523
16524				) {
16525
16526					dayCnt++;
16527
16528				}
16529
16530			}
16531
16532
16533
16534			if (!dayCnt) {
16535
16536				throw 'invalid hiddenDays'; // all days were hidden? bad.
16537
16538			}
16539
16540
16541
16542			this.isHiddenDayHash = isHiddenDayHash;
16543
16544		},
16545
16546
16547
16548
16549
16550		// Is the current day hidden?
16551
16552		// `day` is a day-of-week index (0-6), or a Moment
16553
16554		isHiddenDay: function(day) {
16555
16556			if (moment.isMoment(day)) {
16557
16558				day = day.day();
16559
16560			}
16561
16562			return this.isHiddenDayHash[day];
16563
16564		},
16565
16566
16567
16568
16569
16570		// Incrementing the current day until it is no longer a hidden day, returning a copy.
16571
16572		// If the initial value of `date` is not a hidden day, don't do anything.
16573
16574		// Pass `isExclusive` as `true` if you are dealing with an end date.
16575
16576		// `inc` defaults to `1` (increment one day forward each time)
16577
16578		skipHiddenDays: function(date, inc, isExclusive) {
16579
16580			var out = date.clone();
16581
16582			inc = inc || 1;
16583
16584			while (
16585
16586				this.isHiddenDayHash[(out.day() + (isExclusive ? inc : 0) + 7) % 7]
16587
16588				) {
16589
16590				out.add(inc, 'days');
16591
16592			}
16593
16594			return out;
16595
16596		},
16597
16598
16599
16600
16601
16602		// Returns the date range of the full days the given range visually appears to occupy.
16603
16604		// Returns a new range object.
16605
16606		computeDayRange: function(range) {
16607
16608			var startDay = range.start.clone().stripTime(); // the beginning of the day the range starts
16609
16610			var end = range.end;
16611
16612			var endDay = null;
16613
16614			var endTimeMS;
16615
16616
16617
16618			if (end) {
16619
16620				endDay = end.clone().stripTime(); // the beginning of the day the range exclusively ends
16621
16622				endTimeMS = +end.time(); // # of milliseconds into `endDay`
16623
16624
16625
16626				// If the end time is actually inclusively part of the next day and is equal to or
16627
16628				// beyond the next day threshold, adjust the end to be the exclusive end of `endDay`.
16629
16630				// Otherwise, leaving it as inclusive will cause it to exclude `endDay`.
16631
16632				if (endTimeMS && endTimeMS >= this.nextDayThreshold) {
16633
16634					endDay.add(1, 'days');
16635
16636				}
16637
16638			}
16639
16640
16641
16642			// If no end was specified, or if it is within `startDay` but not past nextDayThreshold,
16643
16644			// assign the default duration of one day.
16645
16646			if (!end || endDay <= startDay) {
16647
16648				endDay = startDay.clone().add(1, 'days');
16649
16650			}
16651
16652
16653
16654			return { start: startDay, end: endDay };
16655
16656		},
16657
16658
16659
16660
16661
16662		// Does the given event visually appear to occupy more than one day?
16663
16664		isMultiDayEvent: function(event) {
16665
16666			var range = this.computeDayRange(event); // event is range-ish
16667
16668
16669
16670			return range.end.diff(range.start, 'days') > 1;
16671
16672		}
16673
16674
16675
16676	});
16677
16678
16679
16680	;;
16681
16682
16683
16684	var Calendar = FC.Calendar = Class.extend({
16685
16686
16687
16688		dirDefaults: null, // option defaults related to LTR or RTL
16689
16690		langDefaults: null, // option defaults related to current locale
16691
16692		overrides: null, // option overrides given to the fullCalendar constructor
16693
16694		options: null, // all defaults combined with overrides
16695
16696		viewSpecCache: null, // cache of view definitions
16697
16698		view: null, // current View object
16699
16700		header: null,
16701
16702		loadingLevel: 0, // number of simultaneous loading tasks
16703
16704
16705
16706
16707
16708		// a lot of this class' OOP logic is scoped within this constructor function,
16709
16710		// but in the future, write individual methods on the prototype.
16711
16712		constructor: Calendar_constructor,
16713
16714
16715
16716
16717
16718		// Subclasses can override this for initialization logic after the constructor has been called
16719
16720		initialize: function() {
16721
16722		},
16723
16724
16725
16726
16727
16728		// Initializes `this.options` and other important options-related objects
16729
16730		initOptions: function(overrides) {
16731
16732			var lang, langDefaults;
16733
16734			var isRTL, dirDefaults;
16735
16736
16737
16738			// converts legacy options into non-legacy ones.
16739
16740			// in the future, when this is removed, don't use `overrides` reference. make a copy.
16741
16742			overrides = massageOverrides(overrides);
16743
16744
16745
16746			lang = overrides.lang;
16747
16748			langDefaults = langOptionHash[lang];
16749
16750			if (!langDefaults) {
16751
16752				lang = Calendar.defaults.lang;
16753
16754				langDefaults = langOptionHash[lang] || {};
16755
16756			}
16757
16758
16759
16760			isRTL = firstDefined(
16761
16762				overrides.isRTL,
16763
16764				langDefaults.isRTL,
16765
16766				Calendar.defaults.isRTL
16767
16768			);
16769
16770			dirDefaults = isRTL ? Calendar.rtlDefaults : {};
16771
16772
16773
16774			this.dirDefaults = dirDefaults;
16775
16776			this.langDefaults = langDefaults;
16777
16778			this.overrides = overrides;
16779
16780			this.options = mergeOptions([ // merge defaults and overrides. lowest to highest precedence
16781
16782				Calendar.defaults, // global defaults
16783
16784				dirDefaults,
16785
16786				langDefaults,
16787
16788				overrides
16789
16790			]);
16791
16792			populateInstanceComputableOptions(this.options);
16793
16794
16795
16796			this.viewSpecCache = {}; // somewhat unrelated
16797
16798		},
16799
16800
16801
16802
16803
16804		// Gets information about how to create a view. Will use a cache.
16805
16806		getViewSpec: function(viewType) {
16807
16808			var cache = this.viewSpecCache;
16809
16810
16811
16812			return cache[viewType] || (cache[viewType] = this.buildViewSpec(viewType));
16813
16814		},
16815
16816
16817
16818
16819
16820		// Given a duration singular unit, like "week" or "day", finds a matching view spec.
16821
16822		// Preference is given to views that have corresponding buttons.
16823
16824		getUnitViewSpec: function(unit) {
16825
16826			var viewTypes;
16827
16828			var i;
16829
16830			var spec;
16831
16832
16833
16834			if ($.inArray(unit, intervalUnits) != -1) {
16835
16836
16837
16838				// put views that have buttons first. there will be duplicates, but oh well
16839
16840				viewTypes = this.header.getViewsWithButtons();
16841
16842				$.each(FC.views, function(viewType) { // all views
16843
16844					viewTypes.push(viewType);
16845
16846				});
16847
16848
16849
16850				for (i = 0; i < viewTypes.length; i++) {
16851
16852					spec = this.getViewSpec(viewTypes[i]);
16853
16854					if (spec) {
16855
16856						if (spec.singleUnit == unit) {
16857
16858							return spec;
16859
16860						}
16861
16862					}
16863
16864				}
16865
16866			}
16867
16868		},
16869
16870
16871
16872
16873
16874		// Builds an object with information on how to create a given view
16875
16876		buildViewSpec: function(requestedViewType) {
16877
16878			var viewOverrides = this.overrides.views || {};
16879
16880			var specChain = []; // for the view. lowest to highest priority
16881
16882			var defaultsChain = []; // for the view. lowest to highest priority
16883
16884			var overridesChain = []; // for the view. lowest to highest priority
16885
16886			var viewType = requestedViewType;
16887
16888			var spec; // for the view
16889
16890			var overrides; // for the view
16891
16892			var duration;
16893
16894			var unit;
16895
16896
16897
16898			// iterate from the specific view definition to a more general one until we hit an actual View class
16899
16900			while (viewType) {
16901
16902				spec = fcViews[viewType];
16903
16904				overrides = viewOverrides[viewType];
16905
16906				viewType = null; // clear. might repopulate for another iteration
16907
16908
16909
16910				if (typeof spec === 'function') { // TODO: deprecate
16911
16912					spec = { 'class': spec };
16913
16914				}
16915
16916
16917
16918				if (spec) {
16919
16920					specChain.unshift(spec);
16921
16922					defaultsChain.unshift(spec.defaults || {});
16923
16924					duration = duration || spec.duration;
16925
16926					viewType = viewType || spec.type;
16927
16928				}
16929
16930
16931
16932				if (overrides) {
16933
16934					overridesChain.unshift(overrides); // view-specific option hashes have options at zero-level
16935
16936					duration = duration || overrides.duration;
16937
16938					viewType = viewType || overrides.type;
16939
16940				}
16941
16942			}
16943
16944
16945
16946			spec = mergeProps(specChain);
16947
16948			spec.type = requestedViewType;
16949
16950			if (!spec['class']) {
16951
16952				return false;
16953
16954			}
16955
16956
16957
16958			if (duration) {
16959
16960				duration = moment.duration(duration);
16961
16962				if (duration.valueOf()) { // valid?
16963
16964					spec.duration = duration;
16965
16966					unit = computeIntervalUnit(duration);
16967
16968
16969
16970					// view is a single-unit duration, like "week" or "day"
16971
16972					// incorporate options for this. lowest priority
16973
16974					if (duration.as(unit) === 1) {
16975
16976						spec.singleUnit = unit;
16977
16978						overridesChain.unshift(viewOverrides[unit] || {});
16979
16980					}
16981
16982				}
16983
16984			}
16985
16986
16987
16988			spec.defaults = mergeOptions(defaultsChain);
16989
16990			spec.overrides = mergeOptions(overridesChain);
16991
16992
16993
16994			this.buildViewSpecOptions(spec);
16995
16996			this.buildViewSpecButtonText(spec, requestedViewType);
16997
16998
16999
17000			return spec;
17001
17002		},
17003
17004
17005
17006
17007
17008		// Builds and assigns a view spec's options object from its already-assigned defaults and overrides
17009
17010		buildViewSpecOptions: function(spec) {
17011
17012			spec.options = mergeOptions([ // lowest to highest priority
17013
17014				Calendar.defaults, // global defaults
17015
17016				spec.defaults, // view's defaults (from ViewSubclass.defaults)
17017
17018				this.dirDefaults,
17019
17020				this.langDefaults, // locale and dir take precedence over view's defaults!
17021
17022				this.overrides, // calendar's overrides (options given to constructor)
17023
17024				spec.overrides // view's overrides (view-specific options)
17025
17026			]);
17027
17028			populateInstanceComputableOptions(spec.options);
17029
17030		},
17031
17032
17033
17034
17035
17036		// Computes and assigns a view spec's buttonText-related options
17037
17038		buildViewSpecButtonText: function(spec, requestedViewType) {
17039
17040
17041
17042			// given an options object with a possible `buttonText` hash, lookup the buttonText for the
17043
17044			// requested view, falling back to a generic unit entry like "week" or "day"
17045
17046			function queryButtonText(options) {
17047
17048				var buttonText = options.buttonText || {};
17049
17050				return buttonText[requestedViewType] ||
17051
17052					(spec.singleUnit ? buttonText[spec.singleUnit] : null);
17053
17054			}
17055
17056
17057
17058			// highest to lowest priority
17059
17060			spec.buttonTextOverride =
17061
17062				queryButtonText(this.overrides) || // constructor-specified buttonText lookup hash takes precedence
17063
17064				spec.overrides.buttonText; // `buttonText` for view-specific options is a string
17065
17066
17067
17068			// highest to lowest priority. mirrors buildViewSpecOptions
17069
17070			spec.buttonTextDefault =
17071
17072				queryButtonText(this.langDefaults) ||
17073
17074				queryButtonText(this.dirDefaults) ||
17075
17076				spec.defaults.buttonText || // a single string. from ViewSubclass.defaults
17077
17078				queryButtonText(Calendar.defaults) ||
17079
17080				(spec.duration ? this.humanizeDuration(spec.duration) : null) || // like "3 days"
17081
17082				requestedViewType; // fall back to given view name
17083
17084		},
17085
17086
17087
17088
17089
17090		// Given a view name for a custom view or a standard view, creates a ready-to-go View object
17091
17092		instantiateView: function(viewType) {
17093
17094			var spec = this.getViewSpec(viewType);
17095
17096
17097
17098			return new spec['class'](this, viewType, spec.options, spec.duration);
17099
17100		},
17101
17102
17103
17104
17105
17106		// Returns a boolean about whether the view is okay to instantiate at some point
17107
17108		isValidViewType: function(viewType) {
17109
17110			return Boolean(this.getViewSpec(viewType));
17111
17112		},
17113
17114
17115
17116
17117
17118		// Should be called when any type of async data fetching begins
17119
17120		pushLoading: function() {
17121
17122			if (!(this.loadingLevel++)) {
17123
17124				this.trigger('loading', null, true, this.view);
17125
17126			}
17127
17128		},
17129
17130
17131
17132
17133
17134		// Should be called when any type of async data fetching completes
17135
17136		popLoading: function() {
17137
17138			if (!(--this.loadingLevel)) {
17139
17140				this.trigger('loading', null, false, this.view);
17141
17142			}
17143
17144		},
17145
17146
17147
17148
17149
17150		// Given arguments to the select method in the API, returns a span (unzoned start/end and other info)
17151
17152		buildSelectSpan: function(zonedStartInput, zonedEndInput) {
17153
17154			var start = this.moment(zonedStartInput).stripZone();
17155
17156			var end;
17157
17158
17159
17160			if (zonedEndInput) {
17161
17162				end = this.moment(zonedEndInput).stripZone();
17163
17164			}
17165
17166			else if (start.hasTime()) {
17167
17168				end = start.clone().add(this.defaultTimedEventDuration);
17169
17170			}
17171
17172			else {
17173
17174				end = start.clone().add(this.defaultAllDayEventDuration);
17175
17176			}
17177
17178
17179
17180			return { start: start, end: end };
17181
17182		}
17183
17184
17185
17186	});
17187
17188
17189
17190
17191
17192	Calendar.mixin(Emitter);
17193
17194
17195
17196
17197
17198	function Calendar_constructor(element, overrides) {
17199
17200		var t = this;
17201
17202
17203
17204
17205
17206		t.initOptions(overrides || {});
17207
17208		var options = this.options;
17209
17210
17211
17212
17213
17214		// Exports
17215
17216		// -----------------------------------------------------------------------------------
17217
17218
17219
17220		t.render = render;
17221
17222		t.destroy = destroy;
17223
17224		t.refetchEvents = refetchEvents;
17225
17226		t.reportEvents = reportEvents;
17227
17228		t.reportEventChange = reportEventChange;
17229
17230		t.rerenderEvents = renderEvents; // `renderEvents` serves as a rerender. an API method
17231
17232		t.changeView = renderView; // `renderView` will switch to another view
17233
17234		t.select = select;
17235
17236		t.unselect = unselect;
17237
17238		t.prev = prev;
17239
17240		t.next = next;
17241
17242		t.prevYear = prevYear;
17243
17244		t.nextYear = nextYear;
17245
17246		t.today = today;
17247
17248		t.gotoDate = gotoDate;
17249
17250		t.incrementDate = incrementDate;
17251
17252		t.zoomTo = zoomTo;
17253
17254		t.getDate = getDate;
17255
17256		t.getCalendar = getCalendar;
17257
17258		t.getView = getView;
17259
17260		t.option = option;
17261
17262		t.trigger = trigger;
17263
17264
17265
17266
17267
17268
17269
17270		// Language-data Internals
17271
17272		// -----------------------------------------------------------------------------------
17273
17274		// Apply overrides to the current language's data
17275
17276
17277
17278
17279
17280		var localeData = createObject( // make a cheap copy
17281
17282			getMomentLocaleData(options.lang) // will fall back to en
17283
17284		);
17285
17286
17287
17288		if (options.monthNames) {
17289
17290			localeData._months = options.monthNames;
17291
17292		}
17293
17294		if (options.monthNamesShort) {
17295
17296			localeData._monthsShort = options.monthNamesShort;
17297
17298		}
17299
17300		if (options.dayNames) {
17301
17302			localeData._weekdays = options.dayNames;
17303
17304		}
17305
17306		if (options.dayNamesShort) {
17307
17308			localeData._weekdaysShort = options.dayNamesShort;
17309
17310		}
17311
17312		if (options.firstDay != null) {
17313
17314			var _week = createObject(localeData._week); // _week: { dow: # }
17315
17316			_week.dow = options.firstDay;
17317
17318			localeData._week = _week;
17319
17320		}
17321
17322
17323
17324		// assign a normalized value, to be used by our .week() moment extension
17325
17326		localeData._fullCalendar_weekCalc = (function(weekCalc) {
17327
17328			if (typeof weekCalc === 'function') {
17329
17330				return weekCalc;
17331
17332			}
17333
17334			else if (weekCalc === 'local') {
17335
17336				return weekCalc;
17337
17338			}
17339
17340			else if (weekCalc === 'iso' || weekCalc === 'ISO') {
17341
17342				return 'ISO';
17343
17344			}
17345
17346		})(options.weekNumberCalculation);
17347
17348
17349
17350
17351
17352
17353
17354		// Calendar-specific Date Utilities
17355
17356		// -----------------------------------------------------------------------------------
17357
17358
17359
17360
17361
17362		t.defaultAllDayEventDuration = moment.duration(options.defaultAllDayEventDuration);
17363
17364		t.defaultTimedEventDuration = moment.duration(options.defaultTimedEventDuration);
17365
17366
17367
17368
17369
17370		// Builds a moment using the settings of the current calendar: timezone and language.
17371
17372		// Accepts anything the vanilla moment() constructor accepts.
17373
17374		t.moment = function() {
17375
17376			var mom;
17377
17378
17379
17380			if (options.timezone === 'local') {
17381
17382				mom = FC.moment.apply(null, arguments);
17383
17384
17385
17386				// Force the moment to be local, because FC.moment doesn't guarantee it.
17387
17388				if (mom.hasTime()) { // don't give ambiguously-timed moments a local zone
17389
17390					mom.local();
17391
17392				}
17393
17394			}
17395
17396			else if (options.timezone === 'UTC') {
17397
17398				mom = FC.moment.utc.apply(null, arguments); // process as UTC
17399
17400			}
17401
17402			else {
17403
17404				mom = FC.moment.parseZone.apply(null, arguments); // let the input decide the zone
17405
17406			}
17407
17408
17409
17410			if ('_locale' in mom) { // moment 2.8 and above
17411
17412				mom._locale = localeData;
17413
17414			}
17415
17416			else { // pre-moment-2.8
17417
17418				mom._lang = localeData;
17419
17420			}
17421
17422
17423
17424			return mom;
17425
17426		};
17427
17428
17429
17430
17431
17432		// Returns a boolean about whether or not the calendar knows how to calculate
17433
17434		// the timezone offset of arbitrary dates in the current timezone.
17435
17436		t.getIsAmbigTimezone = function() {
17437
17438			return options.timezone !== 'local' && options.timezone !== 'UTC';
17439
17440		};
17441
17442
17443
17444
17445
17446		// Returns a copy of the given date in the current timezone. Has no effect on dates without times.
17447
17448		t.applyTimezone = function(date) {
17449
17450			if (!date.hasTime()) {
17451
17452				return date.clone();
17453
17454			}
17455
17456
17457
17458			var zonedDate = t.moment(date.toArray());
17459
17460			var timeAdjust = date.time() - zonedDate.time();
17461
17462			var adjustedZonedDate;
17463
17464
17465
17466			// Safari sometimes has problems with this coersion when near DST. Adjust if necessary. (bug #2396)
17467
17468			if (timeAdjust) { // is the time result different than expected?
17469
17470				adjustedZonedDate = zonedDate.clone().add(timeAdjust); // add milliseconds
17471
17472				if (date.time() - adjustedZonedDate.time() === 0) { // does it match perfectly now?
17473
17474					zonedDate = adjustedZonedDate;
17475
17476				}
17477
17478			}
17479
17480
17481
17482			return zonedDate;
17483
17484		};
17485
17486
17487
17488
17489
17490		// Returns a moment for the current date, as defined by the client's computer or from the `now` option.
17491
17492		// Will return an moment with an ambiguous timezone.
17493
17494		t.getNow = function() {
17495
17496			var now = options.now;
17497
17498			if (typeof now === 'function') {
17499
17500				now = now();
17501
17502			}
17503
17504			return t.moment(now).stripZone();
17505
17506		};
17507
17508
17509
17510
17511
17512		// Get an event's normalized end date. If not present, calculate it from the defaults.
17513
17514		t.getEventEnd = function(event) {
17515
17516			if (event.end) {
17517
17518				return event.end.clone();
17519
17520			}
17521
17522			else {
17523
17524				return t.getDefaultEventEnd(event.allDay, event.start);
17525
17526			}
17527
17528		};
17529
17530
17531
17532
17533
17534		// Given an event's allDay status and start date, return what its fallback end date should be.
17535
17536		// TODO: rename to computeDefaultEventEnd
17537
17538		t.getDefaultEventEnd = function(allDay, zonedStart) {
17539
17540			var end = zonedStart.clone();
17541
17542
17543
17544			if (allDay) {
17545
17546				end.stripTime().add(t.defaultAllDayEventDuration);
17547
17548			}
17549
17550			else {
17551
17552				end.add(t.defaultTimedEventDuration);
17553
17554			}
17555
17556
17557
17558			if (t.getIsAmbigTimezone()) {
17559
17560				end.stripZone(); // we don't know what the tzo should be
17561
17562			}
17563
17564
17565
17566			return end;
17567
17568		};
17569
17570
17571
17572
17573
17574		// Produces a human-readable string for the given duration.
17575
17576		// Side-effect: changes the locale of the given duration.
17577
17578		t.humanizeDuration = function(duration) {
17579
17580			return (duration.locale || duration.lang).call(duration, options.lang) // works moment-pre-2.8
17581
17582				.humanize();
17583
17584		};
17585
17586
17587
17588
17589
17590
17591
17592		// Imports
17593
17594		// -----------------------------------------------------------------------------------
17595
17596
17597
17598
17599
17600		EventManager.call(t, options);
17601
17602		var isFetchNeeded = t.isFetchNeeded;
17603
17604		var fetchEvents = t.fetchEvents;
17605
17606
17607
17608
17609
17610
17611
17612		// Locals
17613
17614		// -----------------------------------------------------------------------------------
17615
17616
17617
17618
17619
17620		var _element = element[0];
17621
17622		var header;
17623
17624		var headerElement;
17625
17626		var content;
17627
17628		var tm; // for making theme classes
17629
17630		var currentView; // NOTE: keep this in sync with this.view
17631
17632		var viewsByType = {}; // holds all instantiated view instances, current or not
17633
17634		var suggestedViewHeight;
17635
17636		var windowResizeProxy; // wraps the windowResize function
17637
17638		var ignoreWindowResize = 0;
17639
17640		var events = [];
17641
17642		var date; // unzoned
17643
17644
17645
17646
17647
17648
17649
17650		// Main Rendering
17651
17652		// -----------------------------------------------------------------------------------
17653
17654
17655
17656
17657
17658		// compute the initial ambig-timezone date
17659
17660		if (options.defaultDate != null) {
17661
17662			date = t.moment(options.defaultDate).stripZone();
17663
17664		}
17665
17666		else {
17667
17668			date = t.getNow(); // getNow already returns unzoned
17669
17670		}
17671
17672
17673
17674
17675
17676		function render() {
17677
17678			if (!content) {
17679
17680				initialRender();
17681
17682			}
17683
17684			else if (elementVisible()) {
17685
17686				// mainly for the public API
17687
17688				calcSize();
17689
17690				renderView();
17691
17692			}
17693
17694		}
17695
17696
17697
17698
17699
17700		function initialRender() {
17701
17702			tm = options.theme ? 'ui' : 'fc';
17703
17704			element.addClass('fc');
17705
17706
17707
17708			if (options.isRTL) {
17709
17710				element.addClass('fc-rtl');
17711
17712			}
17713
17714			else {
17715
17716				element.addClass('fc-ltr');
17717
17718			}
17719
17720
17721
17722			if (options.theme) {
17723
17724				element.addClass('ui-widget');
17725
17726			}
17727
17728			else {
17729
17730				element.addClass('fc-unthemed');
17731
17732			}
17733
17734
17735
17736			content = $("<div class='fc-view-container'/>").prependTo(element);
17737
17738
17739
17740			header = t.header = new Header(t, options);
17741
17742			headerElement = header.render();
17743
17744			if (headerElement) {
17745
17746				element.prepend(headerElement);
17747
17748			}
17749
17750
17751
17752			renderView(options.defaultView);
17753
17754
17755
17756			if (options.handleWindowResize) {
17757
17758				windowResizeProxy = debounce(windowResize, options.windowResizeDelay); // prevents rapid calls
17759
17760				$(window).resize(windowResizeProxy);
17761
17762			}
17763
17764		}
17765
17766
17767
17768
17769
17770		function destroy() {
17771
17772
17773
17774			if (currentView) {
17775
17776				currentView.removeElement();
17777
17778
17779
17780				// NOTE: don't null-out currentView/t.view in case API methods are called after destroy.
17781
17782				// It is still the "current" view, just not rendered.
17783
17784			}
17785
17786
17787
17788			header.removeElement();
17789
17790			content.remove();
17791
17792			element.removeClass('fc fc-ltr fc-rtl fc-unthemed ui-widget');
17793
17794
17795
17796			if (windowResizeProxy) {
17797
17798				$(window).unbind('resize', windowResizeProxy);
17799
17800			}
17801
17802		}
17803
17804
17805
17806
17807
17808		function elementVisible() {
17809
17810			return element.is(':visible');
17811
17812		}
17813
17814
17815
17816
17817
17818
17819
17820		// View Rendering
17821
17822		// -----------------------------------------------------------------------------------
17823
17824
17825
17826
17827
17828		// Renders a view because of a date change, view-type change, or for the first time.
17829
17830		// If not given a viewType, keep the current view but render different dates.
17831
17832		function renderView(viewType) {
17833
17834			ignoreWindowResize++;
17835
17836
17837
17838			// if viewType is changing, remove the old view's rendering
17839
17840			if (currentView && viewType && currentView.type !== viewType) {
17841
17842				header.deactivateButton(currentView.type);
17843
17844				freezeContentHeight(); // prevent a scroll jump when view element is removed
17845
17846				currentView.removeElement();
17847
17848				currentView = t.view = null;
17849
17850			}
17851
17852
17853
17854			// if viewType changed, or the view was never created, create a fresh view
17855
17856			if (!currentView && viewType) {
17857
17858				currentView = t.view =
17859
17860					viewsByType[viewType] ||
17861
17862					(viewsByType[viewType] = t.instantiateView(viewType));
17863
17864
17865
17866				currentView.setElement(
17867
17868					$("<div class='fc-view fc-" + viewType + "-view' />").appendTo(content)
17869
17870				);
17871
17872				header.activateButton(viewType);
17873
17874			}
17875
17876
17877
17878			if (currentView) {
17879
17880
17881
17882				// in case the view should render a period of time that is completely hidden
17883
17884				date = currentView.massageCurrentDate(date);
17885
17886
17887
17888				// render or rerender the view
17889
17890				if (
17891
17892					!currentView.displaying ||
17893
17894					!date.isWithin(currentView.intervalStart, currentView.intervalEnd) // implicit date window change
17895
17896				) {
17897
17898					if (elementVisible()) {
17899
17900
17901
17902						currentView.display(date); // will call freezeContentHeight
17903
17904						unfreezeContentHeight(); // immediately unfreeze regardless of whether display is async
17905
17906
17907
17908						// need to do this after View::render, so dates are calculated
17909
17910						updateHeaderTitle();
17911
17912						updateTodayButton();
17913
17914
17915
17916						getAndRenderEvents();
17917
17918					}
17919
17920				}
17921
17922			}
17923
17924
17925
17926			unfreezeContentHeight(); // undo any lone freezeContentHeight calls
17927
17928			ignoreWindowResize--;
17929
17930		}
17931
17932
17933
17934
17935
17936
17937
17938		// Resizing
17939
17940		// -----------------------------------------------------------------------------------
17941
17942
17943
17944
17945
17946		t.getSuggestedViewHeight = function() {
17947
17948			if (suggestedViewHeight === undefined) {
17949
17950				calcSize();
17951
17952			}
17953
17954			return suggestedViewHeight;
17955
17956		};
17957
17958
17959
17960
17961
17962		t.isHeightAuto = function() {
17963
17964			return options.contentHeight === 'auto' || options.height === 'auto';
17965
17966		};
17967
17968
17969
17970
17971
17972		function updateSize(shouldRecalc) {
17973
17974			if (elementVisible()) {
17975
17976
17977
17978				if (shouldRecalc) {
17979
17980					_calcSize();
17981
17982				}
17983
17984
17985
17986				ignoreWindowResize++;
17987
17988				currentView.updateSize(true); // isResize=true. will poll getSuggestedViewHeight() and isHeightAuto()
17989
17990				ignoreWindowResize--;
17991
17992
17993
17994				return true; // signal success
17995
17996			}
17997
17998		}
17999
18000
18001
18002
18003
18004		function calcSize() {
18005
18006			if (elementVisible()) {
18007
18008				_calcSize();
18009
18010			}
18011
18012		}
18013
18014
18015
18016
18017
18018		function _calcSize() { // assumes elementVisible
18019
18020			if (typeof options.contentHeight === 'number') { // exists and not 'auto'
18021
18022				suggestedViewHeight = options.contentHeight;
18023
18024			}
18025
18026			else if (typeof options.height === 'number') { // exists and not 'auto'
18027
18028				suggestedViewHeight = options.height - (headerElement ? headerElement.outerHeight(true) : 0);
18029
18030			}
18031
18032			else {
18033
18034				suggestedViewHeight = Math.round(content.width() / Math.max(options.aspectRatio, .5));
18035
18036			}
18037
18038		}
18039
18040
18041
18042
18043
18044		function windowResize(ev) {
18045
18046			if (
18047
18048				!ignoreWindowResize &&
18049
18050				ev.target === window && // so we don't process jqui "resize" events that have bubbled up
18051
18052				currentView.start // view has already been rendered
18053
18054			) {
18055
18056				if (updateSize(true)) {
18057
18058					currentView.trigger('windowResize', _element);
18059
18060				}
18061
18062			}
18063
18064		}
18065
18066
18067
18068
18069
18070
18071
18072		/* Event Fetching/Rendering
18073
18074		 -----------------------------------------------------------------------------*/
18075
18076		// TODO: going forward, most of this stuff should be directly handled by the view
18077
18078
18079
18080
18081
18082		function refetchEvents() { // can be called as an API method
18083
18084			destroyEvents(); // so that events are cleared before user starts waiting for AJAX
18085
18086			fetchAndRenderEvents();
18087
18088		}
18089
18090
18091
18092
18093
18094		function renderEvents() { // destroys old events if previously rendered
18095
18096			if (elementVisible()) {
18097
18098				freezeContentHeight();
18099
18100				currentView.displayEvents(events);
18101
18102				unfreezeContentHeight();
18103
18104			}
18105
18106		}
18107
18108
18109
18110
18111
18112		function destroyEvents() {
18113
18114			freezeContentHeight();
18115
18116			currentView.clearEvents();
18117
18118			unfreezeContentHeight();
18119
18120		}
18121
18122
18123
18124
18125
18126		function getAndRenderEvents() {
18127
18128			if (!options.lazyFetching || isFetchNeeded(currentView.start, currentView.end)) {
18129
18130				fetchAndRenderEvents();
18131
18132			}
18133
18134			else {
18135
18136				renderEvents();
18137
18138			}
18139
18140		}
18141
18142
18143
18144
18145
18146		function fetchAndRenderEvents() {
18147
18148			fetchEvents(currentView.start, currentView.end);
18149
18150			// ... will call reportEvents
18151
18152			// ... which will call renderEvents
18153
18154		}
18155
18156
18157
18158
18159
18160		// called when event data arrives
18161
18162		function reportEvents(_events) {
18163
18164			events = _events;
18165
18166			renderEvents();
18167
18168		}
18169
18170
18171
18172
18173
18174		// called when a single event's data has been changed
18175
18176		function reportEventChange() {
18177
18178			renderEvents();
18179
18180		}
18181
18182
18183
18184
18185
18186
18187
18188		/* Header Updating
18189
18190		 -----------------------------------------------------------------------------*/
18191
18192
18193
18194
18195
18196		function updateHeaderTitle() {
18197
18198			header.updateTitle(currentView.title);
18199
18200		}
18201
18202
18203
18204
18205
18206		function updateTodayButton() {
18207
18208			var now = t.getNow();
18209
18210			if (now.isWithin(currentView.intervalStart, currentView.intervalEnd)) {
18211
18212				header.disableButton('today');
18213
18214			}
18215
18216			else {
18217
18218				header.enableButton('today');
18219
18220			}
18221
18222		}
18223
18224
18225
18226
18227
18228
18229
18230		/* Selection
18231
18232		 -----------------------------------------------------------------------------*/
18233
18234
18235
18236
18237
18238		// this public method receives start/end dates in any format, with any timezone
18239
18240		function select(zonedStartInput, zonedEndInput) {
18241
18242			currentView.select(
18243
18244				t.buildSelectSpan.apply(t, arguments)
18245
18246			);
18247
18248		}
18249
18250
18251
18252
18253
18254		function unselect() { // safe to be called before renderView
18255
18256			if (currentView) {
18257
18258				currentView.unselect();
18259
18260			}
18261
18262		}
18263
18264
18265
18266
18267
18268
18269
18270		/* Date
18271
18272		 -----------------------------------------------------------------------------*/
18273
18274
18275
18276
18277
18278		function prev() {
18279
18280			date = currentView.computePrevDate(date);
18281
18282			renderView();
18283
18284		}
18285
18286
18287
18288
18289
18290		function next() {
18291
18292			date = currentView.computeNextDate(date);
18293
18294			renderView();
18295
18296		}
18297
18298
18299
18300
18301
18302		function prevYear() {
18303
18304			date.add(-1, 'years');
18305
18306			renderView();
18307
18308		}
18309
18310
18311
18312
18313
18314		function nextYear() {
18315
18316			date.add(1, 'years');
18317
18318			renderView();
18319
18320		}
18321
18322
18323
18324
18325
18326		function today() {
18327
18328			date = t.getNow();
18329
18330			renderView();
18331
18332		}
18333
18334
18335
18336
18337
18338		function gotoDate(zonedDateInput) {
18339
18340			date = t.moment(zonedDateInput).stripZone();
18341
18342			renderView();
18343
18344		}
18345
18346
18347
18348
18349
18350		function incrementDate(delta) {
18351
18352			date.add(moment.duration(delta));
18353
18354			renderView();
18355
18356		}
18357
18358
18359
18360
18361
18362		// Forces navigation to a view for the given date.
18363
18364		// `viewType` can be a specific view name or a generic one like "week" or "day".
18365
18366		function zoomTo(newDate, viewType) {
18367
18368			var spec;
18369
18370
18371
18372			viewType = viewType || 'day'; // day is default zoom
18373
18374			spec = t.getViewSpec(viewType) || t.getUnitViewSpec(viewType);
18375
18376
18377
18378			date = newDate.clone();
18379
18380			renderView(spec ? spec.type : null);
18381
18382		}
18383
18384
18385
18386
18387
18388		// for external API
18389
18390		function getDate() {
18391
18392			return t.applyTimezone(date); // infuse the calendar's timezone
18393
18394		}
18395
18396
18397
18398
18399
18400
18401
18402		/* Height "Freezing"
18403
18404		 -----------------------------------------------------------------------------*/
18405
18406		// TODO: move this into the view
18407
18408
18409
18410		t.freezeContentHeight = freezeContentHeight;
18411
18412		t.unfreezeContentHeight = unfreezeContentHeight;
18413
18414
18415
18416
18417
18418		function freezeContentHeight() {
18419
18420			content.css({
18421
18422				width: '100%',
18423
18424				height: content.height(),
18425
18426				overflow: 'hidden'
18427
18428			});
18429
18430		}
18431
18432
18433
18434
18435
18436		function unfreezeContentHeight() {
18437
18438			content.css({
18439
18440				width: '',
18441
18442				height: '',
18443
18444				overflow: ''
18445
18446			});
18447
18448		}
18449
18450
18451
18452
18453
18454
18455
18456		/* Misc
18457
18458		 -----------------------------------------------------------------------------*/
18459
18460
18461
18462
18463
18464		function getCalendar() {
18465
18466			return t;
18467
18468		}
18469
18470
18471
18472
18473
18474		function getView() {
18475
18476			return currentView;
18477
18478		}
18479
18480
18481
18482
18483
18484		function option(name, value) {
18485
18486			if (value === undefined) {
18487
18488				return options[name];
18489
18490			}
18491
18492			if (name == 'height' || name == 'contentHeight' || name == 'aspectRatio') {
18493
18494				options[name] = value;
18495
18496				updateSize(true); // true = allow recalculation of height
18497
18498			}
18499
18500		}
18501
18502
18503
18504
18505
18506		function trigger(name, thisObj) { // overrides the Emitter's trigger method :(
18507
18508			var args = Array.prototype.slice.call(arguments, 2);
18509
18510
18511
18512			thisObj = thisObj || _element;
18513
18514			this.triggerWith(name, thisObj, args); // Emitter's method
18515
18516
18517
18518			if (options[name]) {
18519
18520				return options[name].apply(thisObj, args);
18521
18522			}
18523
18524		}
18525
18526
18527
18528		t.initialize();
18529
18530	}
18531
18532
18533
18534	;;
18535
18536
18537
18538	Calendar.defaults = {
18539
18540
18541
18542		titleRangeSeparator: ' \u2014 ', // emphasized dash
18543
18544		monthYearFormat: 'MMMM YYYY', // required for en. other languages rely on datepicker computable option
18545
18546
18547
18548		defaultTimedEventDuration: '02:00:00',
18549
18550		defaultAllDayEventDuration: { days: 1 },
18551
18552		forceEventDuration: false,
18553
18554		nextDayThreshold: '09:00:00', // 9am
18555
18556
18557
18558		// display
18559
18560		defaultView: 'month',
18561
18562		aspectRatio: 1.35,
18563
18564		header: {
18565
18566			left: 'title',
18567
18568			center: '',
18569
18570			right: 'today prev,next'
18571
18572		},
18573
18574		weekends: true,
18575
18576		weekNumbers: false,
18577
18578
18579
18580		weekNumberTitle: 'W',
18581
18582		weekNumberCalculation: 'local',
18583
18584
18585
18586		//editable: false,
18587
18588
18589
18590		scrollTime: '06:00:00',
18591
18592
18593
18594		// event ajax
18595
18596		lazyFetching: true,
18597
18598		startParam: 'start',
18599
18600		endParam: 'end',
18601
18602		timezoneParam: 'timezone',
18603
18604
18605
18606		timezone: false,
18607
18608
18609
18610		//allDayDefault: undefined,
18611
18612
18613
18614		// locale
18615
18616		isRTL: false,
18617
18618		buttonText: {
18619
18620			prev: "prev",
18621
18622			next: "next",
18623
18624			prevYear: "prev year",
18625
18626			nextYear: "next year",
18627
18628			year: 'year', // TODO: locale files need to specify this
18629
18630			today: 'today',
18631
18632			month: 'month',
18633
18634			week: 'week',
18635
18636			day: 'day'
18637
18638		},
18639
18640
18641
18642		buttonIcons: {
18643
18644			prev: 'left-single-arrow',
18645
18646			next: 'right-single-arrow',
18647
18648			prevYear: 'left-double-arrow',
18649
18650			nextYear: 'right-double-arrow'
18651
18652		},
18653
18654
18655
18656		// jquery-ui theming
18657
18658		theme: false,
18659
18660		themeButtonIcons: {
18661
18662			prev: 'circle-triangle-w',
18663
18664			next: 'circle-triangle-e',
18665
18666			prevYear: 'seek-prev',
18667
18668			nextYear: 'seek-next'
18669
18670		},
18671
18672
18673
18674		//eventResizableFromStart: false,
18675
18676		dragOpacity: .75,
18677
18678		dragRevertDuration: 500,
18679
18680		dragScroll: true,
18681
18682
18683
18684		//selectable: false,
18685
18686		unselectAuto: true,
18687
18688
18689
18690		dropAccept: '*',
18691
18692
18693
18694		eventOrder: 'title',
18695
18696
18697
18698		eventLimit: false,
18699
18700		eventLimitText: 'more',
18701
18702		eventLimitClick: 'popover',
18703
18704		dayPopoverFormat: 'LL',
18705
18706
18707
18708		handleWindowResize: true,
18709
18710		windowResizeDelay: 200 // milliseconds before an updateSize happens
18711
18712
18713
18714	};
18715
18716
18717
18718
18719
18720	Calendar.englishDefaults = { // used by lang.js
18721
18722		dayPopoverFormat: 'dddd, MMMM D'
18723
18724	};
18725
18726
18727
18728
18729
18730	Calendar.rtlDefaults = { // right-to-left defaults
18731
18732		header: { // TODO: smarter solution (first/center/last ?)
18733
18734			left: 'next,prev today',
18735
18736			center: '',
18737
18738			right: 'title'
18739
18740		},
18741
18742		buttonIcons: {
18743
18744			prev: 'right-single-arrow',
18745
18746			next: 'left-single-arrow',
18747
18748			prevYear: 'right-double-arrow',
18749
18750			nextYear: 'left-double-arrow'
18751
18752		},
18753
18754		themeButtonIcons: {
18755
18756			prev: 'circle-triangle-e',
18757
18758			next: 'circle-triangle-w',
18759
18760			nextYear: 'seek-prev',
18761
18762			prevYear: 'seek-next'
18763
18764		}
18765
18766	};
18767
18768
18769
18770	;;
18771
18772
18773
18774	var langOptionHash = FC.langs = {}; // initialize and expose
18775
18776
18777
18778
18779
18780// TODO: document the structure and ordering of a FullCalendar lang file
18781
18782// TODO: rename everything "lang" to "locale", like what the moment project did
18783
18784
18785
18786
18787
18788// Initialize jQuery UI datepicker translations while using some of the translations
18789
18790// Will set this as the default language for datepicker.
18791
18792	FC.datepickerLang = function(langCode, dpLangCode, dpOptions) {
18793
18794
18795
18796		// get the FullCalendar internal option hash for this language. create if necessary
18797
18798		var fcOptions = langOptionHash[langCode] || (langOptionHash[langCode] = {});
18799
18800
18801
18802		// transfer some simple options from datepicker to fc
18803
18804		fcOptions.isRTL = dpOptions.isRTL;
18805
18806		fcOptions.weekNumberTitle = dpOptions.weekHeader;
18807
18808
18809
18810		// compute some more complex options from datepicker
18811
18812		$.each(dpComputableOptions, function(name, func) {
18813
18814			fcOptions[name] = func(dpOptions);
18815
18816		});
18817
18818
18819
18820		// is jQuery UI Datepicker is on the page?
18821
18822		if ($.datepicker) {
18823
18824
18825
18826			// Register the language data.
18827
18828			// FullCalendar and MomentJS use language codes like "pt-br" but Datepicker
18829
18830			// does it like "pt-BR" or if it doesn't have the language, maybe just "pt".
18831
18832			// Make an alias so the language can be referenced either way.
18833
18834			$.datepicker.regional[dpLangCode] =
18835
18836				$.datepicker.regional[langCode] = // alias
18837
18838					dpOptions;
18839
18840
18841
18842			// Alias 'en' to the default language data. Do this every time.
18843
18844			$.datepicker.regional.en = $.datepicker.regional[''];
18845
18846
18847
18848			// Set as Datepicker's global defaults.
18849
18850			$.datepicker.setDefaults(dpOptions);
18851
18852		}
18853
18854	};
18855
18856
18857
18858
18859
18860// Sets FullCalendar-specific translations. Will set the language as the global default.
18861
18862	FC.lang = function(langCode, newFcOptions) {
18863
18864		var fcOptions;
18865
18866		var momOptions;
18867
18868
18869
18870		// get the FullCalendar internal option hash for this language. create if necessary
18871
18872		fcOptions = langOptionHash[langCode] || (langOptionHash[langCode] = {});
18873
18874
18875
18876		// provided new options for this language? merge them in
18877
18878		if (newFcOptions) {
18879
18880			fcOptions = langOptionHash[langCode] = mergeOptions([ fcOptions, newFcOptions ]);
18881
18882		}
18883
18884
18885
18886		// compute language options that weren't defined.
18887
18888		// always do this. newFcOptions can be undefined when initializing from i18n file,
18889
18890		// so no way to tell if this is an initialization or a default-setting.
18891
18892		momOptions = getMomentLocaleData(langCode); // will fall back to en
18893
18894		$.each(momComputableOptions, function(name, func) {
18895
18896			if (fcOptions[name] == null) {
18897
18898				fcOptions[name] = func(momOptions, fcOptions);
18899
18900			}
18901
18902		});
18903
18904
18905
18906		// set it as the default language for FullCalendar
18907
18908		Calendar.defaults.lang = langCode;
18909
18910	};
18911
18912
18913
18914
18915
18916// NOTE: can't guarantee any of these computations will run because not every language has datepicker
18917
18918// configs, so make sure there are English fallbacks for these in the defaults file.
18919
18920	var dpComputableOptions = {
18921
18922
18923
18924		buttonText: function(dpOptions) {
18925
18926			return {
18927
18928				// the translations sometimes wrongly contain HTML entities
18929
18930				prev: stripHtmlEntities(dpOptions.prevText),
18931
18932				next: stripHtmlEntities(dpOptions.nextText),
18933
18934				today: stripHtmlEntities(dpOptions.currentText)
18935
18936			};
18937
18938		},
18939
18940
18941
18942		// Produces format strings like "MMMM YYYY" -> "September 2014"
18943
18944		monthYearFormat: function(dpOptions) {
18945
18946			return dpOptions.showMonthAfterYear ?
18947
18948			'YYYY[' + dpOptions.yearSuffix + '] MMMM' :
18949
18950			'MMMM YYYY[' + dpOptions.yearSuffix + ']';
18951
18952		}
18953
18954
18955
18956	};
18957
18958
18959
18960	var momComputableOptions = {
18961
18962
18963
18964		// Produces format strings like "ddd M/D" -> "Fri 9/15"
18965
18966		dayOfMonthFormat: function(momOptions, fcOptions) {
18967
18968			var format = momOptions.longDateFormat('l'); // for the format like "M/D/YYYY"
18969
18970
18971
18972			// strip the year off the edge, as well as other misc non-whitespace chars
18973
18974			format = format.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g, '');
18975
18976
18977
18978			if (fcOptions.isRTL) {
18979
18980				format += ' ddd'; // for RTL, add day-of-week to end
18981
18982			}
18983
18984			else {
18985
18986				format = 'ddd ' + format; // for LTR, add day-of-week to beginning
18987
18988			}
18989
18990			return format;
18991
18992		},
18993
18994
18995
18996		// Produces format strings like "h:mma" -> "6:00pm"
18997
18998		mediumTimeFormat: function(momOptions) { // can't be called `timeFormat` because collides with option
18999
19000			return momOptions.longDateFormat('LT')
19001
19002				.replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
19003
19004		},
19005
19006
19007
19008		// Produces format strings like "h(:mm)a" -> "6pm" / "6:30pm"
19009
19010		smallTimeFormat: function(momOptions) {
19011
19012			return momOptions.longDateFormat('LT')
19013
19014				.replace(':mm', '(:mm)')
19015
19016				.replace(/(\Wmm)$/, '($1)') // like above, but for foreign langs
19017
19018				.replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
19019
19020		},
19021
19022
19023
19024		// Produces format strings like "h(:mm)t" -> "6p" / "6:30p"
19025
19026		extraSmallTimeFormat: function(momOptions) {
19027
19028			return momOptions.longDateFormat('LT')
19029
19030				.replace(':mm', '(:mm)')
19031
19032				.replace(/(\Wmm)$/, '($1)') // like above, but for foreign langs
19033
19034				.replace(/\s*a$/i, 't'); // convert to AM/PM/am/pm to lowercase one-letter. remove any spaces beforehand
19035
19036		},
19037
19038
19039
19040		// Produces format strings like "ha" / "H" -> "6pm" / "18"
19041
19042		hourFormat: function(momOptions) {
19043
19044			return momOptions.longDateFormat('LT')
19045
19046				.replace(':mm', '')
19047
19048				.replace(/(\Wmm)$/, '') // like above, but for foreign langs
19049
19050				.replace(/\s*a$/i, 'a'); // convert AM/PM/am/pm to lowercase. remove any spaces beforehand
19051
19052		},
19053
19054
19055
19056		// Produces format strings like "h:mm" -> "6:30" (with no AM/PM)
19057
19058		noMeridiemTimeFormat: function(momOptions) {
19059
19060			return momOptions.longDateFormat('LT')
19061
19062				.replace(/\s*a$/i, ''); // remove trailing AM/PM
19063
19064		}
19065
19066
19067
19068	};
19069
19070
19071
19072
19073
19074// options that should be computed off live calendar options (considers override options)
19075
19076// TODO: best place for this? related to lang?
19077
19078// TODO: flipping text based on isRTL is a bad idea because the CSS `direction` might want to handle it
19079
19080	var instanceComputableOptions = {
19081
19082
19083
19084		// Produces format strings for results like "Mo 16"
19085
19086		smallDayDateFormat: function(options) {
19087
19088			return options.isRTL ?
19089
19090				'D dd' :
19091
19092				'dd D';
19093
19094		},
19095
19096
19097
19098		// Produces format strings for results like "Wk 5"
19099
19100		weekFormat: function(options) {
19101
19102			return options.isRTL ?
19103
19104			'w[ ' + options.weekNumberTitle + ']' :
19105
19106			'[' + options.weekNumberTitle + ' ]w';
19107
19108		},
19109
19110
19111
19112		// Produces format strings for results like "Wk5"
19113
19114		smallWeekFormat: function(options) {
19115
19116			return options.isRTL ?
19117
19118			'w[' + options.weekNumberTitle + ']' :
19119
19120			'[' + options.weekNumberTitle + ']w';
19121
19122		}
19123
19124
19125
19126	};
19127
19128
19129
19130	function populateInstanceComputableOptions(options) {
19131
19132		$.each(instanceComputableOptions, function(name, func) {
19133
19134			if (options[name] == null) {
19135
19136				options[name] = func(options);
19137
19138			}
19139
19140		});
19141
19142	}
19143
19144
19145
19146
19147
19148// Returns moment's internal locale data. If doesn't exist, returns English.
19149
19150// Works with moment-pre-2.8
19151
19152	function getMomentLocaleData(langCode) {
19153
19154		var func = moment.localeData || moment.langData;
19155
19156		return func.call(moment, langCode) ||
19157
19158			func.call(moment, 'en'); // the newer localData could return null, so fall back to en
19159
19160	}
19161
19162
19163
19164
19165
19166// Initialize English by forcing computation of moment-derived options.
19167
19168// Also, sets it as the default.
19169
19170	FC.lang('en', Calendar.englishDefaults);
19171
19172
19173
19174	;;
19175
19176
19177
19178	/* Top toolbar area with buttons and title
19179
19180	 ----------------------------------------------------------------------------------------------------------------------*/
19181
19182// TODO: rename all header-related things to "toolbar"
19183
19184
19185
19186	function Header(calendar, options) {
19187
19188		var t = this;
19189
19190
19191
19192		// exports
19193
19194		t.render = render;
19195
19196		t.removeElement = removeElement;
19197
19198		t.updateTitle = updateTitle;
19199
19200		t.activateButton = activateButton;
19201
19202		t.deactivateButton = deactivateButton;
19203
19204		t.disableButton = disableButton;
19205
19206		t.enableButton = enableButton;
19207
19208		t.getViewsWithButtons = getViewsWithButtons;
19209
19210
19211
19212		// locals
19213
19214		var el = $();
19215
19216		var viewsWithButtons = [];
19217
19218		var tm;
19219
19220
19221
19222
19223
19224		function render() {
19225
19226			var sections = options.header;
19227
19228
19229
19230			tm = options.theme ? 'ui' : 'fc';
19231
19232
19233
19234			if (sections) {
19235
19236				el = $("<div class='fc-toolbar'/>")
19237
19238					.append(renderSection('left'))
19239
19240					.append(renderSection('right'))
19241
19242					.append(renderSection('center'))
19243
19244					.append('<div class="fc-clear"/>');
19245
19246
19247
19248				return el;
19249
19250			}
19251
19252		}
19253
19254
19255
19256
19257
19258		function removeElement() {
19259
19260			el.remove();
19261
19262			el = $();
19263
19264		}
19265
19266
19267
19268
19269
19270		function renderSection(position) {
19271
19272			var sectionEl = $('<div class="fc-' + position + '"/>');
19273
19274			var buttonStr = options.header[position];
19275
19276
19277
19278			if (buttonStr) {
19279
19280				$.each(buttonStr.split(' '), function(i) {
19281
19282					var groupChildren = $();
19283
19284					var isOnlyButtons = true;
19285
19286					var groupEl;
19287
19288
19289
19290					$.each(this.split(','), function(j, buttonName) {
19291
19292						var customButtonProps;
19293
19294						var viewSpec;
19295
19296						var buttonClick;
19297
19298						var overrideText; // text explicitly set by calendar's constructor options. overcomes icons
19299
19300						var defaultText;
19301
19302						var themeIcon;
19303
19304						var normalIcon;
19305
19306						var innerHtml;
19307
19308						var classes;
19309
19310						var button; // the element
19311
19312
19313
19314						if (buttonName == 'title') {
19315
19316							groupChildren = groupChildren.add($('<h2>&nbsp;</h2>')); // we always want it to take up height
19317
19318							isOnlyButtons = false;
19319
19320						}
19321
19322						else {
19323
19324							if ((customButtonProps = (calendar.options.customButtons || {})[buttonName])) {
19325
19326								buttonClick = function(ev) {
19327
19328									if (customButtonProps.click) {
19329
19330										customButtonProps.click.call(button[0], ev);
19331
19332									}
19333
19334								};
19335
19336								overrideText = ''; // icons will override text
19337
19338								defaultText = customButtonProps.text;
19339
19340							}
19341
19342							else if ((viewSpec = calendar.getViewSpec(buttonName))) {
19343
19344								buttonClick = function() {
19345
19346									calendar.changeView(buttonName);
19347
19348								};
19349
19350								viewsWithButtons.push(buttonName);
19351
19352								overrideText = viewSpec.buttonTextOverride;
19353
19354								defaultText = viewSpec.buttonTextDefault;
19355
19356							}
19357
19358							else if (calendar[buttonName]) { // a calendar method
19359
19360								buttonClick = function() {
19361
19362									calendar[buttonName]();
19363
19364								};
19365
19366								overrideText = (calendar.overrides.buttonText || {})[buttonName];
19367
19368								defaultText = options.buttonText[buttonName]; // everything else is considered default
19369
19370							}
19371
19372
19373
19374							if (buttonClick) {
19375
19376
19377
19378								themeIcon =
19379
19380									customButtonProps ?
19381
19382										customButtonProps.themeIcon :
19383
19384										options.themeButtonIcons[buttonName];
19385
19386
19387
19388								normalIcon =
19389
19390									customButtonProps ?
19391
19392										customButtonProps.icon :
19393
19394										options.buttonIcons[buttonName];
19395
19396
19397
19398								if (overrideText) {
19399
19400									innerHtml = htmlEscape(overrideText);
19401
19402								}
19403
19404								else if (themeIcon && options.theme) {
19405
19406									innerHtml = "<span class='ui-icon ui-icon-" + themeIcon + "'></span>";
19407
19408								}
19409
19410								else if (normalIcon && !options.theme) {
19411
19412									innerHtml = "<span class='fc-icon fc-icon-" + normalIcon + "'></span>";
19413
19414								}
19415
19416								else {
19417
19418									innerHtml = htmlEscape(defaultText);
19419
19420								}
19421
19422
19423
19424								classes = [
19425
19426									'fc-' + buttonName + '-button',
19427
19428									tm + '-button',
19429
19430									tm + '-state-default'
19431
19432								];
19433
19434
19435
19436								button = $( // type="button" so that it doesn't submit a form
19437
19438									'<button type="button" class="' + classes.join(' ') + '">' +
19439
19440									innerHtml +
19441
19442									'</button>'
19443
19444								)
19445
19446									.click(function(ev) {
19447
19448										// don't process clicks for disabled buttons
19449
19450										if (!button.hasClass(tm + '-state-disabled')) {
19451
19452
19453
19454											buttonClick(ev);
19455
19456
19457
19458											// after the click action, if the button becomes the "active" tab, or disabled,
19459
19460											// it should never have a hover class, so remove it now.
19461
19462											if (
19463
19464												button.hasClass(tm + '-state-active') ||
19465
19466												button.hasClass(tm + '-state-disabled')
19467
19468											) {
19469
19470												button.removeClass(tm + '-state-hover');
19471
19472											}
19473
19474										}
19475
19476									})
19477
19478									.mousedown(function() {
19479
19480										// the *down* effect (mouse pressed in).
19481
19482										// only on buttons that are not the "active" tab, or disabled
19483
19484										button
19485
19486											.not('.' + tm + '-state-active')
19487
19488											.not('.' + tm + '-state-disabled')
19489
19490											.addClass(tm + '-state-down');
19491
19492									})
19493
19494									.mouseup(function() {
19495
19496										// undo the *down* effect
19497
19498										button.removeClass(tm + '-state-down');
19499
19500									})
19501
19502									.hover(
19503
19504										function() {
19505
19506											// the *hover* effect.
19507
19508											// only on buttons that are not the "active" tab, or disabled
19509
19510											button
19511
19512												.not('.' + tm + '-state-active')
19513
19514												.not('.' + tm + '-state-disabled')
19515
19516												.addClass(tm + '-state-hover');
19517
19518										},
19519
19520										function() {
19521
19522											// undo the *hover* effect
19523
19524											button
19525
19526												.removeClass(tm + '-state-hover')
19527
19528												.removeClass(tm + '-state-down'); // if mouseleave happens before mouseup
19529
19530										}
19531
19532									);
19533
19534
19535
19536								groupChildren = groupChildren.add(button);
19537
19538							}
19539
19540						}
19541
19542					});
19543
19544
19545
19546					if (isOnlyButtons) {
19547
19548						groupChildren
19549
19550							.first().addClass(tm + '-corner-left').end()
19551
19552							.last().addClass(tm + '-corner-right').end();
19553
19554					}
19555
19556
19557
19558					if (groupChildren.length > 1) {
19559
19560						groupEl = $('<div/>');
19561
19562						if (isOnlyButtons) {
19563
19564							groupEl.addClass('fc-button-group');
19565
19566						}
19567
19568						groupEl.append(groupChildren);
19569
19570						sectionEl.append(groupEl);
19571
19572					}
19573
19574					else {
19575
19576						sectionEl.append(groupChildren); // 1 or 0 children
19577
19578					}
19579
19580				});
19581
19582			}
19583
19584
19585
19586			return sectionEl;
19587
19588		}
19589
19590
19591
19592
19593
19594		function updateTitle(text) {
19595
19596			el.find('h2').text(text);
19597
19598		}
19599
19600
19601
19602
19603
19604		function activateButton(buttonName) {
19605
19606			el.find('.fc-' + buttonName + '-button')
19607
19608				.addClass(tm + '-state-active');
19609
19610		}
19611
19612
19613
19614
19615
19616		function deactivateButton(buttonName) {
19617
19618			el.find('.fc-' + buttonName + '-button')
19619
19620				.removeClass(tm + '-state-active');
19621
19622		}
19623
19624
19625
19626
19627
19628		function disableButton(buttonName) {
19629
19630			el.find('.fc-' + buttonName + '-button')
19631
19632				.attr('disabled', 'disabled')
19633
19634				.addClass(tm + '-state-disabled');
19635
19636		}
19637
19638
19639
19640
19641
19642		function enableButton(buttonName) {
19643
19644			el.find('.fc-' + buttonName + '-button')
19645
19646				.removeAttr('disabled')
19647
19648				.removeClass(tm + '-state-disabled');
19649
19650		}
19651
19652
19653
19654
19655
19656		function getViewsWithButtons() {
19657
19658			return viewsWithButtons;
19659
19660		}
19661
19662
19663
19664	}
19665
19666
19667
19668	;;
19669
19670
19671
19672	FC.sourceNormalizers = [];
19673
19674	FC.sourceFetchers = [];
19675
19676
19677
19678	var ajaxDefaults = {
19679
19680		dataType: 'json',
19681
19682		cache: false
19683
19684	};
19685
19686
19687
19688	var eventGUID = 1;
19689
19690
19691
19692
19693
19694	function EventManager(options) { // assumed to be a calendar
19695
19696		var t = this;
19697
19698
19699
19700
19701
19702		// exports
19703
19704		t.isFetchNeeded = isFetchNeeded;
19705
19706		t.fetchEvents = fetchEvents;
19707
19708		t.addEventSource = addEventSource;
19709
19710		t.removeEventSource = removeEventSource;
19711
19712		t.updateEvent = updateEvent;
19713
19714		t.renderEvent = renderEvent;
19715
19716		t.removeEvents = removeEvents;
19717
19718		t.clientEvents = clientEvents;
19719
19720		t.mutateEvent = mutateEvent;
19721
19722		t.normalizeEventDates = normalizeEventDates;
19723
19724		t.normalizeEventTimes = normalizeEventTimes;
19725
19726
19727
19728
19729
19730		// imports
19731
19732		var reportEvents = t.reportEvents;
19733
19734
19735
19736
19737
19738		// locals
19739
19740		var stickySource = { events: [] };
19741
19742		var sources = [ stickySource ];
19743
19744		var rangeStart, rangeEnd;
19745
19746		var currentFetchID = 0;
19747
19748		var pendingSourceCnt = 0;
19749
19750		var cache = []; // holds events that have already been expanded
19751
19752
19753
19754
19755
19756		$.each(
19757
19758			(options.events ? [ options.events ] : []).concat(options.eventSources || []),
19759
19760			function(i, sourceInput) {
19761
19762				var source = buildEventSource(sourceInput);
19763
19764				if (source) {
19765
19766					sources.push(source);
19767
19768				}
19769
19770			}
19771
19772		);
19773
19774
19775
19776
19777
19778
19779
19780		/* Fetching
19781
19782		 -----------------------------------------------------------------------------*/
19783
19784
19785
19786
19787
19788		// start and end are assumed to be unzoned
19789
19790		function isFetchNeeded(start, end) {
19791
19792			return !rangeStart || // nothing has been fetched yet?
19793
19794				start < rangeStart || end > rangeEnd; // is part of the new range outside of the old range?
19795
19796		}
19797
19798
19799
19800
19801
19802		function fetchEvents(start, end) {
19803
19804			rangeStart = start;
19805
19806			rangeEnd = end;
19807
19808			cache = [];
19809
19810			var fetchID = ++currentFetchID;
19811
19812			var len = sources.length;
19813
19814			pendingSourceCnt = len;
19815
19816			for (var i=0; i<len; i++) {
19817
19818				fetchEventSource(sources[i], fetchID);
19819
19820			}
19821
19822		}
19823
19824
19825
19826
19827
19828		function fetchEventSource(source, fetchID) {
19829
19830			_fetchEventSource(source, function(eventInputs) {
19831
19832				var isArraySource = $.isArray(source.events);
19833
19834				var i, eventInput;
19835
19836				var abstractEvent;
19837
19838
19839
19840				if (fetchID == currentFetchID) {
19841
19842
19843
19844					if (eventInputs) {
19845
19846						for (i = 0; i < eventInputs.length; i++) {
19847
19848							eventInput = eventInputs[i];
19849
19850
19851
19852							if (isArraySource) { // array sources have already been convert to Event Objects
19853
19854								abstractEvent = eventInput;
19855
19856							}
19857
19858							else {
19859
19860								abstractEvent = buildEventFromInput(eventInput, source);
19861
19862							}
19863
19864
19865
19866							if (abstractEvent) { // not false (an invalid event)
19867
19868								cache.push.apply(
19869
19870									cache,
19871
19872									expandEvent(abstractEvent) // add individual expanded events to the cache
19873
19874								);
19875
19876							}
19877
19878						}
19879
19880					}
19881
19882
19883
19884					pendingSourceCnt--;
19885
19886					if (!pendingSourceCnt) {
19887
19888						reportEvents(cache);
19889
19890					}
19891
19892				}
19893
19894			});
19895
19896		}
19897
19898
19899
19900
19901
19902		function _fetchEventSource(source, callback) {
19903
19904			var i;
19905
19906			var fetchers = FC.sourceFetchers;
19907
19908			var res;
19909
19910
19911
19912			for (i=0; i<fetchers.length; i++) {
19913
19914				res = fetchers[i].call(
19915
19916					t, // this, the Calendar object
19917
19918					source,
19919
19920					rangeStart.clone(),
19921
19922					rangeEnd.clone(),
19923
19924					options.timezone,
19925
19926					callback
19927
19928				);
19929
19930
19931
19932				if (res === true) {
19933
19934					// the fetcher is in charge. made its own async request
19935
19936					return;
19937
19938				}
19939
19940				else if (typeof res == 'object') {
19941
19942					// the fetcher returned a new source. process it
19943
19944					_fetchEventSource(res, callback);
19945
19946					return;
19947
19948				}
19949
19950			}
19951
19952
19953
19954			var events = source.events;
19955
19956			if (events) {
19957
19958				if ($.isFunction(events)) {
19959
19960					t.pushLoading();
19961
19962					events.call(
19963
19964						t, // this, the Calendar object
19965
19966						rangeStart.clone(),
19967
19968						rangeEnd.clone(),
19969
19970						options.timezone,
19971
19972						function(events) {
19973
19974							callback(events);
19975
19976							t.popLoading();
19977
19978						}
19979
19980					);
19981
19982				}
19983
19984				else if ($.isArray(events)) {
19985
19986					callback(events);
19987
19988				}
19989
19990				else {
19991
19992					callback();
19993
19994				}
19995
19996			}else{
19997
19998				var url = source.url;
19999
20000				if (url) {
20001
20002					var success = source.success;
20003
20004					var error = source.error;
20005
20006					var complete = source.complete;
20007
20008
20009
20010					// retrieve any outbound GET/POST $.ajax data from the options
20011
20012					var customData;
20013
20014					if ($.isFunction(source.data)) {
20015
20016						// supplied as a function that returns a key/value object
20017
20018						customData = source.data();
20019
20020					}
20021
20022					else {
20023
20024						// supplied as a straight key/value object
20025
20026						customData = source.data;
20027
20028					}
20029
20030
20031
20032					// use a copy of the custom data so we can modify the parameters
20033
20034					// and not affect the passed-in object.
20035
20036					var data = $.extend({}, customData || {});
20037
20038
20039
20040					var startParam = firstDefined(source.startParam, options.startParam);
20041
20042					var endParam = firstDefined(source.endParam, options.endParam);
20043
20044					var timezoneParam = firstDefined(source.timezoneParam, options.timezoneParam);
20045
20046
20047
20048					if (startParam) {
20049
20050						data[startParam] = rangeStart.format();
20051
20052					}
20053
20054					if (endParam) {
20055
20056						data[endParam] = rangeEnd.format();
20057
20058					}
20059
20060					if (options.timezone && options.timezone != 'local') {
20061
20062						data[timezoneParam] = options.timezone;
20063
20064					}
20065
20066
20067
20068					t.pushLoading();
20069
20070					$.ajax($.extend({}, ajaxDefaults, source, {
20071
20072						data: data,
20073
20074						success: function(events) {
20075
20076							events = events || [];
20077
20078							var res = applyAll(success, this, arguments);
20079
20080							if ($.isArray(res)) {
20081
20082								events = res;
20083
20084							}
20085
20086							callback(events);
20087
20088						},
20089
20090						error: function() {
20091
20092							applyAll(error, this, arguments);
20093
20094							callback();
20095
20096						},
20097
20098						complete: function() {
20099
20100							applyAll(complete, this, arguments);
20101
20102							t.popLoading();
20103
20104						}
20105
20106					}));
20107
20108				}else{
20109
20110					callback();
20111
20112				}
20113
20114			}
20115
20116		}
20117
20118
20119
20120
20121
20122
20123
20124		/* Sources
20125
20126		 -----------------------------------------------------------------------------*/
20127
20128
20129
20130
20131
20132		function addEventSource(sourceInput) {
20133
20134			var source = buildEventSource(sourceInput);
20135
20136			if (source) {
20137
20138				sources.push(source);
20139
20140				pendingSourceCnt++;
20141
20142				fetchEventSource(source, currentFetchID); // will eventually call reportEvents
20143
20144			}
20145
20146		}
20147
20148
20149
20150
20151
20152		function buildEventSource(sourceInput) { // will return undefined if invalid source
20153
20154			var normalizers = FC.sourceNormalizers;
20155
20156			var source;
20157
20158			var i;
20159
20160
20161
20162			if ($.isFunction(sourceInput) || $.isArray(sourceInput)) {
20163
20164				source = { events: sourceInput };
20165
20166			}
20167
20168			else if (typeof sourceInput === 'string') {
20169
20170				source = { url: sourceInput };
20171
20172			}
20173
20174			else if (typeof sourceInput === 'object') {
20175
20176				source = $.extend({}, sourceInput); // shallow copy
20177
20178			}
20179
20180
20181
20182			if (source) {
20183
20184
20185
20186				// TODO: repeat code, same code for event classNames
20187
20188				if (source.className) {
20189
20190					if (typeof source.className === 'string') {
20191
20192						source.className = source.className.split(/\s+/);
20193
20194					}
20195
20196					// otherwise, assumed to be an array
20197
20198				}
20199
20200				else {
20201
20202					source.className = [];
20203
20204				}
20205
20206
20207
20208				// for array sources, we convert to standard Event Objects up front
20209
20210				if ($.isArray(source.events)) {
20211
20212					source.origArray = source.events; // for removeEventSource
20213
20214					source.events = $.map(source.events, function(eventInput) {
20215
20216						return buildEventFromInput(eventInput, source);
20217
20218					});
20219
20220				}
20221
20222
20223
20224				for (i=0; i<normalizers.length; i++) {
20225
20226					normalizers[i].call(t, source);
20227
20228				}
20229
20230
20231
20232				return source;
20233
20234			}
20235
20236		}
20237
20238
20239
20240
20241
20242		function removeEventSource(source) {
20243
20244			sources = $.grep(sources, function(src) {
20245
20246				return !isSourcesEqual(src, source);
20247
20248			});
20249
20250			// remove all client events from that source
20251
20252			cache = $.grep(cache, function(e) {
20253
20254				return !isSourcesEqual(e.source, source);
20255
20256			});
20257
20258			reportEvents(cache);
20259
20260		}
20261
20262
20263
20264
20265
20266		function isSourcesEqual(source1, source2) {
20267
20268			return source1 && source2 && getSourcePrimitive(source1) == getSourcePrimitive(source2);
20269
20270		}
20271
20272
20273
20274
20275
20276		function getSourcePrimitive(source) {
20277
20278			return (
20279
20280					(typeof source === 'object') ? // a normalized event source?
20281
20282						(source.origArray || source.googleCalendarId || source.url || source.events) : // get the primitive
20283
20284						null
20285
20286				) ||
20287
20288				source; // the given argument *is* the primitive
20289
20290		}
20291
20292
20293
20294
20295
20296
20297
20298		/* Manipulation
20299
20300		 -----------------------------------------------------------------------------*/
20301
20302
20303
20304
20305
20306		// Only ever called from the externally-facing API
20307
20308		function updateEvent(event) {
20309
20310
20311
20312			// massage start/end values, even if date string values
20313
20314			event.start = t.moment(event.start);
20315
20316			if (event.end) {
20317
20318				event.end = t.moment(event.end);
20319
20320			}
20321
20322			else {
20323
20324				event.end = null;
20325
20326			}
20327
20328
20329
20330			mutateEvent(event, getMiscEventProps(event)); // will handle start/end/allDay normalization
20331
20332			reportEvents(cache); // reports event modifications (so we can redraw)
20333
20334		}
20335
20336
20337
20338
20339
20340		// Returns a hash of misc event properties that should be copied over to related events.
20341
20342		function getMiscEventProps(event) {
20343
20344			var props = {};
20345
20346
20347
20348			$.each(event, function(name, val) {
20349
20350				if (isMiscEventPropName(name)) {
20351
20352					if (val !== undefined && isAtomic(val)) { // a defined non-object
20353
20354						props[name] = val;
20355
20356					}
20357
20358				}
20359
20360			});
20361
20362
20363
20364			return props;
20365
20366		}
20367
20368
20369
20370		// non-date-related, non-id-related, non-secret
20371
20372		function isMiscEventPropName(name) {
20373
20374			return !/^_|^(id|allDay|start|end)$/.test(name);
20375
20376		}
20377
20378
20379
20380
20381
20382		// returns the expanded events that were created
20383
20384		function renderEvent(eventInput, stick) {
20385
20386			var abstractEvent = buildEventFromInput(eventInput);
20387
20388			var events;
20389
20390			var i, event;
20391
20392
20393
20394			if (abstractEvent) { // not false (a valid input)
20395
20396				events = expandEvent(abstractEvent);
20397
20398
20399
20400				for (i = 0; i < events.length; i++) {
20401
20402					event = events[i];
20403
20404
20405
20406					if (!event.source) {
20407
20408						if (stick) {
20409
20410							stickySource.events.push(event);
20411
20412							event.source = stickySource;
20413
20414						}
20415
20416						cache.push(event);
20417
20418					}
20419
20420				}
20421
20422
20423
20424				reportEvents(cache);
20425
20426
20427
20428				return events;
20429
20430			}
20431
20432
20433
20434			return [];
20435
20436		}
20437
20438
20439
20440
20441
20442		function removeEvents(filter) {
20443
20444			var eventID;
20445
20446			var i;
20447
20448
20449
20450			if (filter == null) { // null or undefined. remove all events
20451
20452				filter = function() { return true; }; // will always match
20453
20454			}
20455
20456			else if (!$.isFunction(filter)) { // an event ID
20457
20458				eventID = filter + '';
20459
20460				filter = function(event) {
20461
20462					return event._id == eventID;
20463
20464				};
20465
20466			}
20467
20468
20469
20470			// Purge event(s) from our local cache
20471
20472			cache = $.grep(cache, filter, true); // inverse=true
20473
20474
20475
20476			// Remove events from array sources.
20477
20478			// This works because they have been converted to official Event Objects up front.
20479
20480			// (and as a result, event._id has been calculated).
20481
20482			for (i=0; i<sources.length; i++) {
20483
20484				if ($.isArray(sources[i].events)) {
20485
20486					sources[i].events = $.grep(sources[i].events, filter, true);
20487
20488				}
20489
20490			}
20491
20492
20493
20494			reportEvents(cache);
20495
20496		}
20497
20498
20499
20500
20501
20502		function clientEvents(filter) {
20503
20504			if ($.isFunction(filter)) {
20505
20506				return $.grep(cache, filter);
20507
20508			}
20509
20510			else if (filter != null) { // not null, not undefined. an event ID
20511
20512				filter += '';
20513
20514				return $.grep(cache, function(e) {
20515
20516					return e._id == filter;
20517
20518				});
20519
20520			}
20521
20522			return cache; // else, return all
20523
20524		}
20525
20526
20527
20528
20529
20530
20531
20532		/* Event Normalization
20533
20534		 -----------------------------------------------------------------------------*/
20535
20536
20537
20538
20539
20540		// Given a raw object with key/value properties, returns an "abstract" Event object.
20541
20542		// An "abstract" event is an event that, if recurring, will not have been expanded yet.
20543
20544		// Will return `false` when input is invalid.
20545
20546		// `source` is optional
20547
20548		function buildEventFromInput(input, source) {
20549
20550			var out = {};
20551
20552			var start, end;
20553
20554			var allDay;
20555
20556
20557
20558			if (options.eventDataTransform) {
20559
20560				input = options.eventDataTransform(input);
20561
20562			}
20563
20564			if (source && source.eventDataTransform) {
20565
20566				input = source.eventDataTransform(input);
20567
20568			}
20569
20570
20571
20572			// Copy all properties over to the resulting object.
20573
20574			// The special-case properties will be copied over afterwards.
20575
20576			$.extend(out, input);
20577
20578
20579
20580			if (source) {
20581
20582				out.source = source;
20583
20584			}
20585
20586
20587
20588			out._id = input._id || (input.id === undefined ? '_fc' + eventGUID++ : input.id + '');
20589
20590
20591
20592			if (input.className) {
20593
20594				if (typeof input.className == 'string') {
20595
20596					out.className = input.className.split(/\s+/);
20597
20598				}
20599
20600				else { // assumed to be an array
20601
20602					out.className = input.className;
20603
20604				}
20605
20606			}
20607
20608			else {
20609
20610				out.className = [];
20611
20612			}
20613
20614
20615
20616			start = input.start || input.date; // "date" is an alias for "start"
20617
20618			end = input.end;
20619
20620
20621
20622			// parse as a time (Duration) if applicable
20623
20624			if (isTimeString(start)) {
20625
20626				start = moment.duration(start);
20627
20628			}
20629
20630			if (isTimeString(end)) {
20631
20632				end = moment.duration(end);
20633
20634			}
20635
20636
20637
20638			if (input.dow || moment.isDuration(start) || moment.isDuration(end)) {
20639
20640
20641
20642				// the event is "abstract" (recurring) so don't calculate exact start/end dates just yet
20643
20644				out.start = start ? moment.duration(start) : null; // will be a Duration or null
20645
20646				out.end = end ? moment.duration(end) : null; // will be a Duration or null
20647
20648				out._recurring = true; // our internal marker
20649
20650			}
20651
20652			else {
20653
20654
20655
20656				if (start) {
20657
20658					start = t.moment(start);
20659
20660					if (!start.isValid()) {
20661
20662						return false;
20663
20664					}
20665
20666				}
20667
20668
20669
20670				if (end) {
20671
20672					end = t.moment(end);
20673
20674					if (!end.isValid()) {
20675
20676						end = null; // let defaults take over
20677
20678					}
20679
20680				}
20681
20682
20683
20684				allDay = input.allDay;
20685
20686				if (allDay === undefined) { // still undefined? fallback to default
20687
20688					allDay = firstDefined(
20689
20690						source ? source.allDayDefault : undefined,
20691
20692						options.allDayDefault
20693
20694					);
20695
20696					// still undefined? normalizeEventDates will calculate it
20697
20698				}
20699
20700
20701
20702				assignDatesToEvent(start, end, allDay, out);
20703
20704			}
20705
20706
20707
20708			return out;
20709
20710		}
20711
20712
20713
20714
20715
20716		// Normalizes and assigns the given dates to the given partially-formed event object.
20717
20718		// NOTE: mutates the given start/end moments. does not make a copy.
20719
20720		function assignDatesToEvent(start, end, allDay, event) {
20721
20722			event.start = start;
20723
20724			event.end = end;
20725
20726			event.allDay = allDay;
20727
20728			normalizeEventDates(event);
20729
20730			backupEventDates(event);
20731
20732		}
20733
20734
20735
20736
20737
20738		// Ensures proper values for allDay/start/end. Accepts an Event object, or a plain object with event-ish properties.
20739
20740		// NOTE: Will modify the given object.
20741
20742		function normalizeEventDates(eventProps) {
20743
20744
20745
20746			normalizeEventTimes(eventProps);
20747
20748
20749
20750			if (eventProps.end && !eventProps.end.isAfter(eventProps.start)) {
20751
20752				eventProps.end = null;
20753
20754			}
20755
20756
20757
20758			if (!eventProps.end) {
20759
20760				if (options.forceEventDuration) {
20761
20762					eventProps.end = t.getDefaultEventEnd(eventProps.allDay, eventProps.start);
20763
20764				}
20765
20766				else {
20767
20768					eventProps.end = null;
20769
20770				}
20771
20772			}
20773
20774		}
20775
20776
20777
20778
20779
20780		// Ensures the allDay property exists and the timeliness of the start/end dates are consistent
20781
20782		function normalizeEventTimes(eventProps) {
20783
20784			if (eventProps.allDay == null) {
20785
20786				eventProps.allDay = !(eventProps.start.hasTime() || (eventProps.end && eventProps.end.hasTime()));
20787
20788			}
20789
20790
20791
20792			if (eventProps.allDay) {
20793
20794				eventProps.start.stripTime();
20795
20796				if (eventProps.end) {
20797
20798					// TODO: consider nextDayThreshold here? If so, will require a lot of testing and adjustment
20799
20800					eventProps.end.stripTime();
20801
20802				}
20803
20804			}
20805
20806			else {
20807
20808				if (!eventProps.start.hasTime()) {
20809
20810					eventProps.start = t.applyTimezone(eventProps.start.time(0)); // will assign a 00:00 time
20811
20812				}
20813
20814				if (eventProps.end && !eventProps.end.hasTime()) {
20815
20816					eventProps.end = t.applyTimezone(eventProps.end.time(0)); // will assign a 00:00 time
20817
20818				}
20819
20820			}
20821
20822		}
20823
20824
20825
20826
20827
20828		// If the given event is a recurring event, break it down into an array of individual instances.
20829
20830		// If not a recurring event, return an array with the single original event.
20831
20832		// If given a falsy input (probably because of a failed buildEventFromInput call), returns an empty array.
20833
20834		// HACK: can override the recurring window by providing custom rangeStart/rangeEnd (for businessHours).
20835
20836		function expandEvent(abstractEvent, _rangeStart, _rangeEnd) {
20837
20838			var events = [];
20839
20840			var dowHash;
20841
20842			var dow;
20843
20844			var i;
20845
20846			var date;
20847
20848			var startTime, endTime;
20849
20850			var start, end;
20851
20852			var event;
20853
20854
20855
20856			_rangeStart = _rangeStart || rangeStart;
20857
20858			_rangeEnd = _rangeEnd || rangeEnd;
20859
20860
20861
20862			if (abstractEvent) {
20863
20864				if (abstractEvent._recurring) {
20865
20866
20867
20868					// make a boolean hash as to whether the event occurs on each day-of-week
20869
20870					if ((dow = abstractEvent.dow)) {
20871
20872						dowHash = {};
20873
20874						for (i = 0; i < dow.length; i++) {
20875
20876							dowHash[dow[i]] = true;
20877
20878						}
20879
20880					}
20881
20882
20883
20884					// iterate through every day in the current range
20885
20886					date = _rangeStart.clone().stripTime(); // holds the date of the current day
20887
20888					while (date.isBefore(_rangeEnd)) {
20889
20890
20891
20892						if (!dowHash || dowHash[date.day()]) { // if everyday, or this particular day-of-week
20893
20894
20895
20896							startTime = abstractEvent.start; // the stored start and end properties are times (Durations)
20897
20898							endTime = abstractEvent.end; // "
20899
20900							start = date.clone();
20901
20902							end = null;
20903
20904
20905
20906							if (startTime) {
20907
20908								start = start.time(startTime);
20909
20910							}
20911
20912							if (endTime) {
20913
20914								end = date.clone().time(endTime);
20915
20916							}
20917
20918
20919
20920							event = $.extend({}, abstractEvent); // make a copy of the original
20921
20922							assignDatesToEvent(
20923
20924								start, end,
20925
20926								!startTime && !endTime, // allDay?
20927
20928								event
20929
20930							);
20931
20932							events.push(event);
20933
20934						}
20935
20936
20937
20938						date.add(1, 'days');
20939
20940					}
20941
20942				}
20943
20944				else {
20945
20946					events.push(abstractEvent); // return the original event. will be a one-item array
20947
20948				}
20949
20950			}
20951
20952
20953
20954			return events;
20955
20956		}
20957
20958
20959
20960
20961
20962
20963
20964		/* Event Modification Math
20965
20966		 -----------------------------------------------------------------------------------------*/
20967
20968
20969
20970
20971
20972		// Modifies an event and all related events by applying the given properties.
20973
20974		// Special date-diffing logic is used for manipulation of dates.
20975
20976		// If `props` does not contain start/end dates, the updated values are assumed to be the event's current start/end.
20977
20978		// All date comparisons are done against the event's pristine _start and _end dates.
20979
20980		// Returns an object with delta information and a function to undo all operations.
20981
20982		// For making computations in a granularity greater than day/time, specify largeUnit.
20983
20984		// NOTE: The given `newProps` might be mutated for normalization purposes.
20985
20986		function mutateEvent(event, newProps, largeUnit) {
20987
20988			var miscProps = {};
20989
20990			var oldProps;
20991
20992			var clearEnd;
20993
20994			var startDelta;
20995
20996			var endDelta;
20997
20998			var durationDelta;
20999
21000			var undoFunc;
21001
21002
21003
21004			// diffs the dates in the appropriate way, returning a duration
21005
21006			function diffDates(date1, date0) { // date1 - date0
21007
21008				if (largeUnit) {
21009
21010					return diffByUnit(date1, date0, largeUnit);
21011
21012				}
21013
21014				else if (newProps.allDay) {
21015
21016					return diffDay(date1, date0);
21017
21018				}
21019
21020				else {
21021
21022					return diffDayTime(date1, date0);
21023
21024				}
21025
21026			}
21027
21028
21029
21030			newProps = newProps || {};
21031
21032
21033
21034			// normalize new date-related properties
21035
21036			if (!newProps.start) {
21037
21038				newProps.start = event.start.clone();
21039
21040			}
21041
21042			if (newProps.end === undefined) {
21043
21044				newProps.end = event.end ? event.end.clone() : null;
21045
21046			}
21047
21048			if (newProps.allDay == null) { // is null or undefined?
21049
21050				newProps.allDay = event.allDay;
21051
21052			}
21053
21054			normalizeEventDates(newProps);
21055
21056
21057
21058			// create normalized versions of the original props to compare against
21059
21060			// need a real end value, for diffing
21061
21062			oldProps = {
21063
21064				start: event._start.clone(),
21065
21066				end: event._end ? event._end.clone() : t.getDefaultEventEnd(event._allDay, event._start),
21067
21068				allDay: newProps.allDay // normalize the dates in the same regard as the new properties
21069
21070			};
21071
21072			normalizeEventDates(oldProps);
21073
21074
21075
21076			// need to clear the end date if explicitly changed to null
21077
21078			clearEnd = event._end !== null && newProps.end === null;
21079
21080
21081
21082			// compute the delta for moving the start date
21083
21084			startDelta = diffDates(newProps.start, oldProps.start);
21085
21086
21087
21088			// compute the delta for moving the end date
21089
21090			if (newProps.end) {
21091
21092				endDelta = diffDates(newProps.end, oldProps.end);
21093
21094				durationDelta = endDelta.subtract(startDelta);
21095
21096			}
21097
21098			else {
21099
21100				durationDelta = null;
21101
21102			}
21103
21104
21105
21106			// gather all non-date-related properties
21107
21108			$.each(newProps, function(name, val) {
21109
21110				if (isMiscEventPropName(name)) {
21111
21112					if (val !== undefined) {
21113
21114						miscProps[name] = val;
21115
21116					}
21117
21118				}
21119
21120			});
21121
21122
21123
21124			// apply the operations to the event and all related events
21125
21126			undoFunc = mutateEvents(
21127
21128				clientEvents(event._id), // get events with this ID
21129
21130				clearEnd,
21131
21132				newProps.allDay,
21133
21134				startDelta,
21135
21136				durationDelta,
21137
21138				miscProps
21139
21140			);
21141
21142
21143
21144			return {
21145
21146				dateDelta: startDelta,
21147
21148				durationDelta: durationDelta,
21149
21150				undo: undoFunc
21151
21152			};
21153
21154		}
21155
21156
21157
21158
21159
21160		// Modifies an array of events in the following ways (operations are in order):
21161
21162		// - clear the event's `end`
21163
21164		// - convert the event to allDay
21165
21166		// - add `dateDelta` to the start and end
21167
21168		// - add `durationDelta` to the event's duration
21169
21170		// - assign `miscProps` to the event
21171
21172		//
21173
21174		// Returns a function that can be called to undo all the operations.
21175
21176		//
21177
21178		// TODO: don't use so many closures. possible memory issues when lots of events with same ID.
21179
21180		//
21181
21182		function mutateEvents(events, clearEnd, allDay, dateDelta, durationDelta, miscProps) {
21183
21184			var isAmbigTimezone = t.getIsAmbigTimezone();
21185
21186			var undoFunctions = [];
21187
21188
21189
21190			// normalize zero-length deltas to be null
21191
21192			if (dateDelta && !dateDelta.valueOf()) { dateDelta = null; }
21193
21194			if (durationDelta && !durationDelta.valueOf()) { durationDelta = null; }
21195
21196
21197
21198			$.each(events, function(i, event) {
21199
21200				var oldProps;
21201
21202				var newProps;
21203
21204
21205
21206				// build an object holding all the old values, both date-related and misc.
21207
21208				// for the undo function.
21209
21210				oldProps = {
21211
21212					start: event.start.clone(),
21213
21214					end: event.end ? event.end.clone() : null,
21215
21216					allDay: event.allDay
21217
21218				};
21219
21220				$.each(miscProps, function(name) {
21221
21222					oldProps[name] = event[name];
21223
21224				});
21225
21226
21227
21228				// new date-related properties. work off the original date snapshot.
21229
21230				// ok to use references because they will be thrown away when backupEventDates is called.
21231
21232				newProps = {
21233
21234					start: event._start,
21235
21236					end: event._end,
21237
21238					allDay: allDay // normalize the dates in the same regard as the new properties
21239
21240				};
21241
21242				normalizeEventDates(newProps); // massages start/end/allDay
21243
21244
21245
21246				// strip or ensure the end date
21247
21248				if (clearEnd) {
21249
21250					newProps.end = null;
21251
21252				}
21253
21254				else if (durationDelta && !newProps.end) { // the duration translation requires an end date
21255
21256					newProps.end = t.getDefaultEventEnd(newProps.allDay, newProps.start);
21257
21258				}
21259
21260
21261
21262				if (dateDelta) {
21263
21264					newProps.start.add(dateDelta);
21265
21266					if (newProps.end) {
21267
21268						newProps.end.add(dateDelta);
21269
21270					}
21271
21272				}
21273
21274
21275
21276				if (durationDelta) {
21277
21278					newProps.end.add(durationDelta); // end already ensured above
21279
21280				}
21281
21282
21283
21284				// if the dates have changed, and we know it is impossible to recompute the
21285
21286				// timezone offsets, strip the zone.
21287
21288				if (
21289
21290					isAmbigTimezone &&
21291
21292					!newProps.allDay &&
21293
21294					(dateDelta || durationDelta)
21295
21296				) {
21297
21298					newProps.start.stripZone();
21299
21300					if (newProps.end) {
21301
21302						newProps.end.stripZone();
21303
21304					}
21305
21306				}
21307
21308
21309
21310				$.extend(event, miscProps, newProps); // copy over misc props, then date-related props
21311
21312				backupEventDates(event); // regenerate internal _start/_end/_allDay
21313
21314
21315
21316				undoFunctions.push(function() {
21317
21318					$.extend(event, oldProps);
21319
21320					backupEventDates(event); // regenerate internal _start/_end/_allDay
21321
21322				});
21323
21324			});
21325
21326
21327
21328			return function() {
21329
21330				for (var i = 0; i < undoFunctions.length; i++) {
21331
21332					undoFunctions[i]();
21333
21334				}
21335
21336			};
21337
21338		}
21339
21340
21341
21342
21343
21344		/* Business Hours
21345
21346		 -----------------------------------------------------------------------------------------*/
21347
21348
21349
21350		t.getBusinessHoursEvents = getBusinessHoursEvents;
21351
21352
21353
21354
21355
21356		// Returns an array of events as to when the business hours occur in the given view.
21357
21358		// Abuse of our event system :(
21359
21360		function getBusinessHoursEvents(wholeDay) {
21361
21362			var optionVal = options.businessHours;
21363
21364			var defaultVal = {
21365
21366				className: 'fc-nonbusiness',
21367
21368				start: '09:00',
21369
21370				end: '17:00',
21371
21372				dow: [ 1, 2, 3, 4, 5 ], // monday - friday
21373
21374				rendering: 'inverse-background'
21375
21376			};
21377
21378			var view = t.getView();
21379
21380			var eventInput;
21381
21382
21383
21384			if (optionVal) { // `true` (which means "use the defaults") or an override object
21385
21386				eventInput = $.extend(
21387
21388					{}, // copy to a new object in either case
21389
21390					defaultVal,
21391
21392					typeof optionVal === 'object' ? optionVal : {} // override the defaults
21393
21394				);
21395
21396			}
21397
21398
21399
21400			if (eventInput) {
21401
21402
21403
21404				// if a whole-day series is requested, clear the start/end times
21405
21406				if (wholeDay) {
21407
21408					eventInput.start = null;
21409
21410					eventInput.end = null;
21411
21412				}
21413
21414
21415
21416				return expandEvent(
21417
21418					buildEventFromInput(eventInput),
21419
21420					view.start,
21421
21422					view.end
21423
21424				);
21425
21426			}
21427
21428
21429
21430			return [];
21431
21432		}
21433
21434
21435
21436
21437
21438		/* Overlapping / Constraining
21439
21440		 -----------------------------------------------------------------------------------------*/
21441
21442
21443
21444		t.isEventSpanAllowed = isEventSpanAllowed;
21445
21446		t.isExternalSpanAllowed = isExternalSpanAllowed;
21447
21448		t.isSelectionSpanAllowed = isSelectionSpanAllowed;
21449
21450
21451
21452
21453
21454		// Determines if the given event can be relocated to the given span (unzoned start/end with other misc data)
21455
21456		function isEventSpanAllowed(span, event) {
21457
21458			var source = event.source || {};
21459
21460			var constraint = firstDefined(
21461
21462				event.constraint,
21463
21464				source.constraint,
21465
21466				options.eventConstraint
21467
21468			);
21469
21470			var overlap = firstDefined(
21471
21472				event.overlap,
21473
21474				source.overlap,
21475
21476				options.eventOverlap
21477
21478			);
21479
21480			return isSpanAllowed(span, constraint, overlap, event);
21481
21482		}
21483
21484
21485
21486
21487
21488		// Determines if an external event can be relocated to the given span (unzoned start/end with other misc data)
21489
21490		function isExternalSpanAllowed(eventSpan, eventLocation, eventProps) {
21491
21492			var eventInput;
21493
21494			var event;
21495
21496
21497
21498			// note: very similar logic is in View's reportExternalDrop
21499
21500			if (eventProps) {
21501
21502				eventInput = $.extend({}, eventProps, eventLocation);
21503
21504				event = expandEvent(buildEventFromInput(eventInput))[0];
21505
21506			}
21507
21508
21509
21510			if (event) {
21511
21512				return isEventSpanAllowed(eventSpan, event);
21513
21514			}
21515
21516			else { // treat it as a selection
21517
21518
21519
21520				return isSelectionSpanAllowed(eventSpan);
21521
21522			}
21523
21524		}
21525
21526
21527
21528
21529
21530		// Determines the given span (unzoned start/end with other misc data) can be selected.
21531
21532		function isSelectionSpanAllowed(span) {
21533
21534			return isSpanAllowed(span, options.selectConstraint, options.selectOverlap);
21535
21536		}
21537
21538
21539
21540
21541
21542		// Returns true if the given span (caused by an event drop/resize or a selection) is allowed to exist
21543
21544		// according to the constraint/overlap settings.
21545
21546		// `event` is not required if checking a selection.
21547
21548		function isSpanAllowed(span, constraint, overlap, event) {
21549
21550			var constraintEvents;
21551
21552			var anyContainment;
21553
21554			var peerEvents;
21555
21556			var i, peerEvent;
21557
21558			var peerOverlap;
21559
21560
21561
21562			// the range must be fully contained by at least one of produced constraint events
21563
21564			if (constraint != null) {
21565
21566
21567
21568				// not treated as an event! intermediate data structure
21569
21570				// TODO: use ranges in the future
21571
21572				constraintEvents = constraintToEvents(constraint);
21573
21574
21575
21576				anyContainment = false;
21577
21578				for (i = 0; i < constraintEvents.length; i++) {
21579
21580					if (eventContainsRange(constraintEvents[i], span)) {
21581
21582						anyContainment = true;
21583
21584						break;
21585
21586					}
21587
21588				}
21589
21590
21591
21592				if (!anyContainment) {
21593
21594					return false;
21595
21596				}
21597
21598			}
21599
21600
21601
21602			peerEvents = t.getPeerEvents(span, event);
21603
21604
21605
21606			for (i = 0; i < peerEvents.length; i++)  {
21607
21608				peerEvent = peerEvents[i];
21609
21610
21611
21612				// there needs to be an actual intersection before disallowing anything
21613
21614				if (eventIntersectsRange(peerEvent, span)) {
21615
21616
21617
21618					// evaluate overlap for the given range and short-circuit if necessary
21619
21620					if (overlap === false) {
21621
21622						return false;
21623
21624					}
21625
21626					// if the event's overlap is a test function, pass the peer event in question as the first param
21627
21628					else if (typeof overlap === 'function' && !overlap(peerEvent, event)) {
21629
21630						return false;
21631
21632					}
21633
21634
21635
21636					// if we are computing if the given range is allowable for an event, consider the other event's
21637
21638					// EventObject-specific or Source-specific `overlap` property
21639
21640					if (event) {
21641
21642						peerOverlap = firstDefined(
21643
21644							peerEvent.overlap,
21645
21646							(peerEvent.source || {}).overlap
21647
21648							// we already considered the global `eventOverlap`
21649
21650						);
21651
21652						if (peerOverlap === false) {
21653
21654							return false;
21655
21656						}
21657
21658						// if the peer event's overlap is a test function, pass the subject event as the first param
21659
21660						if (typeof peerOverlap === 'function' && !peerOverlap(event, peerEvent)) {
21661
21662							return false;
21663
21664						}
21665
21666					}
21667
21668				}
21669
21670			}
21671
21672
21673
21674			return true;
21675
21676		}
21677
21678
21679
21680
21681
21682		// Given an event input from the API, produces an array of event objects. Possible event inputs:
21683
21684		// 'businessHours'
21685
21686		// An event ID (number or string)
21687
21688		// An object with specific start/end dates or a recurring event (like what businessHours accepts)
21689
21690		function constraintToEvents(constraintInput) {
21691
21692
21693
21694			if (constraintInput === 'businessHours') {
21695
21696				return getBusinessHoursEvents();
21697
21698			}
21699
21700
21701
21702			if (typeof constraintInput === 'object') {
21703
21704				return expandEvent(buildEventFromInput(constraintInput));
21705
21706			}
21707
21708
21709
21710			return clientEvents(constraintInput); // probably an ID
21711
21712		}
21713
21714
21715
21716
21717
21718		// Does the event's date range fully contain the given range?
21719
21720		// start/end already assumed to have stripped zones :(
21721
21722		function eventContainsRange(event, range) {
21723
21724			var eventStart = event.start.clone().stripZone();
21725
21726			var eventEnd = t.getEventEnd(event).stripZone();
21727
21728
21729
21730			return range.start >= eventStart && range.end <= eventEnd;
21731
21732		}
21733
21734
21735
21736
21737
21738		// Does the event's date range intersect with the given range?
21739
21740		// start/end already assumed to have stripped zones :(
21741
21742		function eventIntersectsRange(event, range) {
21743
21744			var eventStart = event.start.clone().stripZone();
21745
21746			var eventEnd = t.getEventEnd(event).stripZone();
21747
21748
21749
21750			return range.start < eventEnd && range.end > eventStart;
21751
21752		}
21753
21754
21755
21756
21757
21758		t.getEventCache = function() {
21759
21760			return cache;
21761
21762		};
21763
21764
21765
21766	}
21767
21768
21769
21770
21771
21772// Returns a list of events that the given event should be compared against when being considered for a move to
21773
21774// the specified span. Attached to the Calendar's prototype because EventManager is a mixin for a Calendar.
21775
21776	Calendar.prototype.getPeerEvents = function(span, event) {
21777
21778		var cache = this.getEventCache();
21779
21780		var peerEvents = [];
21781
21782		var i, otherEvent;
21783
21784
21785
21786		for (i = 0; i < cache.length; i++) {
21787
21788			otherEvent = cache[i];
21789
21790			if (
21791
21792				!event ||
21793
21794				event._id !== otherEvent._id // don't compare the event to itself or other related [repeating] events
21795
21796			) {
21797
21798				peerEvents.push(otherEvent);
21799
21800			}
21801
21802		}
21803
21804
21805
21806		return peerEvents;
21807
21808	};
21809
21810
21811
21812
21813
21814// updates the "backup" properties, which are preserved in order to compute diffs later on.
21815
21816	function backupEventDates(event) {
21817
21818		event._allDay = event.allDay;
21819
21820		event._start = event.start.clone();
21821
21822		event._end = event.end ? event.end.clone() : null;
21823
21824	}
21825
21826
21827
21828	;;
21829
21830
21831
21832	/* An abstract class for the "basic" views, as well as month view. Renders one or more rows of day cells.
21833
21834	 ----------------------------------------------------------------------------------------------------------------------*/
21835
21836// It is a manager for a DayGrid subcomponent, which does most of the heavy lifting.
21837
21838// It is responsible for managing width/height.
21839
21840
21841
21842	var BasicView = FC.BasicView = View.extend({
21843
21844
21845
21846		dayGridClass: DayGrid, // class the dayGrid will be instantiated from (overridable by subclasses)
21847
21848		dayGrid: null, // the main subcomponent that does most of the heavy lifting
21849
21850
21851
21852		dayNumbersVisible: false, // display day numbers on each day cell?
21853
21854		weekNumbersVisible: false, // display week numbers along the side?
21855
21856
21857
21858		weekNumberWidth: null, // width of all the week-number cells running down the side
21859
21860
21861
21862		headContainerEl: null, // div that hold's the dayGrid's rendered date header
21863
21864		headRowEl: null, // the fake row element of the day-of-week header
21865
21866
21867
21868
21869
21870		initialize: function() {
21871
21872			this.dayGrid = this.instantiateDayGrid();
21873
21874		},
21875
21876
21877
21878
21879
21880		// Generates the DayGrid object this view needs. Draws from this.dayGridClass
21881
21882		instantiateDayGrid: function() {
21883
21884			// generate a subclass on the fly with BasicView-specific behavior
21885
21886			// TODO: cache this subclass
21887
21888			var subclass = this.dayGridClass.extend(basicDayGridMethods);
21889
21890
21891
21892			return new subclass(this);
21893
21894		},
21895
21896
21897
21898
21899
21900		// Sets the display range and computes all necessary dates
21901
21902		setRange: function(range) {
21903
21904			View.prototype.setRange.call(this, range); // call the super-method
21905
21906
21907
21908			this.dayGrid.breakOnWeeks = /year|month|week/.test(this.intervalUnit); // do before setRange
21909
21910			this.dayGrid.setRange(range);
21911
21912		},
21913
21914
21915
21916
21917
21918		// Compute the value to feed into setRange. Overrides superclass.
21919
21920		computeRange: function(date) {
21921
21922			var range = View.prototype.computeRange.call(this, date); // get value from the super-method
21923
21924
21925
21926			// year and month views should be aligned with weeks. this is already done for week
21927
21928			if (/year|month/.test(range.intervalUnit)) {
21929
21930				range.start.startOf('week');
21931
21932				range.start = this.skipHiddenDays(range.start);
21933
21934
21935
21936				// make end-of-week if not already
21937
21938				if (range.end.weekday()) {
21939
21940					range.end.add(1, 'week').startOf('week');
21941
21942					range.end = this.skipHiddenDays(range.end, -1, true); // exclusively move backwards
21943
21944				}
21945
21946			}
21947
21948
21949
21950			return range;
21951
21952		},
21953
21954
21955
21956
21957
21958		// Renders the view into `this.el`, which should already be assigned
21959
21960		renderDates: function() {
21961
21962
21963
21964			this.dayNumbersVisible = this.dayGrid.rowCnt > 1; // TODO: make grid responsible
21965
21966			this.weekNumbersVisible = this.opt('weekNumbers');
21967
21968			this.dayGrid.numbersVisible = this.dayNumbersVisible || this.weekNumbersVisible;
21969
21970
21971
21972			this.el.addClass('fc-basic-view').html(this.renderSkeletonHtml());
21973
21974			this.renderHead();
21975
21976
21977
21978			this.scrollerEl = this.el.find('.fc-day-grid-container');
21979
21980
21981
21982			this.dayGrid.setElement(this.el.find('.fc-day-grid'));
21983
21984			this.dayGrid.renderDates(this.hasRigidRows());
21985
21986		},
21987
21988
21989
21990
21991
21992		// render the day-of-week headers
21993
21994		renderHead: function() {
21995
21996			this.headContainerEl =
21997
21998				this.el.find('.fc-head-container')
21999
22000					.html(this.dayGrid.renderHeadHtml());
22001
22002			this.headRowEl = this.headContainerEl.find('.fc-row');
22003
22004		},
22005
22006
22007
22008
22009
22010		// Unrenders the content of the view. Since we haven't separated skeleton rendering from date rendering,
22011
22012		// always completely kill the dayGrid's rendering.
22013
22014		unrenderDates: function() {
22015
22016			this.dayGrid.unrenderDates();
22017
22018			this.dayGrid.removeElement();
22019
22020		},
22021
22022
22023
22024
22025
22026		renderBusinessHours: function() {
22027
22028			this.dayGrid.renderBusinessHours();
22029
22030		},
22031
22032
22033
22034
22035
22036		// Builds the HTML skeleton for the view.
22037
22038		// The day-grid component will render inside of a container defined by this HTML.
22039
22040		renderSkeletonHtml: function() {
22041
22042			return '' +
22043
22044				'<table>' +
22045
22046				'<thead class="fc-head">' +
22047
22048				'<tr>' +
22049
22050				'<td class="fc-head-container ' + this.widgetHeaderClass + '"></td>' +
22051
22052				'</tr>' +
22053
22054				'</thead>' +
22055
22056				'<tbody class="fc-body">' +
22057
22058				'<tr>' +
22059
22060				'<td class="' + this.widgetContentClass + '">' +
22061
22062				'<div class="fc-day-grid-container">' +
22063
22064				'<div class="fc-day-grid"/>' +
22065
22066				'</div>' +
22067
22068				'</td>' +
22069
22070				'</tr>' +
22071
22072				'</tbody>' +
22073
22074				'</table>';
22075
22076		},
22077
22078
22079
22080
22081
22082		// Generates an HTML attribute string for setting the width of the week number column, if it is known
22083
22084		weekNumberStyleAttr: function() {
22085
22086			if (this.weekNumberWidth !== null) {
22087
22088				return 'style="width:' + this.weekNumberWidth + 'px"';
22089
22090			}
22091
22092			return '';
22093
22094		},
22095
22096
22097
22098
22099
22100		// Determines whether each row should have a constant height
22101
22102		hasRigidRows: function() {
22103
22104			var eventLimit = this.opt('eventLimit');
22105
22106			return eventLimit && typeof eventLimit !== 'number';
22107
22108		},
22109
22110
22111
22112
22113
22114		/* Dimensions
22115
22116		 ------------------------------------------------------------------------------------------------------------------*/
22117
22118
22119
22120
22121
22122		// Refreshes the horizontal dimensions of the view
22123
22124		updateWidth: function() {
22125
22126			if (this.weekNumbersVisible) {
22127
22128				// Make sure all week number cells running down the side have the same width.
22129
22130				// Record the width for cells created later.
22131
22132				this.weekNumberWidth = matchCellWidths(
22133
22134					this.el.find('.fc-week-number')
22135
22136				);
22137
22138			}
22139
22140		},
22141
22142
22143
22144
22145
22146		// Adjusts the vertical dimensions of the view to the specified values
22147
22148		setHeight: function(totalHeight, isAuto) {
22149
22150			var eventLimit = this.opt('eventLimit');
22151
22152			var scrollerHeight;
22153
22154
22155
22156			// reset all heights to be natural
22157
22158			unsetScroller(this.scrollerEl);
22159
22160			uncompensateScroll(this.headRowEl);
22161
22162
22163
22164			this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
22165
22166
22167
22168			// is the event limit a constant level number?
22169
22170			if (eventLimit && typeof eventLimit === 'number') {
22171
22172				this.dayGrid.limitRows(eventLimit); // limit the levels first so the height can redistribute after
22173
22174			}
22175
22176
22177
22178			scrollerHeight = this.computeScrollerHeight(totalHeight);
22179
22180			this.setGridHeight(scrollerHeight, isAuto);
22181
22182
22183
22184			// is the event limit dynamically calculated?
22185
22186			if (eventLimit && typeof eventLimit !== 'number') {
22187
22188				this.dayGrid.limitRows(eventLimit); // limit the levels after the grid's row heights have been set
22189
22190			}
22191
22192
22193
22194			if (!isAuto && setPotentialScroller(this.scrollerEl, scrollerHeight)) { // using scrollbars?
22195
22196
22197
22198				compensateScroll(this.headRowEl, getScrollbarWidths(this.scrollerEl));
22199
22200
22201
22202				// doing the scrollbar compensation might have created text overflow which created more height. redo
22203
22204				scrollerHeight = this.computeScrollerHeight(totalHeight);
22205
22206				this.scrollerEl.height(scrollerHeight);
22207
22208			}
22209
22210		},
22211
22212
22213
22214
22215
22216		// Sets the height of just the DayGrid component in this view
22217
22218		setGridHeight: function(height, isAuto) {
22219
22220			if (isAuto) {
22221
22222				undistributeHeight(this.dayGrid.rowEls); // let the rows be their natural height with no expanding
22223
22224			}
22225
22226			else {
22227
22228				distributeHeight(this.dayGrid.rowEls, height, true); // true = compensate for height-hogging rows
22229
22230			}
22231
22232		},
22233
22234
22235
22236
22237
22238		/* Hit Areas
22239
22240		 ------------------------------------------------------------------------------------------------------------------*/
22241
22242		// forward all hit-related method calls to dayGrid
22243
22244
22245
22246
22247
22248		prepareHits: function() {
22249
22250			this.dayGrid.prepareHits();
22251
22252		},
22253
22254
22255
22256
22257
22258		releaseHits: function() {
22259
22260			this.dayGrid.releaseHits();
22261
22262		},
22263
22264
22265
22266
22267
22268		queryHit: function(left, top) {
22269
22270			return this.dayGrid.queryHit(left, top);
22271
22272		},
22273
22274
22275
22276
22277
22278		getHitSpan: function(hit) {
22279
22280			return this.dayGrid.getHitSpan(hit);
22281
22282		},
22283
22284
22285
22286
22287
22288		getHitEl: function(hit) {
22289
22290			return this.dayGrid.getHitEl(hit);
22291
22292		},
22293
22294
22295
22296
22297
22298		/* Events
22299
22300		 ------------------------------------------------------------------------------------------------------------------*/
22301
22302
22303
22304
22305
22306		// Renders the given events onto the view and populates the segments array
22307
22308		renderEvents: function(events) {
22309
22310			this.dayGrid.renderEvents(events);
22311
22312
22313
22314			this.updateHeight(); // must compensate for events that overflow the row
22315
22316		},
22317
22318
22319
22320
22321
22322		// Retrieves all segment objects that are rendered in the view
22323
22324		getEventSegs: function() {
22325
22326			return this.dayGrid.getEventSegs();
22327
22328		},
22329
22330
22331
22332
22333
22334		// Unrenders all event elements and clears internal segment data
22335
22336		unrenderEvents: function() {
22337
22338			this.dayGrid.unrenderEvents();
22339
22340
22341
22342			// we DON'T need to call updateHeight() because:
22343
22344			// A) a renderEvents() call always happens after this, which will eventually call updateHeight()
22345
22346			// B) in IE8, this causes a flash whenever events are rerendered
22347
22348		},
22349
22350
22351
22352
22353
22354		/* Dragging (for both events and external elements)
22355
22356		 ------------------------------------------------------------------------------------------------------------------*/
22357
22358
22359
22360
22361
22362		// A returned value of `true` signals that a mock "helper" event has been rendered.
22363
22364		renderDrag: function(dropLocation, seg) {
22365
22366			return this.dayGrid.renderDrag(dropLocation, seg);
22367
22368		},
22369
22370
22371
22372
22373
22374		unrenderDrag: function() {
22375
22376			this.dayGrid.unrenderDrag();
22377
22378		},
22379
22380
22381
22382
22383
22384		/* Selection
22385
22386		 ------------------------------------------------------------------------------------------------------------------*/
22387
22388
22389
22390
22391
22392		// Renders a visual indication of a selection
22393
22394		renderSelection: function(span) {
22395
22396			this.dayGrid.renderSelection(span);
22397
22398		},
22399
22400
22401
22402
22403
22404		// Unrenders a visual indications of a selection
22405
22406		unrenderSelection: function() {
22407
22408			this.dayGrid.unrenderSelection();
22409
22410		}
22411
22412
22413
22414	});
22415
22416
22417
22418
22419
22420// Methods that will customize the rendering behavior of the BasicView's dayGrid
22421
22422	var basicDayGridMethods = {
22423
22424
22425
22426
22427
22428		// Generates the HTML that will go before the day-of week header cells
22429
22430		renderHeadIntroHtml: function() {
22431
22432			var view = this.view;
22433
22434
22435
22436			if (view.weekNumbersVisible) {
22437
22438				return '' +
22439
22440					'<th class="fc-week-number ' + view.widgetHeaderClass + '" ' + view.weekNumberStyleAttr() + '>' +
22441
22442					'<span>' + // needed for matchCellWidths
22443
22444					htmlEscape(view.opt('weekNumberTitle')) +
22445
22446					'</span>' +
22447
22448					'</th>';
22449
22450			}
22451
22452
22453
22454			return '';
22455
22456		},
22457
22458
22459
22460
22461
22462		// Generates the HTML that will go before content-skeleton cells that display the day/week numbers
22463
22464		renderNumberIntroHtml: function(row) {
22465
22466			var view = this.view;
22467
22468
22469
22470			if (view.weekNumbersVisible) {
22471
22472				return '' +
22473
22474					'<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '>' +
22475
22476					'<span>' + // needed for matchCellWidths
22477
22478					this.getCellDate(row, 0).format('w') +
22479
22480					'</span>' +
22481
22482					'</td>';
22483
22484			}
22485
22486
22487
22488			return '';
22489
22490		},
22491
22492
22493
22494
22495
22496		// Generates the HTML that goes before the day bg cells for each day-row
22497
22498		renderBgIntroHtml: function() {
22499
22500			var view = this.view;
22501
22502
22503
22504			if (view.weekNumbersVisible) {
22505
22506				return '<td class="fc-week-number ' + view.widgetContentClass + '" ' +
22507
22508					view.weekNumberStyleAttr() + '></td>';
22509
22510			}
22511
22512
22513
22514			return '';
22515
22516		},
22517
22518
22519
22520
22521
22522		// Generates the HTML that goes before every other type of row generated by DayGrid.
22523
22524		// Affects helper-skeleton and highlight-skeleton rows.
22525
22526		renderIntroHtml: function() {
22527
22528			var view = this.view;
22529
22530
22531
22532			if (view.weekNumbersVisible) {
22533
22534				return '<td class="fc-week-number" ' + view.weekNumberStyleAttr() + '></td>';
22535
22536			}
22537
22538
22539
22540			return '';
22541
22542		}
22543
22544
22545
22546	};
22547
22548
22549
22550	;;
22551
22552
22553
22554	/* A month view with day cells running in rows (one-per-week) and columns
22555
22556	 ----------------------------------------------------------------------------------------------------------------------*/
22557
22558
22559
22560	var MonthView = FC.MonthView = BasicView.extend({
22561
22562
22563
22564		// Produces information about what range to display
22565
22566		computeRange: function(date) {
22567
22568			var range = BasicView.prototype.computeRange.call(this, date); // get value from super-method
22569
22570			var rowCnt;
22571
22572
22573
22574			// ensure 6 weeks
22575
22576			if (this.isFixedWeeks()) {
22577
22578				rowCnt = Math.ceil(range.end.diff(range.start, 'weeks', true)); // could be partial weeks due to hiddenDays
22579
22580				range.end.add(6 - rowCnt, 'weeks');
22581
22582			}
22583
22584
22585
22586			return range;
22587
22588		},
22589
22590
22591
22592
22593
22594		// Overrides the default BasicView behavior to have special multi-week auto-height logic
22595
22596		setGridHeight: function(height, isAuto) {
22597
22598
22599
22600			isAuto = isAuto || this.opt('weekMode') === 'variable'; // LEGACY: weekMode is deprecated
22601
22602
22603
22604			// if auto, make the height of each row the height that it would be if there were 6 weeks
22605
22606			if (isAuto) {
22607
22608				height *= this.rowCnt / 6;
22609
22610			}
22611
22612
22613
22614			distributeHeight(this.dayGrid.rowEls, height, !isAuto); // if auto, don't compensate for height-hogging rows
22615
22616		},
22617
22618
22619
22620
22621
22622		isFixedWeeks: function() {
22623
22624			var weekMode = this.opt('weekMode'); // LEGACY: weekMode is deprecated
22625
22626			if (weekMode) {
22627
22628				return weekMode === 'fixed'; // if any other type of weekMode, assume NOT fixed
22629
22630			}
22631
22632
22633
22634			return this.opt('fixedWeekCount');
22635
22636		}
22637
22638
22639
22640	});
22641
22642
22643
22644	;;
22645
22646
22647
22648	fcViews.basic = {
22649
22650		'class': BasicView
22651
22652	};
22653
22654
22655
22656	fcViews.basicDay = {
22657
22658		type: 'basic',
22659
22660		duration: { days: 1 }
22661
22662	};
22663
22664
22665
22666	fcViews.basicWeek = {
22667
22668		type: 'basic',
22669
22670		duration: { weeks: 1 }
22671
22672	};
22673
22674
22675
22676	fcViews.month = {
22677
22678		'class': MonthView,
22679
22680		duration: { months: 1 }, // important for prev/next
22681
22682		defaults: {
22683
22684			fixedWeekCount: true
22685
22686		}
22687
22688	};
22689
22690	;;
22691
22692
22693
22694	/* An abstract class for all agenda-related views. Displays one more columns with time slots running vertically.
22695
22696	 ----------------------------------------------------------------------------------------------------------------------*/
22697
22698// Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
22699
22700// Responsible for managing width/height.
22701
22702
22703
22704	var AgendaView = FC.AgendaView = View.extend({
22705
22706
22707
22708		timeGridClass: TimeGrid, // class used to instantiate the timeGrid. subclasses can override
22709
22710		timeGrid: null, // the main time-grid subcomponent of this view
22711
22712
22713
22714		dayGridClass: DayGrid, // class used to instantiate the dayGrid. subclasses can override
22715
22716		dayGrid: null, // the "all-day" subcomponent. if all-day is turned off, this will be null
22717
22718
22719
22720		axisWidth: null, // the width of the time axis running down the side
22721
22722
22723
22724		headContainerEl: null, // div that hold's the timeGrid's rendered date header
22725
22726		noScrollRowEls: null, // set of fake row elements that must compensate when scrollerEl has scrollbars
22727
22728
22729
22730		// when the time-grid isn't tall enough to occupy the given he
22730ight, we render an <hr> underneath
22731
22732		bottomRuleEl: null,
22733
22734		bottomRuleHeight: null,
22735
22736
22737
22738
22739
22740		initialize: function() {
22741
22742			this.timeGrid = this.instantiateTimeGrid();
22743
22744
22745
22746			if (this.opt('allDaySlot')) { // should we display the "all-day" area?
22747
22748				this.dayGrid = this.instantiateDayGrid(); // the all-day subcomponent of this view
22749
22750			}
22751
22752		},
22753
22754
22755
22756
22757
22758		// Instantiates the TimeGrid object this view needs. Draws from this.timeGridClass
22759
22760		instantiateTimeGrid: function() {
22761
22762			var subclass = this.timeGridClass.extend(agendaTimeGridMethods);
22763
22764
22765
22766			return new subclass(this);
22767
22768		},
22769
22770
22771
22772
22773
22774		// Instantiates the DayGrid object this view might need. Draws from this.dayGridClass
22775
22776		instantiateDayGrid: function() {
22777
22778			var subclass = this.dayGridClass.extend(agendaDayGridMethods);
22779
22780
22781
22782			return new subclass(this);
22783
22784		},
22785
22786
22787
22788
22789
22790		/* Rendering
22791
22792		 ------------------------------------------------------------------------------------------------------------------*/
22793
22794
22795
22796
22797
22798		// Sets the display range and computes all necessary dates
22799
22800		setRange: function(range) {
22801
22802			View.prototype.setRange.call(this, range); // call the super-method
22803
22804
22805
22806			this.timeGrid.setRange(range);
22807
22808			if (this.dayGrid) {
22809
22810				this.dayGrid.setRange(range);
22811
22812			}
22813
22814		},
22815
22816
22817
22818
22819
22820		// Renders the view into `this.el`, which has already been assigned
22821
22822		renderDates: function() {
22823
22824
22825
22826			this.el.addClass('fc-agenda-view').html(this.renderSkeletonHtml());
22827
22828			this.renderHead();
22829
22830
22831
22832			// the element that wraps the time-grid that will probably scroll
22833
22834			this.scrollerEl = this.el.find('.fc-time-grid-container');
22835
22836
22837
22838			this.timeGrid.setElement(this.el.find('.fc-time-grid'));
22839
22840			this.timeGrid.renderDates();
22841
22842
22843
22844			// the <hr> that sometimes displays under the time-grid
22845
22846			this.bottomRuleEl = $('<hr class="fc-divider ' + this.widgetHeaderClass + '"/>')
22847
22848				.appendTo(this.timeGrid.el); // inject it into the time-grid
22849
22850
22851
22852			if (this.dayGrid) {
22853
22854				this.dayGrid.setElement(this.el.find('.fc-day-grid'));
22855
22856				this.dayGrid.renderDates();
22857
22858
22859
22860				// have the day-grid extend it's coordinate area over the <hr> dividing the two grids
22861
22862				this.dayGrid.bottomCoordPadding = this.dayGrid.el.next('hr').outerHeight();
22863
22864			}
22865
22866
22867
22868			this.noScrollRowEls = this.el.find('.fc-row:not(.fc-scroller *)'); // fake rows not within the scroller
22869
22870		},
22871
22872
22873
22874
22875
22876		// render the day-of-week headers
22877
22878		renderHead: function() {
22879
22880			this.headContainerEl =
22881
22882				this.el.find('.fc-head-container')
22883
22884					.html(this.timeGrid.renderHeadHtml());
22885
22886		},
22887
22888
22889
22890
22891
22892		// Unrenders the content of the view. Since we haven't separated skeleton rendering from date rendering,
22893
22894		// always completely kill each grid's rendering.
22895
22896		unrenderDates: function() {
22897
22898			this.timeGrid.unrenderDates();
22899
22900			this.timeGrid.removeElement();
22901
22902
22903
22904			if (this.dayGrid) {
22905
22906				this.dayGrid.unrenderDates();
22907
22908				this.dayGrid.removeElement();
22909
22910			}
22911
22912		},
22913
22914
22915
22916
22917
22918		renderBusinessHours: function() {
22919
22920			this.timeGrid.renderBusinessHours();
22921
22922
22923
22924			if (this.dayGrid) {
22925
22926				this.dayGrid.renderBusinessHours();
22927
22928			}
22929
22930		},
22931
22932
22933
22934
22935
22936		// Builds the HTML skeleton for the view.
22937
22938		// The day-grid and time-grid components will render inside containers defined by this HTML.
22939
22940		renderSkeletonHtml: function() {
22941
22942			return '' +
22943
22944				'<table>' +
22945
22946				'<thead class="fc-head">' +
22947
22948				'<tr>' +
22949
22950				'<td class="fc-head-container ' + this.widgetHeaderClass + '"></td>' +
22951
22952				'</tr>' +
22953
22954				'</thead>' +
22955
22956				'<tbody class="fc-body">' +
22957
22958				'<tr>' +
22959
22960				'<td class="' + this.widgetContentClass + '">' +
22961
22962				(this.dayGrid ?
22963
22964					'<div class="fc-day-grid"/>' +
22965
22966					'<hr class="fc-divider ' + this.widgetHeaderClass + '"/>' :
22967
22968						''
22969
22970				) +
22971
22972				'<div class="fc-time-grid-container">' +
22973
22974				'<div class="fc-time-grid"/>' +
22975
22976				'</div>' +
22977
22978				'</td>' +
22979
22980				'</tr>' +
22981
22982				'</tbody>' +
22983
22984				'</table>';
22985
22986		},
22987
22988
22989
22990
22991
22992		// Generates an HTML attribute string for setting the width of the axis, if it is known
22993
22994		axisStyleAttr: function() {
22995
22996			if (this.axisWidth !== null) {
22997
22998				return 'style="width:' + this.axisWidth + 'px"';
22999
23000			}
23001
23002			return '';
23003
23004		},
23005
23006
23007
23008
23009
23010		/* Dimensions
23011
23012		 ------------------------------------------------------------------------------------------------------------------*/
23013
23014
23015
23016
23017
23018		updateSize: function(isResize) {
23019
23020			this.timeGrid.updateSize(isResize);
23021
23022
23023
23024			View.prototype.updateSize.call(this, isResize); // call the super-method
23025
23026		},
23027
23028
23029
23030
23031
23032		// Refreshes the horizontal dimensions of the view
23033
23034		updateWidth: function() {
23035
23036			// make all axis cells line up, and record the width so newly created axis cells will have it
23037
23038			this.axisWidth = matchCellWidths(this.el.find('.fc-axis'));
23039
23040		},
23041
23042
23043
23044
23045
23046		// Adjusts the vertical dimensions of the view to the specified values
23047
23048		setHeight: function(totalHeight, isAuto) {
23049
23050			var eventLimit;
23051
23052			var scrollerHeight;
23053
23054
23055
23056			if (this.bottomRuleHeight === null) {
23057
23058				// calculate the height of the rule the very first time
23059
23060				this.bottomRuleHeight = this.bottomRuleEl.outerHeight();
23061
23062			}
23063
23064			this.bottomRuleEl.hide(); // .show() will be called later if this <hr> is necessary
23065
23066
23067
23068			// reset all dimensions back to the original state
23069
23070			this.scrollerEl.css('overflow', '');
23071
23072			unsetScroller(this.scrollerEl);
23073
23074			uncompensateScroll(this.noScrollRowEls);
23075
23076
23077
23078			// limit number of events in the all-day area
23079
23080			if (this.dayGrid) {
23081
23082				this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
23083
23084
23085
23086				eventLimit = this.opt('eventLimit');
23087
23088				if (eventLimit && typeof eventLimit !== 'number') {
23089
23090					eventLimit = AGENDA_ALL_DAY_EVENT_LIMIT; // make sure "auto" goes to a real number
23091
23092				}
23093
23094				if (eventLimit) {
23095
23096					this.dayGrid.limitRows(eventLimit);
23097
23098				}
23099
23100			}
23101
23102
23103
23104			if (!isAuto) { // should we force dimensions of the scroll container, or let the contents be natural height?
23105
23106
23107
23108				scrollerHeight = this.computeScrollerHeight(totalHeight);
23109
23110				if (setPotentialScroller(this.scrollerEl, scrollerHeight)) { // using scrollbars?
23111
23112
23113
23114					// make the all-day and header rows lines up
23115
23116					compensateScroll(this.noScrollRowEls, getScrollbarWidths(this.scrollerEl));
23117
23118
23119
23120					// the scrollbar compensation might have changed text flow, which might affect height, so recalculate
23121
23122					// and reapply the desired height to the scroller.
23123
23124					scrollerHeight = this.computeScrollerHeight(totalHeight);
23125
23126					this.scrollerEl.height(scrollerHeight);
23127
23128				}
23129
23130				else { // no scrollbars
23131
23132					// still, force a height and display the bottom rule (marks the end of day)
23133
23134					this.scrollerEl.height(scrollerHeight).css('overflow', 'hidden'); // in case <hr> goes outside
23135
23136					this.bottomRuleEl.show();
23137
23138				}
23139
23140			}
23141
23142		},
23143
23144
23145
23146
23147
23148		// Computes the initial pre-configured scroll state prior to allowing the user to change it
23149
23150		computeInitialScroll: function() {
23151
23152			var scrollTime = moment.duration(this.opt('scrollTime'));
23153
23154			var top = this.timeGrid.computeTimeTop(scrollTime);
23155
23156
23157
23158			// zoom can give weird floating-point values. rather scroll a little bit further
23159
23160			top = Math.ceil(top);
23161
23162
23163
23164			if (top) {
23165
23166				top++; // to overcome top border that slots beyond the first have. looks better
23167
23168			}
23169
23170
23171
23172			return top;
23173
23174		},
23175
23176
23177
23178
23179
23180		/* Hit Areas
23181
23182		 ------------------------------------------------------------------------------------------------------------------*/
23183
23184		// forward all hit-related method calls to the grids (dayGrid might not be defined)
23185
23186
23187
23188
23189
23190		prepareHits: function() {
23191
23192			this.timeGrid.prepareHits();
23193
23194			if (this.dayGrid) {
23195
23196				this.dayGrid.prepareHits();
23197
23198			}
23199
23200		},
23201
23202
23203
23204
23205
23206		releaseHits: function() {
23207
23208			this.timeGrid.releaseHits();
23209
23210			if (this.dayGrid) {
23211
23212				this.dayGrid.releaseHits();
23213
23214			}
23215
23216		},
23217
23218
23219
23220
23221
23222		queryHit: function(left, top) {
23223
23224			var hit = this.timeGrid.queryHit(left, top);
23225
23226
23227
23228			if (!hit && this.dayGrid) {
23229
23230				hit = this.dayGrid.queryHit(left, top);
23231
23232			}
23233
23234
23235
23236			return hit;
23237
23238		},
23239
23240
23241
23242
23243
23244		getHitSpan: function(hit) {
23245
23246			// TODO: hit.component is set as a hack to identify where the hit came from
23247
23248			return hit.component.getHitSpan(hit);
23249
23250		},
23251
23252
23253
23254
23255
23256		getHitEl: function(hit) {
23257
23258			// TODO: hit.component is set as a hack to identify where the hit came from
23259
23260			return hit.component.getHitEl(hit);
23261
23262		},
23263
23264
23265
23266
23267
23268		/* Events
23269
23270		 ------------------------------------------------------------------------------------------------------------------*/
23271
23272
23273
23274
23275
23276		// Renders events onto the view and populates the View's segment array
23277
23278		renderEvents: function(events) {
23279
23280			var dayEvents = [];
23281
23282			var timedEvents = [];
23283
23284			var daySegs = [];
23285
23286			var timedSegs;
23287
23288			var i;
23289
23290
23291
23292			// separate the events into all-day and timed
23293
23294			for (i = 0; i < events.length; i++) {
23295
23296				if (events[i].allDay) {
23297
23298					dayEvents.push(events[i]);
23299
23300				}
23301
23302				else {
23303
23304					timedEvents.push(events[i]);
23305
23306				}
23307
23308			}
23309
23310
23311
23312			// render the events in the subcomponents
23313
23314			timedSegs = this.timeGrid.renderEvents(timedEvents);
23315
23316			if (this.dayGrid) {
23317
23318				daySegs = this.dayGrid.renderEvents(dayEvents);
23319
23320			}
23321
23322
23323
23324			// the all-day area is flexible and might have a lot of events, so shift the height
23325
23326			this.updateHeight();
23327
23328		},
23329
23330
23331
23332
23333
23334		// Retrieves all segment objects that are rendered in the view
23335
23336		getEventSegs: function() {
23337
23338			return this.timeGrid.getEventSegs().concat(
23339
23340				this.dayGrid ? this.dayGrid.getEventSegs() : []
23341
23342			);
23343
23344		},
23345
23346
23347
23348
23349
23350		// Unrenders all event elements and clears internal segment data
23351
23352		unrenderEvents: function() {
23353
23354
23355
23356			// unrender the events in the subcomponents
23357
23358			this.timeGrid.unrenderEvents();
23359
23360			if (this.dayGrid) {
23361
23362				this.dayGrid.unrenderEvents();
23363
23364			}
23365
23366
23367
23368			// we DON'T need to call updateHeight() because:
23369
23370			// A) a renderEvents() call always happens after this, which will eventually call updateHeight()
23371
23372			// B) in IE8, this causes a flash whenever events are rerendered
23373
23374		},
23375
23376
23377
23378
23379
23380		/* Dragging (for events and external elements)
23381
23382		 ------------------------------------------------------------------------------------------------------------------*/
23383
23384
23385
23386
23387
23388		// A returned value of `true` signals that a mock "helper" event has been rendered.
23389
23390		renderDrag: function(dropLocation, seg) {
23391
23392			if (dropLocation.start.hasTime()) {
23393
23394				return this.timeGrid.renderDrag(dropLocation, seg);
23395
23396			}
23397
23398			else if (this.dayGrid) {
23399
23400				return this.dayGrid.renderDrag(dropLocation, seg);
23401
23402			}
23403
23404		},
23405
23406
23407
23408
23409
23410		unrenderDrag: function() {
23411
23412			this.timeGrid.unrenderDrag();
23413
23414			if (this.dayGrid) {
23415
23416				this.dayGrid.unrenderDrag();
23417
23418			}
23419
23420		},
23421
23422
23423
23424
23425
23426		/* Selection
23427
23428		 ------------------------------------------------------------------------------------------------------------------*/
23429
23430
23431
23432
23433
23434		// Renders a visual indication of a selection
23435
23436		renderSelection: function(span) {
23437
23438			if (span.start.hasTime() || span.end.hasTime()) {
23439
23440				this.timeGrid.renderSelection(span);
23441
23442			}
23443
23444			else if (this.dayGrid) {
23445
23446				this.dayGrid.renderSelection(span);
23447
23448			}
23449
23450		},
23451
23452
23453
23454
23455
23456		// Unrenders a visual indications of a selection
23457
23458		unrenderSelection: function() {
23459
23460			this.timeGrid.unrenderSelection();
23461
23462			if (this.dayGrid) {
23463
23464				this.dayGrid.unrenderSelection();
23465
23466			}
23467
23468		}
23469
23470
23471
23472	});
23473
23474
23475
23476
23477
23478// Methods that will customize the rendering behavior of the AgendaView's timeGrid
23479
23480	var agendaTimeGridMethods = {
23481
23482
23483
23484
23485
23486		// Generates the HTML that will go before the day-of week header cells
23487
23488		renderHeadIntroHtml: function() {
23489
23490			var view = this.view;
23491
23492			var weekText;
23493
23494
23495
23496			if (view.opt('weekNumbers')) {
23497
23498				weekText = this.start.format(view.opt('smallWeekFormat'));
23499
23500
23501
23502				return '' +
23503
23504					'<th class="fc-axis fc-week-number ' + view.widgetHeaderClass + '" ' + view.axisStyleAttr() + '>' +
23505
23506					'<span>' + // needed for matchCellWidths
23507
23508					htmlEscape(weekText) +
23509
23510					'</span>' +
23511
23512					'</th>';
23513
23514			}
23515
23516			else {
23517
23518				return '<th class="fc-axis ' + view.widgetHeaderClass + '" ' + view.axisStyleAttr() + '></th>';
23519
23520			}
23521
23522		},
23523
23524
23525
23526
23527
23528		// Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column.
23529
23530		renderBgIntroHtml: function() {
23531
23532			var view = this.view;
23533
23534
23535
23536			return '<td class="fc-axis ' + view.widgetContentClass + '" ' + view.axisStyleAttr() + '></td>';
23537
23538		},
23539
23540
23541
23542
23543
23544		// Generates the HTML that goes before all other types of cells.
23545
23546		// Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
23547
23548		renderIntroHtml: function() {
23549
23550			var view = this.view;
23551
23552
23553
23554			return '<td class="fc-axis" ' + view.axisStyleAttr() + '></td>';
23555
23556		}
23557
23558
23559
23560	};
23561
23562
23563
23564
23565
23566// Methods that will customize the rendering behavior of the AgendaView's dayGrid
23567
23568	var agendaDayGridMethods = {
23569
23570
23571
23572
23573
23574		// Generates the HTML that goes before the all-day cells
23575
23576		renderBgIntroHtml: function() {
23577
23578			var view = this.view;
23579
23580
23581
23582			return '' +
23583
23584				'<td class="fc-axis ' + view.widgetContentClass + '" ' + view.axisStyleAttr() + '>' +
23585
23586				'<span>' + // needed for matchCellWidths
23587
23588				(view.opt('allDayHtml') || htmlEscape(view.opt('allDayText'))) +
23589
23590				'</span>' +
23591
23592				'</td>';
23593
23594		},
23595
23596
23597
23598
23599
23600		// Generates the HTML that goes before all other types of cells.
23601
23602		// Affects content-skeleton, helper-skeleton, highlight-skeleton for both the time-grid and day-grid.
23603
23604		renderIntroHtml: function() {
23605
23606			var view = this.view;
23607
23608
23609
23610			return '<td class="fc-axis" ' + view.axisStyleAttr() + '></td>';
23611
23612		}
23613
23614
23615
23616	};
23617
23618
23619
23620	;;
23621
23622
23623
23624	var AGENDA_ALL_DAY_EVENT_LIMIT = 5;
23625
23626
23627
23628// potential nice values for the slot-duration and interval-duration
23629
23630// from largest to smallest
23631
23632	var AGENDA_STOCK_SUB_DURATIONS = [
23633
23634		{ hours: 1 },
23635
23636		{ minutes: 30 },
23637
23638		{ minutes: 15 },
23639
23640		{ seconds: 30 },
23641
23642		{ seconds: 15 }
23643
23644	];
23645
23646
23647
23648	fcViews.agenda = {
23649
23650		'class': AgendaView,
23651
23652		defaults: {
23653
23654			allDaySlot: true,
23655
23656			allDayText: 'all-day',
23657
23658			slotDuration: '00:30:00',
23659
23660			minTime: '00:00:00',
23661
23662			maxTime: '24:00:00',
23663
23664			slotEventOverlap: true // a bad name. confused with overlap/constraint system
23665
23666		}
23667
23668	};
23669
23670
23671
23672	fcViews.agendaDay = {
23673
23674		type: 'agenda',
23675
23676		duration: { days: 1 }
23677
23678	};
23679
23680
23681
23682	fcViews.agendaWeek = {
23683
23684		type: 'agenda',
23685
23686		duration: { weeks: 1 }
23687
23688	};
23689
23690	;;
23691
23692
23693
23694	return FC; // export for Node/CommonJS
23695
23696});
23697
23698
23699!function(a){"function"==typeof define&&define.amd?define(["jquery","moment"],a):"object"==typeof exports?module.exports=a(require("jquery"),require("moment")):a(jQuery,moment)}(function(a,b){!function(){"use strict";var a=(b.defineLocale||b.lang).call(b,"zh-cn",{months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"日_一_二_三_四_五_六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah点mm分",LTS:"Ah点m分s秒",L:"YYYY-MM-DD",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah点mm分",LLLL:"YYYY年MMMD日ddddAh点mm分",l:"YYYY-MM-DD",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah点mm分",llll:"YYYY年MMMD日ddddAh点mm分"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"凌晨"===b||"早上"===b||"上午"===b?a:"下午"===b||"晚上"===b?a+12:a>=11?a:a+12},meridiem:function(a,b,c){var d=100*a+b;return 600>
23699d?"凌晨":900>d?"早上":1130>d?"上午":1230>d?"中午":1800>d?"下午":"晚上"},calendar:{sameDay:function(){return 0===this.minutes()?"[今天]Ah[点整]":"[今天]LT"},nextDay:function(){return 0===this.minutes()?"[明天]Ah[点整]":"[明天]LT"},lastDay:function(){return 0===this.minutes()?"[昨天]Ah[点整]":"[昨天]LT"},nextWeek:function(){var a,c;return a=b().startOf("week"),c=this.unix()-a.unix()>=604800?"[下]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},lastWeek:function(){var a,c;return a=b().startOf("week"),c=this.unix()<a.unix()?"[上]":"[本]",0===this.minutes()?c+"dddAh点整":c+"dddAh点mm"},sameElse:"LL"},ordinalParse:/\d{1,2}(日|月|周)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"周";default:return a}},relativeTime:{future:"%s内",past:"%s前",s:"几秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}});return a}(),a.fullCalendar.datepickerLang("zh-cn","zh-CN",{closeText:"关闭",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthNamesShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["日","一","二","三","四","五","六"],dayNamesMin:["日","一","二","三","四","五","六"],weekHeader:"周",dateFormat:"yy-mm-dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"年"}),a.fullCalendar.lang("zh-cn",{buttonText:{month:"月",week:"周",day:"日",list:"日程"},allDayText:"全天",eventLimitText:function(a){return"另外 "+a+" 个"}})});
23700!function(a){"function"==typeof define&&define.amd?define(["jquery","moment"],a):"object"==typeof exports?module.exports=a(require("jquery"),require("moment")):a(jQuery,moment)}(function(a,b){!function(){"use strict";var a=(b.defineLocale||b.lang).call(b,"zh-tw",{months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"日_一_二_三_四_五_六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"Ah點mm分",LTS:"Ah點m分s秒",L:"YYYY年MMMD日",LL:"YYYY年MMMD日",LLL:"YYYY年MMMD日Ah點mm分",LLLL:"YYYY年MMMD日ddddAh點mm分",l:"YYYY年MMMD日",ll:"YYYY年MMMD日",lll:"YYYY年MMMD日Ah點mm分",llll:"YYYY年MMMD日ddddAh點mm分"},meridiemParse:/早上|上午|中午|下午|晚上/,meridiemHour:function(a,b){return 12===a&&(a=0),"早上"===b||"上午"===b?a:"中午"===b?a>=11?a:a+12:"下午"===b||"晚上"===b?a+12:void 0},meridiem:function(a,b,c){var d=100*a+b;return 900>d?"早上":1130>d?"上午":1230>d?"中午":1800>d?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},ordinalParse:/\d{1,2}(日|月|週)/,ordinal:function(a,b){switch(b){case"d":case"D":case"DDD":return a+"日";case"M":return a+"月";case"w":case"W":return a+"週";default:return a}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",m:"一分鐘",mm:"%d分鐘",h:"一小時",hh:"%d小時",d:"一天",dd:"%d天",M:"一個月",MM:"%d個月",y:"一年",yy:"%d年"}});return a}(),a.fullCalendar.datepickerLang("zh-tw","zh-TW",{closeText:"關閉",prevText:"&#x3C;上月",nextText:"下月&#x3E;",currentText:"今天",monthNames:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],monthNamesShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayNames:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayNamesShort:["日","一","二","三","四","五","六"],dayNamesMin:["日","一","二","三","四","五","六"],weekHeader:"周",dateFormat:"yy/mm/dd",firstDay:1,isRTL:!1,showMonthAfterYear:!0,yearSuffix:"年"}),a.fullCalendar.lang("zh-tw",{buttonText:{month:"月",week:"週",day:"天",list:"待辦事項"},allDayText:"全天",eventLimitText:"更多"})});
23701!function(a){function b(){return new Date(Date.UTC.apply(Date,arguments))}var c=function(b,c){var f=this;this.element=a(b),this.autoShow=c.autoShow||!0,this.appendTo=c.appendTo||"body",this.closeButton=c.closeButton,this.language=c.language||this.element.data("date-language")||"en",this.language=this.language in d?this.language:this.language.split("-")[0],this.language=this.language in d?this.language:"en",this.isRTL=d[this.language].rtl||!1,this.format=e.parseFormat(c.format||this.element.data("date-format")||d[this.language].format||"mm/dd/yyyy"),this.isInline=!1,this.isInput=this.element.is("input"),this.component=this.element.is(".date")?this.element.find(".prefix, .postfix"):!1,this.hasInput=this.component&&this.element.find("input").length,this.disableDblClickSelection=c.disableDblClickSelection,this.onRender=c.onRender||function(){},this.component&&0===this.component.length&&(this.component=!1),this.linkField=c.linkField||this.element.data("link-field")||!1,this.linkFormat=e.parseFormat(c.linkFormat||this.element.data("link-format")||"yyyy-mm-dd hh:ii:ss"),this.minuteStep=c.minuteStep||this.element.data("minute-step")||5,this.pickerPosition=c.pickerPosition||this.element.data("picker-position")||"bottom-right",this.initialDate=c.initialDate||null,this._attachEvents(),this.minView=0,"minView"in c?this.minView=c.minView:"minView"in this.element.data()&&(this.minView=this.element.data("min-view")),this.minView=e.convertViewMode(this.minView),this.maxView=e.modes.length-1,"maxView"in c?this.maxView=c.maxView:"maxView"in this.element.data()&&(this.maxView=this.element.data("max-view")),this.maxView=e.convertViewMode(this.maxView),this.startViewMode="month","startView"in c?this.startViewMode=c.startView:"startView"in this.element.data()&&(this.startViewMode=this.element.data("start-view")),this.startViewMode=e.convertViewMode(this.startViewMode),this.viewMode=this.startViewMode,"minView"in c||"maxView"in c||this.element.data("min-view")&&!this.element.data("max-view")||(this.pickTime=!1,"pickTime"in c&&(this.pickTime=c.pickTime),1==this.pickTime?(this.minView=0,this.maxView=4):(this.minView=2,this.maxView=4)),this.forceParse=!0,"forceParse"in c?this.forceParse=c.forceParse:"dateForceParse"in this.element.data()&&(this.forceParse=this.element.data("date-force-parse")),this.picker=a(e.template).appendTo(this.isInline?this.element:this.appendTo).on({click:a.proxy(this.click,this),mousedown:a.proxy(this.mousedown,this)}),this.closeButton?this.picker.find("a.datepicker-close").show():this.picker.find("a.datepicker-close").hide(),this.isInline?this.picker.addClass("datepicker-inline"):this.picker.addClass("datepicker-dropdown dropdown-menu"),this.isRTL&&(this.picker.addClass("datepicker-rtl"),this.picker.find(".prev i, .next i").toggleClass("fa-chevron-left fa-chevron-right")),a(document).on("mousedown",function(b){0===a(b.target).closest(".datepicker.datepicker-inline, .datepicker.datepicker-dropdown").length&&f.hide()}),this.autoclose=!0,"autoclose"in c?this.autoclose=c.autoclose:"dateAutoclose"in this.element.data()&&(this.autoclose=this.element.data("date-autoclose")),this.keyboardNavigation=!0,"keyboardNavigation"in c?this.keyboardNavigation=c.keyboardNavigation:"dateKeyboardNavigation"in this.element.data()&&(this.keyboardNavigation=this.element.data("date-keyboard-navigation")),this.todayBtn=c.todayBtn||this.element.data("date-today-btn")||!1,this.todayHighlight=c.todayHighlight||this.element.data("date-today-highlight")||!1,this.calendarWeeks=!1,"calendarWeeks"in c?this.calendarWeeks=c.calendarWeeks:"dateCalendarWeeks"in this.element.data()&&(this.calendarWeeks=this.element.data("date-calendar-weeks")),this.calendarWeeks&&this.picker.find("tfoot th.today").attr("colspan",function(a,b){return parseInt(b)+1}),this.weekStart=(c.weekStart||this.element.data("date-weekstart")||d[this.language].weekStart||0)%7,this.weekEnd=(this.weekStart+6)%7,this.startDate=-(1/0),this.endDate=1/0,this.daysOfWeekDisabled=[],this.setStartDate(c.startDate||this.element.data("date-startdate")),this.setEndDate(c.endDate||this.element.data("date-enddate")),this.setDaysOfWeekDisabled(c.daysOfWeekDisabled||this.element.data("date-days-of-week-disabled")),this.fillDow(),this.fillMonths(),this.update(),this.showMode(),this.isInline&&this.show()};c.prototype={constructor:c,_events:[],_attachEvents:function(){this._detachEvents(),this.isInput?this._events=[[this.element,{focus:this.autoShow?a.proxy(this.show,this):function(){},keyup:a.proxy(this.update,this),keydown:a.proxy(this.keydown,this)}]]:this.component&&this.hasInput?this._events=[[this.element.find("input"),{focus:this.autoShow?a.proxy(this.show,this):function(){},keyup:a.proxy(this.update,this),keydown:a.proxy(this.keydown,this)}],[this.component,{click:a.proxy(this.show,this)}]]:this.element.is("div")?this.isInline=!0:this._events=[[this.element,{click:a.proxy(this.show,this)}]],this.disableDblClickSelection&&(this._events[this._events.length]=[this.element,{dblclick:function(b){b.preventDefault(),b.stopPropagation(),a(this).blur()}}]);for(var b,c,d=0;d<this._events.length;d++)b=this._events[d][0],c=this._events[d][1],b.on(c)},_detachEvents:function(){for(var a,b,c=0;c<this._events.length;c++)a=this._events[c][0],b=this._events[c][1],a.off(b);this._events=[]},show:function(b){this.picker.show(),this.height=this.component?this.component.outerHeight():this.element.outerHeight(),this.update(),this.place(),a(window).on("resize",a.proxy(this.place,this)),b&&(b.stopPropagation(),b.preventDefault()),this.element.trigger({type:"show",date:this.date})},hide:function(b){this.isInline||this.picker.is(":visible")&&(this.picker.hide(),a(window).off("resize",this.place),this.viewMode=this.startViewMode,this.showMode(),this.isInput||a(document).off("mousedown",this.hide),this.forceParse&&(this.isInput&&this.element.val()||this.hasInput&&this.element.find("input").val())&&this.setValue(),this.element.trigger({type:"hide",date:this.date}))},remove:function(){this._detachEvents(),this.picker.remove(),delete this.element.data().datepicker},getDate:function(){var a=this.getUTCDate();return new Date(a.getTime()+6e4*a.getTimezoneOffset())},getUTCDate:function(){return this.date},setDate:function(a){this.setUTCDate(new Date(a.getTime()-6e4*a.getTimezoneOffset()))},setUTCDate:function(a){this.date=a,this.setValue()},setValue:function(){var a=this.getFormattedDate();this.isInput?this.element.val(a):(this.component&&this.element.find("input").val(a),this.element.data("date",a))},getFormattedDate:function(a){return void 0===a&&(a=this.format),e.formatDate(this.date,a,this.language)},setStartDate:function(a){this.startDate=a||-(1/0),this.startDate!==-(1/0)&&(this.startDate=e.parseDate(this.startDate,this.format,this.language)),this.update(),this.updateNavArrows()},setEndDate:function(a){this.endDate=a||1/0,this.endDate!==1/0&&(this.endDate=e.parseDate(this.endDate,this.format,this.language)),this.update(),this.updateNavArrows()},setDaysOfWeekDisabled:function(b){this.daysOfWeekDisabled=b||[],a.isArray(this.daysOfWeekDisabled)||(this.daysOfWeekDisabled=this.daysOfWeekDisabled.split(/,\s*/)),this.daysOfWeekDisabled=a.map(this.daysOfWeekDisabled,function(a){return parseInt(a,10)}),this.update(),this.updateNavArrows()},place:function(){if(!this.isInline){var b=parseInt(this.element.parents().filter(function(){return"auto"!=a(this).css("z-index")}).first().css("z-index"))+10,c=this.component?this.component:this.element,d=c.offset(),e=c.outerHeight()+parseInt(c.css("margin-top")),f=c.outerWidth()+parseInt(c.css("margin-left")),g=d.top+e,h=d.left;g+this.picker.outerHeight()>=a(window).scrollTop()+a(window).height()&&(g=d.top-this.picker.outerHeight()),d.left+this.picker.width()>=a(window).width()&&(h=d.left+f-this.picker.width()),this.picker.css({top:g,left:h,zIndex:b})}},update:function(){var a,b=!1;arguments&&arguments.length&&("string"==typeof arguments[0]||arguments[0]instanceof Date)?(a=arguments[0],b=!0):a=null!=this.initialDate?this.initialDate:this.isInput?this.element.val():this.element.data("date")||this.element.find("input").val(),this.date=e.parseDate(a,this.format,this.language),(b||null!=this.initialDate)&&this.setValue(),this.date<this.startDate?this.viewDate=new Date(this.startDate.valueOf()):this.date>this.endDate?this.viewDate=new Date(this.endDate.valueOf()):this.viewDate=new Date(this.date.valueOf()),this.fill()},fillDow:function(){var a=this.weekStart,b="<tr>";if(this.calendarWeeks){var c='<th class="cw">&nbsp;</th>';b+=c,this.picker.find(".datepicker-days thead tr:first-child").prepend(c)}for(;a<this.weekStart+7;)b+='<th class="dow">'+d[this.language].daysMin[a++%7]+"</th>";b+="</tr>",this.picker.find(".datepicker-days thead").append(b)},fillMonths:function(){for(var a="",b=0;12>b;)a+='<span class="month">'+d[this.language].monthsShort[b++]+"</span>";this.picker.find(".datepicker-months td").html(a)},fill:function(){if(null!=this.date&&null!=this.viewDate){var c=new Date(this.viewDate.valueOf()),f=c.getUTCFullYear(),g=c.getUTCMonth(),h=c.getUTCDate(),i=c.getUTCHours(),j=c.getUTCMinutes(),k=this.startDate!==-(1/0)?this.startDate.getUTCFullYear():-(1/0),l=this.startDate!==-(1/0)?this.startDate.getUTCMonth():-(1/0),m=this.endDate!==1/0?this.endDate.getUTCFullYear():1/0,n=this.endDate!==1/0?this.endDate.getUTCMonth():1/0,o=this.date&&this.date.valueOf(),p=new Date;d[this.language].titleFormat||d.en.titleFormat;this.picker.find(".datepicker-days thead th:eq(1)").text(d[this.language].months[g]+" "+f),this.picker.find(".datepicker-hours thead th:eq(1)").text(h+" "+d[this.language].months[g]+" "+f),this.picker.find(".datepicker-minutes thead th:eq(1)").text(h+" "+d[this.language].months[g]+" "+f),this.picker.find("tfoot th.today").text(d[this.language].today).toggle(this.todayBtn!==!1),this.updateNavArrows(),this.fillMonths();var q=b(f,g-1,28,0,0,0,0),r=e.getDaysInMonth(q.getUTCFullYear(),q.getUTCMonth());q.setUTCDate(r),q.setUTCDate(r-(q.getUTCDay()-this.weekStart+7)%7);var s=new Date(q.valueOf());s.setUTCDate(s.getUTCDate()+42),s=s.valueOf();for(var t,u=[];q.valueOf()<s;){if(q.getUTCDay()==this.weekStart&&(u.push("<tr>"),this.calendarWeeks)){var v=new Date(q.getUTCFullYear(),q.getUTCMonth(),q.getUTCDate()-q.getDay()+10-(this.weekStart&&this.weekStart%7<5&&7)),w=new Date(v.getFullYear(),0,4),x=~~((v-w)/864e5/7+1.5);u.push('<td class="cw">'+x+"</td>")}t=" "+this.onRender(q)+" ",q.getUTCFullYear()<f||q.getUTCFullYear()==f&&q.getUTCMonth()<g?t+=" old":(q.getUTCFullYear()>f||q.getUTCFullYear()==f&&q.getUTCMonth()>g)&&(t+=" new"),this.todayHighlight&&q.getUTCFullYear()==p.getFullYear()&&q.getUTCMonth()==p.getMonth()&&q.getUTCDate()==p.getDate()&&(t+=" today"),o&&q.valueOf()==o&&(t+=" active"),(q.valueOf()<this.startDate||q.valueOf()>this.endDate||-1!==a.inArray(q.getUTCDay(),this.daysOfWeekDisabled))&&(t+=" disabled"),u.push('<td class="day'+t+'">'+q.getUTCDate()+"</td>"),q.getUTCDay()==this.weekEnd&&u.push("</tr>"),q.setUTCDate(q.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(u.join("")),u=[];for(var y=0;24>y;y++){var z=b(f,g,h,y);t="",z.valueOf()+36e5<this.startDate||z.valueOf()>this.endDate?t+=" disabled":i==y&&(t+=" active"),u.push('<span class="hour'+t+'">'+y+":00</span>")}this.picker.find(".datepicker-hours td").html(u.join("")),u=[];for(var y=0;60>y;y+=this.minuteStep){var z=b(f,g,h,i,y);t="",z.valueOf()<this.startDate||z.valueOf()>this.endDate?t+=" disabled":Math.floor(j/this.minuteStep)==Math.floor(y/this.minuteStep)&&(t+=" active"),u.push('<span class="minute'+t+'">'+i+":"+(10>y?"0"+y:y)+"</span>")}this.picker.find(".datepicker-minutes td").html(u.join(""));var A=this.date&&this.date.getUTCFullYear(),B=this.picker.find(".datepicker-months").find("th:eq(1)").text(f).end().find("span").removeClass("active");A&&A==f&&B.eq(this.date.getUTCMonth()).addClass("active"),(k>f||f>m)&&B.addClass("disabled"),f==k&&B.slice(0,l).addClass("disabled"),f==m&&B.slice(n+1).addClass("disabled"),u="",f=10*parseInt(f/10,10);
23701var C=this.picker.find(".datepicker-years").find("th:eq(1)").text(f+"-"+(f+9)).end().find("td");f-=1;for(var y=-1;11>y;y++)u+='<span class="year'+(-1==y||10==y?" old":"")+(A==f?" active":"")+(k>f||f>m?" disabled":"")+'">'+f+"</span>",f+=1;C.html(u)}},updateNavArrows:function(){var a=new Date(this.viewDate),b=a.getUTCFullYear(),c=a.getUTCMonth(),d=a.getUTCDate(),e=a.getUTCHours();switch(this.viewMode){case 0:this.startDate!==-(1/0)&&b<=this.startDate.getUTCFullYear()&&c<=this.startDate.getUTCMonth()&&d<=this.startDate.getUTCDate()&&e<=this.startDate.getUTCHours()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.endDate!==1/0&&b>=this.endDate.getUTCFullYear()&&c>=this.endDate.getUTCMonth()&&d>=this.endDate.getUTCDate()&&e>=this.endDate.getUTCHours()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:this.startDate!==-(1/0)&&b<=this.startDate.getUTCFullYear()&&c<=this.startDate.getUTCMonth()&&d<=this.startDate.getUTCDate()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.endDate!==1/0&&b>=this.endDate.getUTCFullYear()&&c>=this.endDate.getUTCMonth()&&d>=this.endDate.getUTCDate()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 2:this.startDate!==-(1/0)&&b<=this.startDate.getUTCFullYear()&&c<=this.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.endDate!==1/0&&b>=this.endDate.getUTCFullYear()&&c>=this.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 3:case 4:this.startDate!==-(1/0)&&b<=this.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.endDate!==1/0&&b>=this.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}},click:function(c){c.stopPropagation(),c.preventDefault(),(a(c.target).hasClass("datepicker-close")||a(c.target).parent().hasClass("datepicker-close"))&&this.hide();var d=a(c.target).closest("span, td, th");if(1==d.length){if(d.is(".disabled"))return void this.element.trigger({type:"outOfRange",date:this.viewDate,startDate:this.startDate,endDate:this.endDate});switch(d[0].nodeName.toLowerCase()){case"th":switch(d[0].className){case"date-switch":this.showMode(1);break;case"prev":case"next":var f=e.modes[this.viewMode].navStep*("prev"==d[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveHour(this.viewDate,f);break;case 1:this.viewDate=this.moveDate(this.viewDate,f);break;case 2:this.viewDate=this.moveMonth(this.viewDate,f);break;case 3:case 4:this.viewDate=this.moveYear(this.viewDate,f)}this.fill();break;case"today":var g=new Date;g=b(g.getFullYear(),g.getMonth(),g.getDate(),g.getHours(),g.getMinutes(),g.getSeconds()),this.viewMode=this.startViewMode,this.showMode(0),this._setDate(g)}break;case"span":if(!d.is(".disabled")){if(d.is(".month"))if(3===this.minView){var h=d.parent().find("span").index(d)||0,i=this.viewDate.getUTCFullYear(),j=1,k=this.viewDate.getUTCHours(),l=this.viewDate.getUTCMinutes(),m=this.viewDate.getUTCSeconds();this._setDate(b(i,h,j,k,l,m,0))}else{this.viewDate.setUTCDate(1);var h=d.parent().find("span").index(d);this.viewDate.setUTCMonth(h),this.element.trigger({type:"changeMonth",date:this.viewDate})}else if(d.is(".year"))if(4===this.minView){var i=parseInt(d.text(),10)||0,h=0,j=1,k=this.viewDate.getUTCHours(),l=this.viewDate.getUTCMinutes(),m=this.viewDate.getUTCSeconds();this._setDate(b(i,h,j,k,l,m,0))}else{this.viewDate.setUTCDate(1);var i=parseInt(d.text(),10)||0;this.viewDate.setUTCFullYear(i),this.element.trigger({type:"changeYear",date:this.viewDate})}else if(d.is(".hour")){var k=parseInt(d.text(),10)||0,i=this.viewDate.getUTCFullYear(),h=this.viewDate.getUTCMonth(),j=this.viewDate.getUTCDate(),l=this.viewDate.getUTCMinutes(),m=this.viewDate.getUTCSeconds();this._setDate(b(i,h,j,k,l,m,0))}else if(d.is(".minute")){var l=parseInt(d.text().substr(d.text().indexOf(":")+1),10)||0,i=this.viewDate.getUTCFullYear(),h=this.viewDate.getUTCMonth(),j=this.viewDate.getUTCDate(),k=this.viewDate.getUTCHours(),m=this.viewDate.getUTCSeconds();this._setDate(b(i,h,j,k,l,m,0))}if(0!=this.viewMode){var n=this.viewMode;this.showMode(-1),this.fill(),n==this.viewMode&&this.autoclose&&this.hide()}else this.fill(),this.autoclose&&this.hide()}break;case"td":if(d.is(".day")&&!d.is(".disabled")){var j=parseInt(d.text(),10)||1,i=this.viewDate.getUTCFullYear(),h=this.viewDate.getUTCMonth(),k=this.viewDate.getUTCHours(),l=this.viewDate.getUTCMinutes(),m=this.viewDate.getUTCSeconds();d.is(".old")?0===h?(h=11,i-=1):h-=1:d.is(".new")&&(11==h?(h=0,i+=1):h+=1),this._setDate(b(i,h,j,k,l,m,0))}var n=this.viewMode;this.showMode(-1),this.fill(),n==this.viewMode&&this.autoclose&&this.hide()}}},_setDate:function(a,b){b&&"date"!=b||(this.date=a),b&&"view"!=b||(this.viewDate=a),this.fill(),this.setValue(),this.element.trigger({type:"changeDate",date:this.date});var c;this.isInput?c=this.element:this.component&&(c=this.element.find("input")),c&&(c.change(),this.autoclose&&(!b||"date"==b))},moveHour:function(a,b){if(!b)return a;var c=new Date(a.valueOf());return b=b>0?1:-1,c.setUTCHours(c.getUTCHours()+b),c},moveDate:function(a,b){if(!b)return a;var c=new Date(a.valueOf());return b=b>0?1:-1,c.setUTCDate(c.getUTCDate()+b),c},moveMonth:function(a,b){if(!b)return a;var c,d,e=new Date(a.valueOf()),f=e.getUTCDate(),g=e.getUTCMonth(),h=Math.abs(b);
vendor: 5,256 bytes, line 23701
23701if(b=b>0?1:-1,1==h)d=-1==b?function(){return e.getUTCMonth()==g}:function(){return e.getUTCMonth()!=c},c=g+b,e.setUTCMonth(c),(0>c||c>11)&&(c=(c+12)%12);else{for(var i=0;h>i;i++)e=this.moveMonth(e,b);c=e.getUTCMonth(),e.setUTCDate(f),d=function(){return c!=e.getUTCMonth()}}for(;d();)e.setUTCDate(--f),e.setUTCMonth(c);return e},moveYear:function(a,b){return this.moveMonth(a,12*b)},dateWithinRange:function(a){return a>=this.startDate&&a<=this.endDate},keydown:function(a){if(this.picker.is(":not(:visible)"))return void(27==a.keyCode&&this.show());var b,c,d,e=!1;switch(a.keyCode){case 27:this.hide(),a.preventDefault();break;case 37:case 39:if(!this.keyboardNavigation)break;b=37==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date.valueOf()),c.setUTCDate(this.date.getUTCDate()+b),d=new Date(this.viewDate.valueOf()),d.setUTCDate(this.viewDate.getUTCDate()+b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 38:case 40:if(!this.keyboardNavigation)break;b=38==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date.valueOf()),c.setUTCDate(this.date.getUTCDate()+7*b),d=new Date(this.viewDate.valueOf()),d.setUTCDate(this.viewDate.getUTCDate()+7*b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 13:this.hide(),a.preventDefault();break;case 9:this.hide()}if(e){this.element.trigger({type:"changeDate",date:this.date});var f;this.isInput?f=this.element:this.component&&(f=this.element.find("input")),f&&f.change()}},showMode:function(a){if(a){var b=Math.max(0,Math.min(e.modes.length-1,this.viewMode+a));b>=this.minView&&b<=this.maxView&&(this.viewMode=b)}this.picker.find(">div").hide().filter(".datepicker-"+e.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()},reset:function(a){this._setDate(null,"date")}},a.fn.fdatepicker=function(b){var d=Array.apply(null,arguments);return d.shift(),this.each(function(){var e=a(this),f=e.data("datepicker"),g="object"==typeof b&&b;f||e.data("datepicker",f=new c(this,a.extend({},a.fn.fdatepicker.defaults,g))),"string"==typeof b&&"function"==typeof f[b]&&f[b].apply(f,d)})},a.fn.fdatepicker.defaults={onRender:function(a){return""}},a.fn.fdatepicker.Constructor=c;var d=a.fn.fdatepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",titleFormat:"MM yyyy"}},e={modes:[{clsName:"minutes",navFnc:"Hours",navStep:1},{clsName:"hours",navFnc:"Date",navStep:1},{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(a){return a%4===0&&a%100!==0||a%400===0},getDaysInMonth:function(a,b){return[31,e.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]},validParts:/hh?|ii?|ss?|dd?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(a){var b=a.replace(this.validParts,"\x00").split("\x00"),c=a.match(this.validParts);if(!b||!b.length||!c||0===c.length)throw new Error("Invalid date format.");return{separators:b,parts:c}},parseDate:function(c,e,f){if(c instanceof Date)return new Date(c.valueOf()-6e4*c.getTimezoneOffset());if(/^\d{4}\-\d{1,2}\-\d{1,2}$/.test(c)&&(e=this.parseFormat("yyyy-mm-dd")),/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}$/.test(c)&&(e=this.parseFormat("yyyy-mm-dd hh:ii")),/^\d{4}\-\d{1,2}\-\d{1,2}[T ]\d{1,2}\:\d{1,2}\:\d{1,2}[Z]{0,1}$/.test(c)&&(e=this.parseFormat("yyyy-mm-dd hh:ii:ss")),/^[-+]\d+[dmwy]([\s,]+[-+]\d+[dmwy])*$/.test(c)){var g,h,i=/([-+]\d+)([dmwy])/,j=c.match(/([-+]\d+)([dmwy])/g);c=new Date;for(var k=0;k<j.length;k++)switch(g=i.exec(j[k]),h=parseInt(g[1]),g[2]){case"d":c.setUTCDate(c.getUTCDate()+h);break;case"m":c=Datetimepicker.prototype.moveMonth.call(Datetimepicker.prototype,c,h);break;case"w":c.setUTCDate(c.getUTCDate()+7*h);break;case"y":c=Datetimepicker.prototype.moveYear.call(Datetimepicker.prototype,c,h)}return b(c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate(),c.getUTCHours(),c.getUTCMinutes(),c.getUTCSeconds())}var l,m,g,j=c&&c.match(this.nonpunctuation)||[],c=new Date,n={},o=["hh","h","ii","i","ss","s","yyyy","yy","M","MM","m","mm","d","dd"],p={hh:function(a,b){return a.setUTCHours(b)},h:function(a,b){return a.setUTCHours(b)},ii:function(a,b){return a.setUTCMinutes(b)},i:function(a,b){return a.setUTCMinutes(b)},ss:function(a,b){return a.setUTCSeconds(b)},s:function(a,b){return a.setUTCSeconds(b)},yyyy:function(a,b){return a.setUTCFullYear(b)},yy:function(a,b){return a.setUTCFullYear(2e3+b)},m:function(a,b){for(b-=1;0>b;)b+=12;for(b%=12,a.setUTCMonth(b);a.getUTCMonth()!=b;
23701)a.setUTCDate(a.getUTCDate()-1);return a},d:function(a,b){return a.setUTCDate(b)}};if(p.M=p.MM=p.mm=p.m,p.dd=p.d,c=b(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0),j.length==e.parts.length){for(var k=0,q=e.parts.length;q>k;k++){if(l=parseInt(j[k],10),g=e.parts[k],isNaN(l))switch(g){case"MM":m=a(d[f].months).filter(function(){var a=this.slice(0,j[k].length),b=j[k].slice(0,a.length);return a==b}),l=a.inArray(m[0],d[f].months)+1;break;case"M":m=a(d[f].monthsShort).filter(function(){var a=this.slice(0,j[k].length),b=j[k].slice(0,a.length);return a==b}),l=a.inArray(m[0],d[f].monthsShort)+1}n[g]=l}for(var r,k=0;k<o.length;k++)r=o[k],r in n&&!isNaN(n[r])&&p[r](c,n[r])}return c},formatDate:function(b,c,e){if(null==b)return"";var f={h:b.getUTCHours(),i:b.getUTCMinutes(),s:b.getUTCSeconds(),d:b.getUTCDate(),m:b.getUTCMonth()+1,M:d[e].monthsShort[b.getUTCMonth()],MM:d[e].months[b.getUTCMonth()],yy:b.getUTCFullYear().toString().substring(2),yyyy:b.getUTCFullYear()};f.hh=(f.h<10?"0":"")+f.h,f.ii=(f.i<10?"0":"")+f.i,f.ss=(f.s<10?"0":"")+f.s,f.dd=(f.d<10?"0":"")+f.d,f.mm=(f.m<10?"0":"")+f.m;for(var b=[],g=a.extend([],c.separators),h=0,i=c.parts.length;i>h;h++)g.length&&b.push(g.shift()),b.push(f[c.parts[h]]);return b.join("")},convertViewMode:function(a){switch(a){case 4:case"decade":a=4;break;case 3:case"year":a=3;break;case 2:case"month":a=2;break;case 1:case"day":a=1;break;case 0:case"hour":a=0}return a},headTemplate:'<thead><tr><th class="prev"><i class="fa fa-chevron-left fi-arrow-left"/></th><th colspan="5" class="date-switch"></th><th class="next"><i class="fa fa-chevron-right fi-arrow-right"/></th></tr></thead>',contTemplate:'<tbody><tr><td colspan="7"></td></tr></tbody>',footTemplate:'<tfoot><tr><th colspan="7" class="today"></th></tr></tfoot>'};e.template='<div class="datepicker"><div class="datepicker-minutes"><table class=" table-condensed">'+e.headTemplate+e.contTemplate+e.footTemplate+'</table></div><div class="datepicker-hours"><table class=" table-condensed">'+e.headTemplate+e.contTemplate+e.footTemplate+'</table></div><div class="datepicker-days"><table class=" table-condensed">'+e.headTemplate+"<tbody></tbody>"+e.footTemplate+'</table></div><div class="datepicker-months"><table class="table-condensed">'+e.headTemplate+e.contTemplate+e.footTemplate+'</table></div><div class="datepicker-years"><table class="table-condensed">'+e.headTemplate+e.contTemplate+e.footTemplate+'</table></div><a class="button datepicker-close tiny alert right" style="width:auto;"><i class="fa fa-remove fa-times fi-x"></i></a></div>',a.fn.fdatepicker.DPGlobal=e}(window.jQuery);
23702/**
23703
23704 * Simplified Chinese translation for foundation-datepicker
23705
23706 * Yuan Cheung <[email protected]>
23707
23708 */
23709
23710;(function($){
23711
23712	$.fn.fdatepicker.dates['zh-CN'] = {
23713
23714        days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
23715
23716        daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
23717
23718        daysMin: ["日", "一", "二", "三", "四", "五", "六"],
23719
23720        months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
23721
23722        monthsShort: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"],
23723
23724        today: '今天'
23725
23726	};
23727
23728}(jQuery));
23729
23730
23731/**
23732
23733 * Traditional Chinese translation for fondation-datepicker
23734
23735 * Rung-Sheng Jang <[email protected]>
23736
23737 */
23738
23739;(function($){
23740
23741	$.fn.fdatepicker.dates['zh-TW'] = {
23742
23743        days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
23744
23745        daysShort: ["週日", "週一", "週二", "週三", "週四", "週五", "週六"],
23746
23747        daysMin: ["日", "一", "二", "三", "四", "五", "六"],
23748
23749        months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
23750
23751        monthsShort: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"],
23752
23753        today: '今天'
23754
23755	};
23756
23757}(jQuery));
23758
23759
23760/*
23761
23762 * Foundation Responsive Library
23763
23764 * http://foundation.zurb.com
23765
23766 * Copyright 2015, ZURB
23767
23768 * Free to use under the MIT license.
23769
23770 * http://www.opensource.org/licenses/mit-license.php
23771
23772*/
23773
23774!function(t,e,i,s){"use strict";function n(t){return("string"==typeof t||t instanceof String)&&(t=t.replace(/^['\\/"]+|(;\s?})+|['\\/"]+$/g,"")),t}function a(t){this.selector=t,this.query=""}var o=function(e){var i=t("head");i.prepend(t.map(e,function(t){return 0===i.has("."+t).length?'<meta class="'+t+'" />':void 0}))};o(["foundation-mq-small","foundation-mq-small-only","foundation-mq-medium","foundation-mq-medium-only","foundation-mq-large","foundation-mq-large-only","foundation-mq-xlarge","foundation-mq-xlarge-only","foundation-mq-xxlarge","foundation-data-attribute-namespace"]),t(function(){"undefined"!=typeof FastClick&&"undefined"!=typeof i.body&&FastClick.attach(i.body)});var r=function(e,s){if("string"==typeof e){if(s){var n;if(s.jquery){if(n=s[0],!n)return s}else n=s;return t(n.querySelectorAll(e))}return t(i.querySelectorAll(e))}return t(e,s)},l=function(t){var e=[];return t||e.push("data"),this.namespace.length>0&&e.push(this.namespace),e.push(this.name),e.join("-")},d=function(t){for(var e=t.split("-"),i=e.length,s=[];i--;)0!==i?s.push(e[i]):this.namespace.length>0?s.push(this.namespace,e[i]):s.push(e[i]);return s.reverse().join("-")},c=function(e,i){var s=this,n=function(){var n=r(this),a=!n.data(s.attr_name(!0)+"-init");n.data(s.attr_name(!0)+"-init",t.extend({},s.settings,i||e,s.data_options(n))),a&&s.events(this)};return r(this.scope).is("["+this.attr_name()+"]")?n.call(this.scope):r("["+this.attr_name()+"]",this.scope).each(n),"string"==typeof e?this[e].call(this,i):void 0},h=function(t,e){function i(){e(t[0])}function s(){if(this.one("load",i),/MSIE (\d+\.\d+);/.test(navigator.userAgent)){var t=this.attr("src"),e=t.match(/\?/)?"&":"?";e+="random="+(new Date).getTime(),this.attr("src",t+e)}}return t.attr("src")?void(t[0].complete||4===t[0].readyState?i():s.call(t)):void i()};/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
23775
23776e.matchMedia||(e.matchMedia=function(){var t=e.styleMedia||e.media;if(!t){var s=i.createElement("style"),n=i.getElementsByTagName("script")[0],a=null;s.type="text/css",s.id="matchmediajs-test",n.parentNode.insertBefore(s,n),a="getComputedStyle"in e&&e.getComputedStyle(s,null)||s.currentStyle,t={matchMedium:function(t){var e="@media "+t+"{ #matchmediajs-test { width: 1px; } }";return s.styleSheet?s.styleSheet.cssText=e:s.textContent=e,"1px"===a.width}}}return function(e){return{matches:t.matchMedium(e||"all"),media:e||"all"}}}()),/*
23777
23778   * jquery.requestAnimationFrame
23779
23780   * https://github.com/gnarf37/jquery-requestAnimationFrame
23781
23782   * Requires jQuery 1.8+
23783
23784   *
23785
23786   * Copyright (c) 2012 Corey Frang
23787
23788   * Licensed under the MIT license.
23789
23790   */
23791
23792function(t){function i(){s&&(o(i),l&&t.fx.tick())}for(var s,n=0,a=["webkit","moz"],o=e.requestAnimationFrame,r=e.cancelAnimationFrame,l="undefined"!=typeof t.fx;n<a.length&&!o;n++)o=e[a[n]+"RequestAnimationFrame"],r=r||e[a[n]+"CancelAnimationFrame"]||e[a[n]+"CancelRequestAnimationFrame"];o?(e.requestAnimationFrame=o,e.cancelAnimationFrame=r,l&&(t.fx.timer=function(e){e()&&t.timers.push(e)&&!s&&(s=!0,i())},t.fx.stop=function(){s=!1})):(e.requestAnimationFrame=function(t){var i=(new Date).getTime(),s=Math.max(0,16-(i-n)),a=e.setTimeout(function(){t(i+s)},s);return n=i+s,a},e.cancelAnimationFrame=function(t){clearTimeout(t)})}(t),a.prototype.toString=function(){return this.query||(this.query=r(this.selector).css("font-family").replace(/^[\/\\'"]+|(;\s?})+|[\/\\'"]+$/g,""))},e.Foundation={name:"Foundation",version:"5.5.3",media_queries:{small:new a(".foundation-mq-small"),"small-only":new a(".foundation-mq-small-only"),medium:new a(".foundation-mq-medium"),"medium-only":new a(".foundation-mq-medium-only"),large:new a(".foundation-mq-large"),"large-only":new a(".foundation-mq-large-only"),xlarge:new a(".foundation-mq-xlarge"),"xlarge-only":new a(".foundation-mq-xlarge-only"),xxlarge:new a(".foundation-mq-xxlarge")},stylesheet:t("<style></style>").appendTo("head")[0].sheet,global:{namespace:s},init:function(t,i,s,n,a){var o=[t,s,n,a],l=[];
vendor: 77,614 bytes, lines 23792-23796
23792if(this.rtl=/rtl/i.test(r("html").attr("dir")),this.scope=t||this.scope,this.set_namespace(),i&&"string"==typeof i&&!/reflow/i.test(i))this.libs.hasOwnProperty(i)&&l.push(this.init_lib(i,o));else for(var d in this.libs)l.push(this.init_lib(d,i));return r(e).load(function(){r(e).trigger("resize.fndtn.clearing").trigger("resize.fndtn.dropdown").trigger("resize.fndtn.equalizer").trigger("resize.fndtn.interchange").trigger("resize.fndtn.joyride").trigger("resize.fndtn.magellan").trigger("resize.fndtn.topbar").trigger("resize.fndtn.slider")}),t},init_lib:function(e,i){return this.libs.hasOwnProperty(e)?(this.patch(this.libs[e]),i&&i.hasOwnProperty(e)?("undefined"!=typeof this.libs[e].settings?t.extend(!0,this.libs[e].settings,i[e]):"undefined"!=typeof this.libs[e].defaults&&t.extend(!0,this.libs[e].defaults,i[e]),this.libs[e].init.apply(this.libs[e],[this.scope,i[e]])):(i=i instanceof Array?i:new Array(i),this.libs[e].init.apply(this.libs[e],i))):function(){}},patch:function(t){t.scope=this.scope,t.namespace=this.global.namespace,t.rtl=this.rtl,t.data_options=this.utils.data_options,t.attr_name=l,t.add_namespace=d,t.bindings=c,t.S=this.utils.S},inherit:function(t,e){for(var i=e.split(" "),s=i.length;s--;)this.utils.hasOwnProperty(i[s])&&(t[i[s]]=this.utils[i[s]])},set_namespace:function(){var e=this.global.namespace===s?t(".foundation-data-attribute-namespace").css("font-family"):this.global.namespace;this.global.namespace=e===s||/false/i.test(e)?"":e},libs:{},utils:{S:r,throttle:function(t,e){var i=null;return function(){var s=this,n=arguments;null==i&&(i=setTimeout(function(){t.apply(s,n),i=null},e))}},debounce:function(t,e,i){var s,n;return function(){var a=this,o=arguments,r=function(){s=null,i||(n=t.apply(a,o))},l=i&&!s;return clearTimeout(s),s=setTimeout(r,e),l&&(n=t.apply(a,o)),n}},data_options:function(e,i){function s(t){return!isNaN(t-0)&&null!==t&&""!==t&&t!==!1&&t!==!0}function n(e){return"string"==typeof e?t.trim(e):e}i=i||"options";var a,o,r,l={},d=function(t){var e=Foundation.global.namespace;return t.data(e.length>0?e+"-"+i:i)},c=d(e);if("object"==typeof c)return c;for(r=(c||":").split(";"),a=r.length;a--;)o=r[a].split(":"),o=[o[0],o.slice(1).join(":")],/true/i.test(o[1])&&(o[1]=!0),/false/i.test(o[1])&&(o[1]=!1),s(o[1])&&(o[1]=-1===o[1].indexOf(".")?parseInt(o[1],10):parseFloat(o[1])),2===o.length&&o[0].length>0&&(l[n(o[0])]=n(o[1]));return l},register_media:function(e,i){Foundation.media_queries[e]===s&&(t("head").append('<meta class="'+i+'"/>'),Foundation.media_queries[e]=n(t("."+i).css("font-family")))},add_custom_rule:function(t,e){if(e===s&&Foundation.stylesheet)Foundation.stylesheet.insertRule(t,Foundation.stylesheet.cssRules.length);else{var i=Foundation.media_queries[e];i!==s&&Foundation.stylesheet.insertRule("@media "+Foundation.media_queries[e]+"{ "+t+" }",Foundation.stylesheet.cssRules.length)}},image_loaded:function(t,e){function i(t){for(var e=t.length,i=e-1;i>=0;i--)if(t.attr("height")===s)return!1;return!0}var n=this,a=t.length;(0===a||i(t))&&e(t),t.each(function(){h(n.S(this),function(){a-=1,0===a&&e(t)})})},random_str:function(){return this.fidx||(this.fidx=0),this.prefix=this.prefix||[this.name||"F",(+new Date).toString(36)].join("-"),this.prefix+(this.fidx++).toString(36)},match:function(t){return e.matchMedia(t).matches},is_small_up:function(){return this.match(Foundation.media_queries.small)},is_medium_up:function(){return this.match(Foundation.media_queries.medium)},is_large_up:function(){return this.match(Foundation.media_queries.large)},is_xlarge_up:function(){return this.match(Foundation.media_queries.xlarge)},is_xxlarge_up:function(){return this.match(Foundation.media_queries.xxlarge)},is_small_only:function(){return!(this.is_medium_up()||this.is_large_up()||this.is_xlarge_up()||this.is_xxlarge_up())},is_medium_only:function(){return this.is_medium_up()&&!this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_large_only:function(){return this.is_medium_up()&&this.is_large_up()&&!this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&!this.is_xxlarge_up()},is_xxlarge_only:function(){return this.is_medium_up()&&this.is_large_up()&&this.is_xlarge_up()&&this.is_xxlarge_up()}}},t.fn.foundation=function(){var t=Array.prototype.slice.call(arguments,0);return this.each(function(){return Foundation.init.apply(Foundation,[this].concat(t)),this})}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.slider={name:"slider",version:"5.5.3",settings:{start:0,end:100,step:1,precision:2,initial:null,display_selector:"",vertical:!1,trigger_input_change:!1,on_change:function(){}},cache:{},init:function(t,e,i){Foundation.inherit(this,"throttle"),this.bindings(e,i),this.reflow()},events:function(){var i=this;t(this.scope).off(".slider").on("mousedown.fndtn.slider touchstart.fndtn.slider pointerdown.fndtn.slider","["+i.attr_name()+"]:not(.disabled, [disabled]) .range-slider-handle",function(e){i.cache.active||(e.preventDefault(),i.set_active_slider(t(e.target)))}).on("mousemove.fndtn.slider touchmove.fndtn.slider pointermove.fndtn.slider",function(s){if(i.cache.active)if(s.preventDefault(),t.data(i.cache.active[0],"settings").vertical){var n=0;s.pageY||(n=e.scrollY),i.calculate_position(i.cache.active,i.get_cursor_position(s,"y")+n)}else i.calculate_position(i.cache.active,i.get_cursor_position(s,"x"))}).on("mouseup.fndtn.slider touchend.fndtn.slider pointerup.fndtn.slider",function(s){if(!i.cache.active){var n="slider"===t(s.target).attr("role")?t(s.target):t(s.target).closest(".range-slider").find("[role='slider']");if(n.length&&!n.parent().hasClass("disabled")&&!n.parent().attr("disabled"))if(i.set_active_slider(n),t.data(i.cache.active[0],"settings").vertical){var a=0;s.pageY||(a=e.scrollY),i.calculate_position(i.cache.active,i.get_cursor_position(s,"y")+a)}else i.calculate_position(i.cache.active,i.get_cursor_position(s,"x"))}i.remove_active_slider()}).on("change.fndtn.slider",function(){i.settings.on_change()}),i.S(e).on("resize.fndtn.slider",i.throttle(function(){i.reflow()},300)),this.S("["+this.attr_name()+"]").each(function(){var e=t(this),s=e.children(".range-slider-handle")[0],n=i.initialize_settings(s);""!=n.display_selector&&t(n.display_selector).each(function(){t(this).attr("value")&&t(this).off("change").on("change",function(){e.foundation("slider","set_value",t(this).val())})})})},get_cursor_position:function(t,e){var i,s="page"+e.toUpperCase(),n="client"+e.toUpperCase();return"undefined"!=typeof t[s]?i=t[s]:"undefined"!=typeof t.originalEvent[n]?i=t.originalEvent[n]:t.originalEvent.touches&&t.originalEvent.touches[0]&&"undefined"!=typeof t.originalEvent.touches[0][n]?i=t.originalEvent.touches[0][n]:t.currentPoint&&"undefined"!=typeof t.currentPoint[e]&&(i=t.currentPoint[e]),i},set_active_slider:function(t){this.cache.active=t},remove_active_slider:function(){this.cache.active=null},calculate_position:function(e,i){var s=this,n=t.data(e[0],"settings"),a=(t.data(e[0],"handle_l"),t.data(e[0],"handle_o"),t.data(e[0],"bar_l")),o=t.data(e[0],"bar_o");requestAnimationFrame(function(){var t;t=Foundation.rtl&&!n.vertical?s.limit_to((o+a-i)/a,0,1):s.limit_to((i-o)/a,0,1),t=n.vertical?1-t:t;var r=s.normalized_value(t,n.start,n.end,n.step,n.precision);s.set_ui(e,r)})},set_ui:function(e,i){var s=t.data(e[0],"settings"),n=t.data(e[0],"handle_l"),a=t.data(e[0],"bar_l"),o=this.normalized_percentage(i,s.start,s.end),r=o*(a-n)-1,l=100*o,d=e.parent(),c=e.parent().children("input[type=hidden]");Foundation.rtl&&!s.vertical&&(r=-r),r=s.vertical?-r+a-n+1:r,this.set_translate(e,r,s.vertical),s.vertical?e.siblings(".range-slider-active-segment").css("height",l+"%"):e.siblings(".range-slider-active-segment").css("width",l+"%"),d.attr(this.attr_name(),i).trigger("change.fndtn.slider"),c.val(i),s.trigger_input_change&&c.trigger("change.fndtn.slider"),e[0].hasAttribute("aria-valuemin")||e.attr({"aria-valuemin":s.start,"aria-valuemax":s.end}),e.attr("aria-valuenow",i),""!=s.display_selector&&t(s.display_selector).each(function(){this.hasAttribute("value")?t(this).val(i):t(this).text(i)})},normalized_percentage:function(t,e,i){return Math.min(1,(t-e)/(i-e))},normalized_value:function(t,e,i,s,n){var a=i-e,o=t*a,r=(o-o%s)/s,l=o%s,d=l>=.5*s?s:0;return(r*s+d+e).toFixed(n)},set_translate:function(e,i,s){s?t(e).css("-webkit-transform","translateY("+i+"px)").css("-moz-transform","translateY("+i+"px)").css("-ms-transform","translateY("+i+"px)").css("-o-transform","translateY("+i+"px)").css("transform","translateY("+i+"px)"):t(e).css("-webkit-transform","translateX("+i+"px)").css("-moz-transform","translateX("+i+"px)").css("-ms-transform","translateX("+i+"px)").css("-o-transform","translateX("+i+"px)").css("transform","translateX("+i+"px)")},limit_to:function(t,e,i){return Math.min(Math.max(t,e),i)},initialize_settings:function(e){var i,s=t.extend({},this.settings,this.data_options(t(e).parent()));return null===s.precision&&(i=(""+s.step).match(/\.([\d]*)/),s.precision=i&&i[1]?i[1].length:0),s.vertical?(t.data(e,"bar_o",t(e).parent().offset().top),t.data(e,"bar_l",t(e).parent().outerHeight()),t.data(e,"handle_o",t(e).offset().top),t.data(e,"handle_l",t(e).outerHeight())):(t.data(e,"bar_o",t(e).parent().offset().left),t.data(e,"bar_l",t(e).parent().outerWidth()),t.data(e,"handle_o",t(e).offset().left),t.data(e,"handle_l",t(e).outerWidth())),t.data(e,"bar",t(e).parent()),t.data(e,"settings",s)},set_initial_position:function(e){var i=t.data(e.children(".range-slider-handle")[0],"settings"),s="number"!=typeof i.initial||isNaN(i.initial)?Math.floor(.5*(i.end-i.start)/i.step)*i.step+i.start:i.initial,n=e.children(".range-slider-handle");this.set_ui(n,s)},set_value:function(e){var i=this;t("["+i.attr_name()+"]",this.scope).each(function(){t(this).attr(i.attr_name(),e)}),t(this.scope).attr(i.attr_name())&&t(this.scope).attr(i.attr_name(),e),i.reflow()},reflow:function(){var e=this;e.S("["+this.attr_name()+"]").each(function(){var i=t(this).children(".range-slider-handle")[0],s=t(this).attr(e.attr_name());e.initialize_settings(i),s?e.set_ui(t(i),parseFloat(s)):e.set_initial_position(t(this))})}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.joyride={name:"joyride",version:"5.5.3",defaults:{expose:!1,modal:!0,keyboard:!0,tip_location:"bottom",nub_position:"auto",scroll_speed:1500,scroll_animation:"linear",timer:0,start_timer_on_click:!0,start_offset:0,next_button:!0,prev_button:!0,tip_animation:"fade",pause_after:[],exposed:[],tip_animation_fade_speed:300,cookie_monster:!1,cookie_name:"joyride",cookie_domain:!1,cookie_expires:365,tip_container:"body",abort_on_close:!0,tip_location_patterns:{top:["bottom"],bottom:[],left:["right","top","bottom"],right:["left","top","bottom"]},post_ride_callback:function(){},post_step_callback:function(){},pre_step_callback:function(){},pre_ride_callback:function(){},post_expose_callback:function(){},template:{link:'<a href="#close" class="joyride-close-tip">&times;</a>',timer:'<div class="joyride-timer-indicator-wrap"><span class="joyride-timer-indicator"></span></div>',tip:'<div class="joyride-tip-guide"><span class="joyride-nub"></span></div>',wrapper:'<div class="joyride-content-wrapper"></div>',button:'<a href="#" class="small button joyride-next-tip"></a>',prev_button:'<a href="#" class="small button joyride-prev-tip"></a>',modal:'<div class="joyride-modal-bg"></div>',expose:'<div class="joyride-expose-wrapper"></div>',expose_cover:'<div class="joyride-expose-cover"></div>'},expose_add_class:""},init:function(e,i,s){Foundation.inherit(this,"throttle random_str"),this.settings=this.settings||t.extend({},this.defaults,s||i),this.bindings(i,s)},go_next:function(){this.settings.$li.next().length<1?this.end():this.settings.timer>0?(clearTimeout(this.settings.automate),this.hide(),this.show(),this.startTimer()):(this.hide(),this.show())},go_prev:function(){this.settings.$li.prev().length<1||(this.settings.timer>0?(clearTimeout(this.settings.automate),this.hide(),this.show(null,!0),this.startTimer()):(this.hide(),this.show(null,!0)))},events:function(){var i=this;t(this.scope).off(".joyride").on("click.fndtn.joyride",".joyride-next-tip, .joyride-modal-bg",function(t){t.preventDefault(),this.go_next()}.bind(this)).on("click.fndtn.joyride",".joyride-prev-tip",function(t){t.preventDefault(),this.go_prev()}.bind(this)).on("click.fndtn.joyride",".joyride-close-tip",function(t){t.preventDefault(),this.end(this.settings.abort_on_close)}.bind(this)).on("keyup.fndtn.joyride",function(t){if(this.settings.keyboard&&this.settings.riding)switch(t.which){case 39:t.preventDefault(),this.go_next();break;case 37:t.preventDefault(),this.go_prev();break;case 27:t.preventDefault(),this.end(this.settings.abort_on_close)}}.bind(this)),t(e).off(".joyride").on("resize.fndtn.joyride",i.throttle(function(){if(t("["+i.attr_name()+"]").length>0&&i.settings.$next_tip&&i.settings.riding){if(i.settings.exposed.length>0){var e=t(i.settings.exposed);e.each(function(){var e=t(this);i.un_expose(e),i.expose(e)})}i.is_phone()?i.pos_phone():i.pos_default(!1)}},100))},start:function(){var e=this,i=t("["+this.attr_name()+"]",this.scope),s=["timer","scrollSpeed","startOffset","tipAnimationFadeSpeed","cookieExpires"],n=s.length;!i.length>0||(this.settings.init||this.events(),this.settings=i.data(this.attr_name(!0)+"-init"),this.settings.$content_el=i,this.settings.$body=t(this.settings.tip_container),this.settings.body_offset=t(this.settings.tip_container).position(),this.settings.$tip_content=this.settings.$content_el.find("> li"),this.settings.paused=!1,this.settings.attempts=0,this.settings.riding=!0,"function"!=typeof t.cookie&&(this.settings.cookie_monster=!1),(!this.settings.cookie_monster||this.settings.cookie_monster&&!t.cookie(this.settings.cookie_name))&&(this.settings.$tip_content.each(function(i){var a=t(this);this.settings=t.extend({},e.defaults,e.data_options(a));for(var o=n;o--;)e.settings[s[o]]=parseInt(e.settings[s[o]],10);e.create({$li:a,index:i})}),!this.settings.start_timer_on_click&&this.settings.timer>0?(this.show("init"),this.startTimer()):this.show("init")))},resume:function(){this.set_li(),this.show()},tip_template:function(e){var i,s;return e.tip_class=e.tip_class||"",i=t(this.settings.template.tip).addClass(e.tip_class),s=t.trim(t(e.li).html())+this.prev_button_text(e.prev_button_text,e.index)+this.button_text(e.button_text)+this.settings.template.link+this.timer_instance(e.index),i.append(t(this.settings.template.wrapper)),i.first().attr(this.add_namespace("data-index"),e.index),t(".joyride-content-wrapper",i).append(s),i[0]},timer_instance:function(e){var i;return i=0===e&&this.settings.start_timer_on_click&&this.settings.timer>0||0===this.settings.timer?"":t(this.settings.template.timer)[0].outerHTML},button_text:function(e){return this.settings.tip_settings.next_button?(e=t.trim(e)||"Next",e=t(this.settings.template.button).append(e)[0].outerHTML):e="",e},prev_button_text:function(e,i){return this.settings.tip_settings.prev_button?(e=t.trim(e)||"Previous",e=0==i?t(this.settings.template.prev_button).append(e).addClass("disabled")[0].outerHTML:t(this.settings.template.prev_button).append(e)[0].outerHTML):e="",e},create:function(e){this.settings.tip_settings=t.extend({},this.settings,this.data_options(e.$li));var i=e.$li.attr(this.add_namespace("data-button"))||e.$li.attr(this.add_namespace("data-text")),s=e.$li.attr(this.add_namespace("data-button-prev"))||e.$li.attr(this.add_namespace("data-prev-text")),n=e.$li.attr("class"),a=t(this.tip_template({tip_class:n,index:e.index,button_text:i,prev_button_text:s,li:e.$li}));t(this.settings.tip_container).append(a)},show:function(e,i){var n=null;if(this.settings.$li===s||-1===t.inArray(this.settings.$li.index(),this.settings.pause_after))if(this.settings.paused?this.settings.paused=!1:this.set_li(e,i),this.settings.attempts=0,this.settings.$li.length&&this.settings.$target.length>0){if(e&&(this.settings.pre_ride_callback(this.settings.$li.index(),this.settings.$next_tip),this.settings.modal&&this.show_modal()),this.settings.pre_step_callback(this.settings.$li.index(),this.settings.$next_tip),this.settings.modal&&this.settings.expose&&this.expose(),this.settings.tip_settings=t.extend({},this.settings,this.data_options(this.settings.$li)),this.settings.timer=parseInt(this.settings.timer,10),this.settings.tip_settings.tip_location_pattern=this.settings.tip_location_patterns[this.settings.tip_settings.tip_location],!/body/i.test(this.settings.$target.selector)&&!this.settings.expose){var a=t(".joyride-modal-bg");/pop/i.test(this.settings.tipAnimation)?a.hide():a.fadeOut(this.settings.tipAnimationFadeSpeed),this.scroll_to()}this.is_phone()?this.pos_phone(!0):this.pos_default(!0),n=this.settings.$next_tip.find(".joyride-timer-indicator"),/pop/i.test(this.settings.tip_animation)?(n.width(0),this.settings.timer>0?(this.settings.$next_tip.show(),setTimeout(function(){n.animate({width:n.parent().width()},this.settings.timer,"linear")}.bind(this),this.settings.tip_animation_fade_speed)):this.settings.$next_tip.show()):/fade/i.test(this.settings.tip_animation)&&(n.width(0),this.settings.timer>0?(this.settings.$next_tip.fadeIn(this.settings.tip_animation_fade_speed).show(),setTimeout(function(){n.animate({width:n.parent().width()},this.settings.timer,"linear")}.bind(this),this.settings.tip_animation_fade_speed)):this.settings.$next_tip.fadeIn(this.settings.tip_animation_fade_speed)),this.settings.$current_tip=this.settings.$next_tip}else this.settings.$li&&this.settings.$target.length<1?this.show(e,i):this.end();else this.settings.paused=!0},is_phone:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},hide:function(){this.settings.modal&&this.settings.expose&&this.un_expose(),this.settings.modal||t(".joyride-modal-bg").hide(),this.settings.$current_tip.css("visibility","hidden"),setTimeout(t.proxy(function(){this.hide(),this.css("visibility","visible")},this.settings.$current_tip),0),this.settings.post_step_callback(this.settings.$li.index(),this.settings.$current_tip)},set_li:function(t,e){t?(this.settings.$li=this.settings.$tip_content.eq(this.settings.start_offset),this.set_next_tip(),this.settings.$current_tip=this.settings.$next_tip):(this.settings.$li=e?this.settings.$li.prev():this.settings.$li.next(),this.set_next_tip()),this.set_target()},set_next_tip:function(){this.settings.$next_tip=t(".joyride-tip-guide").eq(this.settings.$li.index()),this.settings.$next_tip.data("closed","")},set_target:function(){var e=this.settings.$li.attr(this.add_namespace("data-class")),s=this.settings.$li.attr(this.add_namespace("data-id")),n=function(){return s?t(i.getElementById(s)):e?t("."+e).first():t("body")};this.settings.$target=n()},scroll_to:function(){var i,s;i=t(e).height()/2,s=Math.ceil(this.settings.$target.offset().top-i+this.settings.$next_tip.outerHeight()),0!=s&&t("html, body").stop().animate({scrollTop:s},this.settings.scroll_speed,"swing")},paused:function(){return-1===t.inArray(this.settings.$li.index()+1,this.settings.pause_after)},restart:function(){this.hide(),this.settings.$li=s,this.show("init")},pos_default:function(t){var e=this.settings.$next_tip.find(".joyride-nub"),i=Math.ceil(e.outerWidth()/2),s=Math.ceil(e.outerHeight()/2),n=t||!1;if(n&&(this.settings.$next_tip.css("visibility","hidden"),this.settings.$next_tip.show()),/body/i.test(this.settings.$target.selector))this.settings.$li.length&&this.pos_modal(e);else{var a=this.settings.tip_settings.tipAdjustmentY?parseInt(this.settings.tip_settings.tipAdjustmentY):0,o=this.settings.tip_settings.tipAdjustmentX?parseInt(this.settings.tip_settings.tipAdjustmentX):0;this.bottom()?(this.settings.$next_tip.css(this.rtl?{top:this.settings.$target.offset().top+s+this.settings.$target.outerHeight()+a,left:this.settings.$target.offset().left+this.settings.$target.outerWidth()-this.settings.$next_tip.outerWidth()+o}:{top:this.settings.$target.offset().top+s+this.settings.$target.outerHeight()+a,left:this.settings.$target.offset().left+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"top")):this.top()?(this.settings.$next_tip.css(this.rtl?{top:this.settings.$target.offset().top-this.settings.$next_tip.outerHeight()-s+a,left:this.settings.$target.offset().left+this.settings.$target.outerWidth()-this.settings.$next_tip.outerWidth()}:{top:this.settings.$target.offset().top-this.settings.$next_tip.outerHeight()-s+a,left:this.settings.$target.offset().left+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"bottom")):this.right()?(this.settings.$next_tip.css({top:this.settings.$target.offset().top+a,left:this.settings.$target.outerWidth()+this.settings.$target.offset().left+i+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"left")):this.left()&&(this.settings.$next_tip.css({top:this.settings.$target.offset().top+a,left:this.settings.$target.offset().left-this.settings.$next_tip.outerWidth()-i+o}),this.nub_position(e,this.settings.tip_settings.nub_position,"right")),!this.visible(this.corners(this.settings.$next_tip))&&this.settings.attempts<this.settings.tip_settings.tip_location_pattern.length&&(e.removeClass("bottom").removeClass("top").removeClass("right").removeClass("left"),this.settings.tip_settings.tip_location=this.settings.tip_settings.tip_location_pattern[this.settings.attempts],this.settings.attempts++,this.pos_default())}n&&(this.settings.$next_tip.hide(),this.settings.$next_tip.css("visibility","visible"))},pos_phone:function(e){var i=this.settings.$next_tip.outerHeight(),s=(this.settings.$next_tip.offset(),this.settings.$target.outerHeight()),n=t(".joyride-nub",this.settings.$next_tip),a=Math.ceil(n.outerHeight()/2),o=e||!1;n.removeClass("bottom").removeClass("top").removeClass("right").removeClass("left"),o&&(this.settings.$next_tip.css("visibility","hidden"),this.settings.$next_tip.show()),/body/i.test(this.settings.$target.selector)?this.settings.$li.length&&this.pos_modal(n):this.top()?(this.settings.$next_tip.offset({top:this.settings.$target.offset().top-i-a}),n.addClass("bottom")):(this.settings.$next_tip.offset({top:this.settings.$target.offset().top+s+a}),n.addClass("top")),o&&(this.settings.$next_tip.hide(),this.settings.$next_tip.css("visibility","visible"))},pos_modal:function(t){this.center(),t.hide(),this.show_modal()},show_modal:function(){if(!this.settings.$next_tip.data("closed")){var e=t(".joyride-modal-bg");if(e.length<1){var e=t(this.settings.template.modal);e.appendTo("body")}/pop/i.test(this.settings.tip_animation)?e.show():e.fadeIn(this.settings.tip_animation_fade_speed)}},expose:function(){var i,s,n,a,o,r="expose-"+this.random_str(6);if(arguments.length>0&&arguments[0]instanceof t)n=arguments[0];else{if(!this.settings.$target||/body/i.test(this.settings.$target.selector))return!1;n=this.settings.$target}return n.length<1?(e.console&&console.error("element not valid",n),!1):(i=t(this.settings.template.expose),this.settings.$body.append(i),i.css({top:n.offset().top,left:n.offset().left,width:n.outerWidth(!0),height:n.outerHeight(!0)}),s=t(this.settings.template.expose_cover),a={zIndex:n.css("z-index"),position:n.css("position")},o=null==n.attr("class")?"":n.attr("class"),n.css("z-index",parseInt(i.css("z-index"))+1),"static"==a.position&&n.css("position","relative"),n.data("expose-css",a),n.data("orig-class",o),n.attr("class",o+" "+this.settings.expose_add_class),s.css({top:n.offset().top,left:n.offset().left,width:n.outerWidth(!0),height:n.outerHeight(!0)}),this.settings.modal&&this.show_modal(),this.settings.$body.append(s),i.addClass(r),s.addClass(r),n.data("expose",r),this.settings.post_expose_callback(this.settings.$li.index(),this.settings.$next_tip,n),void this.add_exposed(n))},un_expose:function(){var i,s,n,a,o,r=!1;if(arguments.length>0&&arguments[0]instanceof t)s=arguments[0];else{if(!this.settings.$target||/body/i.test(this.settings.$target.selector))return!1;s=this.settings.$target}return s.length<1?(e.console&&console.error("element not valid",s),!1):(i=s.data("expose"),n=t("."+i),arguments.length>1&&(r=arguments[1]),r===!0?t(".joyride-expose-wrapper,.joyride-expose-cover").remove():n.remove(),a=s.data("expose-css"),"auto"==a.zIndex?s.css("z-index",""):s.css("z-index",a.zIndex),a.position!=s.css("position")&&("static"==a.position?s.css("position",""):s.css("position",a.position)),o=s.data("orig-class"),s.attr("class",o),s.removeData("orig-classes"),s.removeData("expose"),s.removeData("expose-z-index"),void this.remove_exposed(s))},add_exposed:function(e){this.settings.exposed=this.settings.exposed||[],e instanceof t||"object"==typeof e?this.settings.exposed.push(e[0]):"string"==typeof e&&this.settings.exposed.push(e)},remove_exposed:function(e){var i,s;for(e instanceof t?i=e[0]:"string"==typeof e&&(i=e),this.settings.exposed=this.settings.exposed||[],s=this.settings.exposed.length;s--;)if(this.settings.exposed[s]==i)return void this.settings.exposed.splice(s,1)},center:function(){var i=t(e);return this.settings.$next_tip.css({top:(i.height()-this.settings.$next_tip.outerHeight())/2+i.scrollTop(),left:(i.width()-this.settings.$next_tip.outerWidth())/2+i.scrollLeft()}),!0},bottom:function(){return/bottom/i.test(this.settings.tip_settings.tip_location)},top:function(){return/top/i.test(this.settings.tip_settings.tip_location)},right:function(){return/right/i.test(this.settings.tip_settings.tip_location)},left:function(){return/left/i.test(this.settings.tip_settings.tip_location)},corners:function(i){if(0===i.length)return[!1,!1,!1,!1];var s=t(e),n=s.height()/2,a=Math.ceil(this.settings.$target.offset().top-n+this.settings.$next_tip.outerHeight()),o=s.width()+s.scrollLeft(),r=s.height()+a,l=s.height()+s.scrollTop(),d=s.scrollTop();return d>a&&(d=0>a?0:a),r>l&&(l=r),[i.offset().top<d,o<i.offset().left+i.outerWidth(),l<i.offset().top+i.outerHeight(),s.scrollLeft()>i.offset().left]},visible:function(t){for(var e=t.length;e--;)if(t[e])return!1;return!0},nub_position:function(t,e,i){t.addClass("auto"===e?i:e)},startTimer:function(){this.settings.$li.length?this.settings.automate=setTimeout(function(){this.hide(),this.show(),this.startTimer()}.bind(this),this.settings.timer):clearTimeout(this.settings.automate)},end:function(e){this.settings.cookie_monster&&t.cookie(this.settings.cookie_name,"ridden",{expires:this.settings.cookie_expires,domain:this.settings.cookie_domain}),this.settings.timer>0&&clearTimeout(this.settings.automate),this.settings.modal&&this.settings.expose&&this.un_expose(),t(this.scope).off("keyup.joyride"),this.settings.$next_tip.data("closed",!0),this.settings.riding=!1,t(".joyride-modal-bg").hide(),this.settings.$current_tip.hide(),("undefined"==typeof e||e===!1)&&(this.settings.post_step_callback(this.settings.$li.index(),this.settings.$current_tip),this.settings.post_ride_callback(this.settings.$li.index(),this.settings.$current_tip)),t(".joyride-tip-guide").remove()},off:function(){t(this.scope).off(".joyride"),t(e).off(".joyride"),t(".joyride-close-tip, .joyride-next-tip, .joyride-modal-bg").off(".joyride"),t(".joyride-tip-guide, .joyride-modal-bg").remove(),clearTimeout(this.settings.automate)},reflow:function(){}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.equalizer={name:"equalizer",version:"5.5.3",settings:{use_tallest:!0,before_height_change:t.noop,after_height_change:t.noop,equalize_on_stack:!1,act_on_hidden_el:!1},init:function(t,e,i){Foundation.inherit(this,"image_loaded"),this.bindings(e,i),this.reflow()},events:function(){this.S(e).off(".equalizer").on("resize.fndtn.equalizer",function(){this.reflow()}.bind(this))},equalize:function(e){var i,s,n=!1,a=e.data("equalizer"),o=e.data(this.attr_name(!0)+"-init")||this.settings;if(i=e.find(o.act_on_hidden_el?a?"["+this.attr_name()+'-watch="'+a+'"]':"["+this.attr_name()+"-watch]":a?"["+this.attr_name()+'-watch="'+a+'"]:visible':"["+this.attr_name()+"-watch]:visible"),0!==i.length&&(o.before_height_change(),e.trigger("before-height-change.fndth.equalizer"),i.height("inherit"),o.equalize_on_stack!==!1||(s=i.first().offset().top,i.each(function(){return t(this).offset().top!==s?(n=!0,!1):void 0}),!n))){var r=i.map(function(){return t(this).outerHeight(!1)}).get();if(o.use_tallest){var l=Math.max.apply(null,r);i.css("height",l)}else{var d=Math.min.apply(null,r);i.css("height",d)}o.after_height_change(),e.trigger("after-height-change.fndtn.equalizer")}},reflow:function(){var e=this;this.S("["+this.attr_name()+"]",this.scope).each(function(){var i=t(this),s=i.data("equalizer-mq"),n=!0;s&&(s="is_"+s.replace(/-/g,"_"),Foundation.utils.hasOwnProperty(s)&&(n=!1)),e.image_loaded(e.S("img",this),function(){if(n||Foundation.utils[s]())e.equalize(i);else{var t=i.find("["+e.attr_name()+"-watch]:visible");t.css("height","auto")}})})}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.dropdown={name:"dropdown",version:"5.5.3",settings:{active_class:"open",disabled_class:"disabled",mega_class:"mega",align:"bottom",is_hover:!1,hover_timeout:150,opened:function(){},closed:function(){}},init:function(e,i,s){Foundation.inherit(this,"throttle"),t.extend(!0,this.settings,i,s),this.bindings(i,s)},events:function(){var s=this,n=s.S;n(this.scope).off(".dropdown").on("click.fndtn.dropdown","["+this.attr_name()+"]",function(e){var i=n(this).data(s.attr_name(!0)+"-init")||s.settings;(!i.is_hover||Modernizr.touch)&&(e.preventDefault(),n(this).parent("[data-reveal-id]").length&&e.stopPropagation(),s.toggle(t(this)))}).on("mouseenter.fndtn.dropdown","["+this.attr_name()+"], ["+this.attr_name()+"-content]",function(t){var e,i,a=n(this);clearTimeout(s.timeout),a.data(s.data_attr())?(e=n("#"+a.data(s.data_attr())),i=a):(e=a,i=n("["+s.attr_name()+'="'+e.attr("id")+'"]'));var o=i.data(s.attr_name(!0)+"-init")||s.settings;n(t.currentTarget).data(s.data_attr())&&o.is_hover&&s.closeall.call(s),o.is_hover&&s.open.apply(s,[e,i])}).on("mouseleave.fndtn.dropdown","["+this.attr_name()+"], ["+this.attr_name()+"-content]",function(){var t,e=n(this);if(e.data(s.data_attr()))t=e.data(s.data_attr(!0)+"-init")||s.settings;else var i=n("["+s.attr_name()+'="'+n(this).attr("id")+'"]'),t=i.data(s.attr_name(!0)+"-init")||s.settings;s.timeout=setTimeout(function(){e.data(s.data_attr())?t.is_hover&&s.close.call(s,n("#"+e.data(s.data_attr()))):t.is_hover&&s.close.call(s,e)}.bind(this),t.hover_timeout)}).on("click.fndtn.dropdown",function(e){var a=n(e.target).closest("["+s.attr_name()+"-content]"),o=a.find("a");return o.length>0&&"false"!==a.attr("aria-autoclose")&&s.close.call(s,n("["+s.attr_name()+"-content]")),e.target!==i&&!t.contains(i.documentElement,e.target)||n(e.target).closest("["+s.attr_name()+"]").length>0?void 0:!n(e.target).data("revealId")&&a.length>0&&(n(e.target).is("["+s.attr_name()+"-content]")||t.contains(a.first()[0],e.target))?void e.stopPropagation():void s.close.call(s,n("["+s.attr_name()+"-content]"))}).on("opened.fndtn.dropdown","["+s.attr_name()+"-content]",function(){s.settings.opened.call(this)}).on("closed.fndtn.dropdown","["+s.attr_name()+"-content]",function(){s.settings.closed.call(this)}),n(e).off(".dropdown").on("resize.fndtn.dropdown",s.throttle(function(){s.resize.call(s)},50)),this.resize()},close:function(e){var i=this;e.each(function(s){var n=t("["+i.attr_name()+"="+e[s].id+"]")||t("aria-controls="+e[s].id+"]");
23793
23794n.attr("aria-expanded","false"),i.S(this).hasClass(i.settings.active_class)&&(i.S(this).css(Foundation.rtl?"right":"left","-99999px").attr("aria-hidden","true").removeClass(i.settings.active_class).prev("["+i.attr_name()+"]").removeClass(i.settings.active_class).removeData("target"),i.S(this).trigger("closed.fndtn.dropdown",[e]))}),e.removeClass("f-open-"+this.attr_name(!0))},closeall:function(){var e=this;t.each(e.S(".f-open-"+this.attr_name(!0)),function(){e.close.call(e,e.S(this))})},open:function(t,e){this.css(t.addClass(this.settings.active_class),e),t.prev("["+this.attr_name()+"]").addClass(this.settings.active_class),t.data("target",e.get(0)).trigger("opened.fndtn.dropdown",[t,e]),t.attr("aria-hidden","false"),e.attr("aria-expanded","true"),t.focus(),t.addClass("f-open-"+this.attr_name(!0))},data_attr:function(){return this.namespace.length>0?this.namespace+"-"+this.name:this.name},toggle:function(t){if(!t.hasClass(this.settings.disabled_class)){var e=this.S("#"+t.data(this.data_attr()));0!==e.length&&(this.close.call(this,this.S("["+this.attr_name()+"-content]").not(e)),e.hasClass(this.settings.active_class)?(this.close.call(this,e),e.data("target")!==t.get(0)&&this.open.call(this,e,t)):this.open.call(this,e,t))}},resize:function(){var e=this.S("["+this.attr_name()+"-content].open"),i=t(e.data("target"));e.length&&i.length&&this.css(e,i)},css:function(t,e){var i=Math.max((e.width()-t.width())/2,8),s=e.data(this.attr_name(!0)+"-init")||this.settings,n=t.parent().css("overflow-y")||t.parent().css("overflow");if(this.clear_idx(),this.small()){var a=this.dirs.bottom.call(t,e,s);t.attr("style","").removeClass("drop-left drop-right drop-top").css({position:"absolute",width:"95%","max-width":"none",top:a.top}),t.css(Foundation.rtl?"right":"left",i)}else if("visible"!==n){var o=e[0].offsetTop+e[0].offsetHeight;t.attr("style","").css({position:"absolute",top:o}),t.css(Foundation.rtl?"right":"left",i)}else this.style(t,e,s);return t},style:function(e,i,s){var n=t.extend({position:"absolute"},this.dirs[s.align].call(e,i,s));e.attr("style","").css(n)},dirs:{_base:function(t,s){var n=this.offsetParent(),a=n.offset(),o=t.offset();o.top-=a.top,o.left-=a.left,o.missRight=!1,o.missTop=!1,o.missLeft=!1,o.leftRightFlag=!1;var r,l=e.innerWidth;r=i.getElementsByClassName("row")[0]?i.getElementsByClassName("row")[0].clientWidth:l;var d=(l-r)/2,c=r;if(!this.hasClass("mega")&&!s.ignore_repositioning){var h=this.outerWidth(),u=t.offset().left;t.offset().top<=this.outerHeight()&&(o.missTop=!0,c=l-d,o.leftRightFlag=!0),u+h>u+d&&u-d>h&&(o.missRight=!0,o.missLeft=!1),0>=u-h&&(o.missLeft=!0,o.missRight=!1)}return o},top:function(t,e){var i=Foundation.libs.dropdown,s=i.dirs._base.call(this,t,e);return this.addClass("drop-top"),1==s.missTop&&(s.top=s.top+t.outerHeight()+this.outerHeight(),this.removeClass("drop-top")),1==s.missRight&&(s.left=s.left-this.outerWidth()+t.outerWidth()),(t.outerWidth()<this.outerWidth()||i.small()||this.hasClass(e.mega_menu))&&i.adjust_pip(this,t,e,s),Foundation.rtl?{left:s.left-this.outerWidth()+t.outerWidth(),top:s.top-this.outerHeight()}:{left:s.left,top:s.top-this.outerHeight()}},bottom:function(t,e){var i=Foundation.libs.dropdown,s=i.dirs._base.call(this,t,e);return 1==s.missRight&&(s.left=s.left-this.outerWidth()+t.outerWidth()),(t.outerWidth()<this.outerWidth()||i.small()||this.hasClass(e.mega_menu))&&i.adjust_pip(this,t,e,s),i.rtl?{left:s.left-this.outerWidth()+t.outerWidth(),top:s.top+t.outerHeight()}:{left:s.left,top:s.top+t.outerHeight()}},left:function(t,e){var i=Foundation.libs.dropdown.dirs._base.call(this,t,e);return this.addClass("drop-left"),1==i.missLeft&&(i.left=i.left+this.outerWidth(),i.top=i.top+t.outerHeight(),this.removeClass("drop-left")),{left:i.left-this.outerWidth(),top:i.top}},right:function(t,e){var i=Foundation.libs.dropdown.dirs._base.call(this,t,e);this.addClass("drop-right"),1==i.missRight?(i.left=i.left-this.outerWidth(),i.top=i.top+t.outerHeight(),this.removeClass("drop-right")):i.triggeredRight=!0;var s=Foundation.libs.dropdown;return(t.outerWidth()<this.outerWidth()||s.small()||this.hasClass(e.mega_menu))&&s.adjust_pip(this,t,e,i),{left:i.left+t.outerWidth(),top:i.top}}},adjust_pip:function(t,e,i,s){var n=Foundation.stylesheet,a=8;t.hasClass(i.mega_class)?a=s.left+e.outerWidth()/2-8:this.small()&&(a+=s.left-8),this.rule_idx=n.cssRules.length;var o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left: "+a+"px;",d="left: "+(a-1)+"px;";1==s.missRight&&(a=t.outerWidth()-23,o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left: "+a+"px;",d="left: "+(a-1)+"px;"),1==s.triggeredRight&&(o=".f-dropdown.open:before",r=".f-dropdown.open:after",l="left:-12px;",d="left:-14px;"),n.insertRule?(n.insertRule([o,"{",l,"}"].join(" "),this.rule_idx),n.insertRule([r,"{",d,"}"].join(" "),this.rule_idx+1)):(n.addRule(o,l,this.rule_idx),n.addRule(r,d,this.rule_idx+1))},clear_idx:function(){var t=Foundation.stylesheet;"undefined"!=typeof this.rule_idx&&(t.deleteRule(this.rule_idx),t.deleteRule(this.rule_idx),delete this.rule_idx)},small:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},off:function(){this.S(this.scope).off(".fndtn.dropdown"),this.S("html, body").off(".fndtn.dropdown"),this.S(e).off(".fndtn.dropdown"),this.S("[data-dropdown-content]").off(".fndtn.dropdown")},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.clearing={name:"clearing",version:"5.5.3",settings:{templates:{viewing:'<a href="#" class="clearing-close">&times;</a><div class="visible-img" style="display: none"><div class="clearing-touch-label"></div><img src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" /><p class="clearing-caption"></p><a href="#" class="clearing-main-prev"><span></span></a><a href="#" class="clearing-main-next"><span></span></a></div><img class="clearing-preload-next" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" /><img class="clearing-preload-prev" style="display: none" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D" alt="" />'},close_selectors:".clearing-close, div.clearing-blackout",open_selectors:"",skip_selector:"",touch_label:"",init:!1,locked:!1},init:function(t,e,i){var s=this;Foundation.inherit(this,"throttle image_loaded"),this.bindings(e,i),s.S(this.scope).is("["+this.attr_name()+"]")?this.assemble(s.S("li",this.scope)):s.S("["+this.attr_name()+"]",this.scope).each(function(){s.assemble(s.S("li",this))})},events:function(s){var n=this,a=n.S,o=t(".scroll-container");o.length>0&&(this.scope=o),a(this.scope).off(".clearing").on("click.fndtn.clearing","ul["+this.attr_name()+"] li "+this.settings.open_selectors,function(t,e,i){var e=e||a(this),i=i||e,s=e.next("li"),o=e.closest("["+n.attr_name()+"]").data(n.attr_name(!0)+"-init"),r=a(t.target);t.preventDefault(),o||(n.init(),o=e.closest("["+n.attr_name()+"]").data(n.attr_name(!0)+"-init")),i.hasClass("visible")&&e[0]===i[0]&&s.length>0&&n.is_open(e)&&(i=s,r=a("img",i)),n.open(r,e,i),n.update_paddles(i)}).on("click.fndtn.clearing",".clearing-main-next",function(t){n.nav(t,"next")}).on("click.fndtn.clearing",".clearing-main-prev",function(t){n.nav(t,"prev")}).on("click.fndtn.clearing",this.settings.close_selectors,function(t){Foundation.libs.clearing.close(t,this)}),t(i).on("keydown.fndtn.clearing",function(t){n.keydown(t)}),a(e).off(".clearing").on("resize.fndtn.clearing",function(){n.resize()}),this.swipe_events(s)},swipe_events:function(){var t=this,e=t.S;e(this.scope).on("touchstart.fndtn.clearing",".visible-img",function(t){t.touches||(t=t.originalEvent);var i={start_page_x:t.touches[0].pageX,start_page_y:t.touches[0].pageY,start_time:(new Date).getTime(),delta_x:0,is_scrolling:s};e(this).data("swipe-transition",i),t.stopPropagation()}).on("touchmove.fndtn.clearing",".visible-img",function(i){if(i.touches||(i=i.originalEvent),!(i.touches.length>1||i.scale&&1!==i.scale)){var s=e(this).data("swipe-transition");if("undefined"==typeof s&&(s={}),s.delta_x=i.touches[0].pageX-s.start_page_x,Foundation.rtl&&(s.delta_x=-s.delta_x),"undefined"==typeof s.is_scrolling&&(s.is_scrolling=!!(s.is_scrolling||Math.abs(s.delta_x)<Math.abs(i.touches[0].pageY-s.start_page_y))),!s.is_scrolling&&!s.active){i.preventDefault();var n=s.delta_x<0?"next":"prev";s.active=!0,t.nav(i,n)}}}).on("touchend.fndtn.clearing",".visible-img",function(t){e(this).data("swipe-transition",{}),t.stopPropagation()})},assemble:function(e){var i=e.parent();if(!i.parent().hasClass("carousel")){i.after('<div id="foundationClearingHolder"></div>');var s=i.detach(),n="";if(null!=s[0]){n=s[0].outerHTML;var a=this.S("#foundationClearingHolder"),o=i.data(this.attr_name(!0)+"-init"),r={grid:'<div class="carousel">'+n+"</div>",viewing:o.templates.viewing},l='<div class="clearing-assembled"><div>'+r.viewing+r.grid+"</div></div>",d=this.settings.touch_label;Modernizr.touch&&(l=t(l).find(".clearing-touch-label").html(d).end()),a.after(l).remove()}}},open:function(e,s,n){function a(){setTimeout(function(){this.image_loaded(u,function(){1!==u.outerWidth()||p?o.call(this,u):a.call(this)}.bind(this))}.bind(this),100)}function o(e){var i=t(e);i.css("visibility","visible"),i.trigger("imageVisible"),l.css("overflow","hidden"),d.addClass("clearing-blackout"),c.addClass("clearing-container"),h.show(),this.fix_height(n).caption(r.S(".clearing-caption",h),r.S("img",n)).center_and_label(e,f).shift(s,n,function(){n.closest("li").siblings().removeClass("visible"),n.closest("li").addClass("visible")}),h.trigger("opened.fndtn.clearing")}var r=this,l=t(i.body),d=n.closest(".clearing-assembled"),c=r.S("div",d).first(),h=r.S(".visible-img",c),u=r.S("img",h).not(e),f=r.S(".clearing-touch-label",c),p=!1,g={};t("body").on("touchmove",function(t){t.preventDefault()}),u.error(function(){p=!0}),this.locked()||(h.trigger("open.fndtn.clearing"),g=this.load(e),g.interchange?u.attr("data-interchange",g.interchange).foundation("interchange","reflow"):u.attr("src",g.src).attr("data-interchange",""),u.css("visibility","hidden"),a.call(this))},close:function(e,s){e.preventDefault();var n,a,o=function(t){return/blackout/.test(t.selector)?t:t.closest(".clearing-blackout")}(t(s)),r=t(i.body);return s===e.target&&o&&(r.css("overflow",""),n=t("div",o).first(),a=t(".visible-img",n),a.trigger("close.fndtn.clearing"),this.settings.prev_index=0,t("ul["+this.attr_name()+"]",o).attr("style","").closest(".clearing-blackout").removeClass("clearing-blackout"),n.removeClass("clearing-container"),a.hide(),a.trigger("closed.fndtn.clearing")),t("body").off("touchmove"),!1},is_open:function(t){return t.parent().prop("style").length>0},keydown:function(e){var i=t(".clearing-blackout ul["+this.attr_name()+"]"),s=this.rtl?37:39,n=this.rtl?39:37,a=27;e.which===s&&this.go(i,"next"),e.which===n&&this.go(i,"prev"),e.which===a&&this.S("a.clearing-close").trigger("click.fndtn.clearing")},nav:function(e,i){var s=t("ul["+this.attr_name()+"]",".clearing-blackout");e.preventDefault(),this.go(s,i)},resize:function(){var e=t("img",".clearing-blackout .visible-img"),i=t(".clearing-touch-label",".clearing-blackout");e.length&&(this.center_and_label(e,i),e.trigger("resized.fndtn.clearing"))},fix_height:function(t){var e=t.parent().children(),i=this;return e.each(function(){var t=i.S(this),e=t.find("img");t.height()>e.outerHeight()&&t.addClass("fix-height")}).closest("ul").width(100*e.length+"%"),this},update_paddles:function(t){t=t.closest("li");var e=t.closest(".carousel").siblings(".visible-img");t.next().length>0?this.S(".clearing-main-next",e).removeClass("disabled"):this.S(".clearing-main-next",e).addClass("disabled"),t.prev().length>0?this.S(".clearing-main-prev",e).removeClass("disabled"):this.S(".clearing-main-prev",e).addClass("disabled")},center_and_label:function(t,e){return e.css(!this.rtl&&e.length>0?{marginLeft:-(e.outerWidth()/2),marginTop:-(t.outerHeight()/2)-e.outerHeight()-10}:{marginRight:-(e.outerWidth()/2),marginTop:-(t.outerHeight()/2)-e.outerHeight()-10,left:"auto",right:"50%"}),this},load:function(t){var e,i,s;return"A"===t[0].nodeName?(e=t.attr("href"),i=t.data("clearing-interchange")):(s=t.closest("a"),e=s.attr("href"),i=s.data("clearing-interchange")),this.preload(t),{src:e?e:t.attr("src"),interchange:e?i:t.data("clearing-interchange")}},preload:function(t){this.img(t.closest("li").next(),"next").img(t.closest("li").prev(),"prev")},img:function(e,i){if(e.length){var s,n,a,o=t(".clearing-preload-"+i),r=this.S("a",e);r.length?(s=r.attr("href"),n=r.data("clearing-interchange")):(a=this.S("img",e),s=a.attr("src"),n=a.data("clearing-interchange")),n?o.attr("data-interchange",n):(o.attr("src",s),o.attr("data-interchange",""))}return this},caption:function(t,e){var i=e.attr("data-caption");if(i){var s=t.get(0);s.innerHTML=i,t.show()}else t.text("").hide();return this},go:function(t,e){var i=this.S(".visible",t),s=i[e]();this.settings.skip_selector&&0!=s.find(this.settings.skip_selector).length&&(s=s[e]()),s.length&&this.S("img",s).trigger("click.fndtn.clearing",[i,s]).trigger("change.fndtn.clearing")},shift:function(t,e,i){var s,n=e.parent(),a=this.settings.prev_index||e.index(),o=this.direction(n,t,e),r=this.rtl?"right":"left",l=parseInt(n.css("left"),10),d=e.outerWidth(),c={};e.index()===a||/skip/.test(o)?/skip/.test(o)&&(s=e.index()-this.settings.up_count,this.lock(),s>0?(c[r]=-(s*d),n.animate(c,300,this.unlock())):(c[r]=0,n.animate(c,300,this.unlock()))):/left/.test(o)?(this.lock(),c[r]=l+d,n.animate(c,300,this.unlock())):/right/.test(o)&&(this.lock(),c[r]=l-d,n.animate(c,300,this.unlock())),i()},direction:function(t,e,i){var s,n=this.S("li",t),a=n.outerWidth()+n.outerWidth()/4,o=Math.floor(this.S(".clearing-container").outerWidth()/a)-1,r=n.index(i);return this.settings.up_count=o,s=this.adjacent(this.settings.prev_index,r)?r>o&&r>this.settings.prev_index?"right":r>o-1&&r<=this.settings.prev_index?"left":!1:"skip",this.settings.prev_index=r,s},adjacent:function(t,e){for(var i=e+1;i>=e-1;i--)if(i===t)return!0;return!1},lock:function(){this.settings.locked=!0},unlock:function(){this.settings.locked=!1},locked:function(){return this.settings.locked},off:function(){this.S(this.scope).off(".fndtn.clearing"),this.S(e).off(".fndtn.clearing")},reflow:function(){this.init()}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";var n=function(){},a=function(n,a){if(n.hasClass(a.slides_container_class))return this;var d,c,h,u,f,p,g=this,_=n,m=0,v=!1;g.slides=function(){return _.children(a.slide_selector)},g.slides().first().addClass(a.active_slide_class),g.update_slide_number=function(e){a.slide_number&&(c.find("span:first").text(parseInt(e)+1),c.find("span:last").text(g.slides().length)),a.bullets&&(h.children().removeClass(a.bullets_active_class),t(h.children().get(e)).addClass(a.bullets_active_class))},g.update_active_link=function(e){var i=t('[data-orbit-link="'+g.slides().eq(e).attr("data-orbit-slide")+'"]');i.siblings().removeClass(a.bullets_active_class),i.addClass(a.bullets_active_class)},g.build_markup=function(){_.wrap('<div class="'+a.container_class+'"></div>'),d=_.parent(),_.addClass(a.slides_container_class),a.stack_on_small&&d.addClass(a.stack_on_small_class),a.navigation_arrows&&(d.append(t('<a href="#"><span></span></a>').addClass(a.prev_class)),d.append(t('<a href="#"><span></span></a>').addClass(a.next_class))),a.timer&&(u=t("<div>").addClass(a.timer_container_class),u.append("<span>"),u.append(t("<div>").addClass(a.timer_progress_class)),u.addClass(a.timer_paused_class),d.append(u)),a.slide_number&&(c=t("<div>").addClass(a.slide_number_class),c.append("<span></span> "+a.slide_number_text+" <span></span>"),d.append(c)),a.bullets&&(h=t("<ol>").addClass(a.bullets_container_class),d.append(h),h.wrap('<div class="orbit-bullets-container"></div>'),g.slides().each(function(e){var i=t("<li>").attr("data-orbit-slide",e).on("click",g.link_bullet);h.append(i)}))},g._goto=function(e,i){if(e===m)return!1;"object"==typeof p&&p.restart();var s=g.slides(),n="next";if(v=!0,m>e&&(n="prev"),e>=s.length){if(!a.circular)return!1;e=0}else if(0>e){if(!a.circular)return!1;e=s.length-1}var o=t(s.get(m)),r=t(s.get(e));o.css("zIndex",2),o.removeClass(a.active_slide_class),r.css("zIndex",4).addClass(a.active_slide_class),_.trigger("before-slide-change.fndtn.orbit"),a.before_slide_change(),g.update_active_link(e);var l=function(){var t=function(){m=e,v=!1,i===!0&&(p=g.create_timer(),p.start()),g.update_slide_number(m),_.trigger("after-slide-change.fndtn.orbit",[{slide_number:m,total_slides:s.length}]),a.after_slide_change(m,s.length)};_.outerHeight()!=r.outerHeight()&&a.variable_height?_.animate({height:r.outerHeight()},250,"linear",t):t()};if(1===s.length)return l(),!1;var d=function(){"next"===n&&f.next(o,r,l),"prev"===n&&f.prev(o,r,l)};r.outerHeight()>_.outerHeight()&&a.variable_height?_.animate({height:r.outerHeight()},250,"linear",d):d()},g.next=function(t){t.stopImmediatePropagation(),t.preventDefault(),g._goto(m+1)},g.prev=function(t){t.stopImmediatePropagation(),t.preventDefault(),g._goto(m-1)},g.link_custom=function(e){e.preventDefault();var i=t(this).attr("data-orbit-link");if("string"==typeof i&&""!=(i=t.trim(i))){var s=d.find("[data-orbit-slide="+i+"]");-1!=s.index()&&g._goto(s.index())}},g.link_bullet=function(){var e=t(this).attr("data-orbit-slide");if("string"==typeof e&&""!=(e=t.trim(e)))if(isNaN(parseInt(e))){var i=d.find("[data-orbit-slide="+e+"]");-1!=i.index()&&g._goto(i.index()+1)}else g._goto(parseInt(e))},g.timer_callback=function(){g._goto(m+1,!0)},g.compute_dimensions=function(){var e=t(g.slides().get(m)),i=e.outerHeight();a.variable_height||g.slides().each(function(){t(this).outerHeight()>i&&(i=t(this).outerHeight())}),_.height(i)},g.create_timer=function(){var t=new o(d.find("."+a.timer_container_class),a,g.timer_callback);return t},g.stop_timer=function(){"object"==typeof p&&p.stop()},g.toggle_timer=function(){var t=d.find("."+a.timer_container_class);t.hasClass(a.timer_paused_class)?("undefined"==typeof p&&(p=g.create_timer()),p.start()):"object"==typeof p&&p.stop()},g.init=function(){g.build_markup(),a.timer&&(p=g.create_timer(),Foundation.utils.image_loaded(this.slides().children("img"),p.start)),f=new l(a,_),"slide"===a.animation&&(f=new r(a,_)),d.on("click","."+a.next_class,g.next),d.on("click","."+a.prev_class,g.prev),a.next_on_click&&d.on("click","."+a.slides_container_class+" [data-orbit-slide]",g.link_bullet),d.on("click",g.toggle_timer),a.swipe&&d.on("touchstart.fndtn.orbit",function(t){t.touches||(t=t.originalEvent);var e={start_page_x:t.touches[0].pageX,start_page_y:t.touches[0].pageY,start_time:(new Date).getTime(),delta_x:0,is_scrolling:s};d.data("swipe-transition",e),t.stopPropagation()}).on("touchmove.fndtn.orbit",function(t){if(t.touches||(t=t.originalEvent),!(t.touches.length>1||t.scale&&1!==t.scale)){var e=d.data("swipe-transition");if("undefined"==typeof e&&(e={}),e.delta_x=t.touches[0].pageX-e.start_page_x,"undefined"==typeof e.is_scrolling&&(e.is_scrolling=!!(e.is_scrolling||Math.abs(e.delta_x)<Math.abs(t.touches[0].pageY-e.start_page_y))),!e.is_scrolling&&!e.active){t.preventDefault();var i=e.delta_x<0?m+1:m-1;e.active=!0,g._goto(i)}}}).on("touchend.fndtn.orbit",function(t){d.data("swipe-transition",{}),t.stopPropagation()}),d.on("mouseenter.fndtn.orbit",function(){a.timer&&a.pause_on_hover&&g.stop_timer()}).on("mouseleave.fndtn.orbit",function(){a.timer&&a.resume_on_mouseout&&p.start()}),t(i).on("click","[data-orbit-link]",g.link_custom),t(e).on("load resize",g.compute_dimensions),Foundation.utils.image_loaded(this.slides().children("img"),g.compute_dimensions),Foundation.utils.image_loaded(this.slides().children("img"),function(){d.prev("."+a.preloader_class).css("display","none"),g.update_slide_number(0),g.update_active_link(0),_.trigger("ready.fndtn.orbit")})},g.init()},o=function(t,e,i){var s,n,a=this,o=e.timer_speed,r=t.find("."+e.timer_progress_class),l=-1;this.update_progress=function(t){var e=r.clone();e.attr("style",""),e.css("width",t+"%"),r.replaceWith(e),r=e},this.restart=function(){clearTimeout(n),t.addClass(e.timer_paused_class),l=-1,a.update_progress(0)},this.start=function(){return t.hasClass(e.timer_paused_class)?(l=-1===l?o:l,t.removeClass(e.timer_paused_class),s=(new Date).getTime(),r.animate({width:"100%"},l,"linear"),n=setTimeout(function(){a.restart(),i()},l),void t.trigger("timer-started.fndtn.orbit")):!0},this.stop=function(){if(t.hasClass(e.timer_paused_class))return!0;clearTimeout(n),t.addClass(e.timer_paused_class);var i=(new Date).getTime();l-=i-s;var r=100-l/o*100;a.update_progress(r),t.trigger("timer-stopped.fndtn.orbit")}},r=function(e){var i=e.animation_speed,s=1===t("html[dir=rtl]").length,n=s?"marginRight":"marginLeft",a={};a[n]="0%",this.next=function(t,e,s){t.animate({marginLeft:"-100%"},i),e.animate(a,i,function(){t.css(n,"100%"),s()})},this.prev=function(t,e,s){t.animate({marginLeft:"100%"},i),e.css(n,"-100%"),e.animate(a,i,function(){t.css(n,"100%"),s()})}},l=function(e){{var i=e.animation_speed;1===t("html[dir=rtl]").length}this.next=function(t,e,s){e.css({margin:"0%",opacity:"0.01"}),e.animate({opacity:"1"},i,"linear",function(){t.css("margin","100%"),s()})},this.prev=function(t,e,s){e.css({margin:"0%",opacity:"0.01"}),e.animate({opacity:"1"},i,"linear",function(){t.css("margin","100%"),s()})}};Foundation.libs=Foundation.libs||{},Foundation.libs.orbit={name:"orbit",version:"5.5.3",settings:{animation:"slide",timer_speed:1e4,pause_on_hover:!0,resume_on_mouseout:!1,next_on_click:!0,animation_speed:500,stack_on_small:!1,navigation_arrows:!0,slide_number:!0,slide_number_text:"of",container_class:"orbit-container",stack_on_small_class:"orbit-stack-on-small",next_class:"orbit-next",prev_class:"orbit-prev",timer_container_class:"orbit-timer",timer_paused_class:"paused",timer_progress_class:"orbit-progress",slides_container_class:"orbit-slides-container",preloader_class:"preloader",slide_selector:"*",bullets_container_class:"orbit-bullets",bullets_active_class:"active",slide_number_class:"orbit-slide-number",caption_class:"orbit-caption",active_slide_class:"active",orbit_transition_class:"orbit-transitioning",bullets:!0,circular:!0,timer:!0,variable_height:!1,swipe:!0,before_slide_change:n,after_slide_change:n},init:function(t,e,i){this.bindings(e,i)},events:function(t){var e=new a(this.S(t),this.S(t).data("orbit-init"));this.S(t).data(this.name+"-instance",e)},reflow:function(){var t=this;if(t.S(t.scope).is("[data-orbit]")){var e=t.S(t.scope),i=e.data(t.name+"-instance");i.compute_dimensions()}else t.S("[data-orbit]",t.scope).each(function(e,i){var s=t.S(i),n=(t.data_options(s),s.data(t.name+"-instance"));n.compute_dimensions()})}}}(jQuery,window,window.document),function(t){"use strict";Foundation.libs.offcanvas={name:"offcanvas",version:"5.5.3",settings:{open_method:"move",close_on_click:!1},init:function(t,e,i){this.bindings(e,i)},events:function(){var e=this,i=e.S,s="",n="",a="",o="",r="";"move"===this.settings.open_method?(s="move-",n="right",a="left",o="top",r="bottom"):"overlap_single"===this.settings.open_method?(s="offcanvas-overlap-",n="right",a="left",o="top",r="bottom"):"overlap"===this.settings.open_method&&(s="offcanvas-overlap"),i(this.scope).off(".offcanvas").on("click.fndtn.offcanvas",".left-off-canvas-toggle",function(a){e.click_toggle_class(a,s+n),"overlap"!==e.settings.open_method&&i(".left-submenu").removeClass(s+n),t(".left-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".left-off-canvas-menu a",function(a){var o=e.get_settings(a),r=i(this).parent();!o.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(a.preventDefault(),i(this).siblings(".left-submenu").toggleClass(s+n)):r.hasClass("back")&&(a.preventDefault(),r.parent().removeClass(s+n)):(e.hide.call(e,s+n,e.get_wrapper(a)),r.parent().removeClass(s+n)),t(".left-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".right-off-canvas-toggle",function(n){e.click_toggle_class(n,s+a),"overlap"!==e.settings.open_method&&i(".right-submenu").removeClass(s+a),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".right-off-canvas-menu a",function(n){var o=e.get_settings(n),r=i(this).parent();!o.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".right-submenu").toggleClass(s+a)):r.hasClass("back")&&(n.preventDefault(),r.parent().removeClass(s+a)):(e.hide.call(e,s+a,e.get_wrapper(n)),r.parent().removeClass(s+a)),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".top-off-canvas-toggle",function(n){e.click_toggle_class(n,s+r),"overlap"!==e.settings.open_method&&i(".top-submenu").removeClass(s+r),t(".top-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".top-off-canvas-menu a",function(n){var a=e.get_settings(n),o=i(this).parent();!a.close_on_click||o.hasClass("has-submenu")||o.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".top-submenu").toggleClass(s+r)):o.hasClass("back")&&(n.preventDefault(),o.parent().removeClass(s+r)):(e.hide.call(e,s+r,e.get_wrapper(n)),o.parent().removeClass(s+r)),t(".top-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".bottom-off-canvas-toggle",function(n){e.click_toggle_class(n,s+o),"overlap"!==e.settings.open_method&&i(".bottom-submenu").removeClass(s+o),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".bottom-off-canvas-menu a",function(n){var a=e.get_settings(n),r=i(this).parent();!a.close_on_click||r.hasClass("has-submenu")||r.hasClass("back")?i(this).parent().hasClass("has-submenu")?(n.preventDefault(),i(this).siblings(".bottom-submenu").toggleClass(s+o)):r.hasClass("back")&&(n.preventDefault(),r.parent().removeClass(s+o)):(e.hide.call(e,s+o,e.get_wrapper(n)),r.parent().removeClass(s+o)),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(o){e.click_remove_class(o,s+a),i(".right-submenu").removeClass(s+a),n&&(e.click_remove_class(o,s+n),i(".left-submenu").removeClass(s+a)),t(".right-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(i){e.click_remove_class(i,s+a),t(".left-off-canvas-toggle").attr("aria-expanded","false"),n&&(e.click_remove_class(i,s+n),t(".right-off-canvas-toggle").attr("aria-expanded","false"))}).on("click.fndtn.offcanvas",".exit-off-canvas",function(n){e.click_remove_class(n,s+o),i(".bottom-submenu").removeClass(s+o),r&&(e.click_remove_class(n,s+r),i(".top-submenu").removeClass(s+o)),t(".bottom-off-canvas-toggle").attr("aria-expanded","true")}).on("click.fndtn.offcanvas",".exit-off-canvas",function(i){e.click_remove_class(i,s+o),t(".top-off-canvas-toggle").attr("aria-expanded","false"),r&&(e.click_remove_class(i,s+r),t(".bottom-off-canvas-toggle").attr("aria-expanded","false"))})},toggle:function(t,e){e=e||this.get_wrapper(),e.is("."+t)?this.hide(t,e):this.show(t,e)},show:function(t,e){e=e||this.get_wrapper(),e.trigger("open.fndtn.offcanvas"),e.addClass(t)},hide:function(t,e){e=e||this.get_wrapper(),e.trigger("close.fndtn.offcanvas"),e.removeClass(t)},click_toggle_class:function(t,e){t.preventDefault();var i=this.get_wrapper(t);this.toggle(e,i)},click_remove_class:function(t,e){t.preventDefault();var i=this.get_wrapper(t);this.hide(e,i)},get_settings:function(t){var e=this.S(t.target).closest("["+this.attr_name()+"]");return e.data(this.attr_name(!0)+"-init")||this.settings},get_wrapper:function(t){var e=this.S(t?t.target:this.scope).closest(".off-canvas-wrap");return 0===e.length&&(e=this.S(".off-canvas-wrap")),e},reflow:function(){}}}(jQuery,window,window.document),function(t){"use strict";Foundation.libs.alert={name:"alert",version:"5.5.3",settings:{callback:function(){}},init:function(t,e,i){this.bindings(e,i)},events:function(){var e=this,i=this.S;t(this.scope).off(".alert").on("click.fndtn.alert","["+this.attr_name()+"] .close",function(t){var s=i(this).closest("["+e.attr_name()+"]"),n=s.data(e.attr_name(!0)+"-init")||e.settings;t.preventDefault(),Modernizr.csstransitions?(s.addClass("alert-close"),s.on("transitionend webkitTransitionEnd oTransitionEnd",function(){i(this).trigger("close.fndtn.alert").remove(),n.callback()})):s.fadeOut(300,function(){i(this).trigger("close.fndtn.alert").remove(),n.callback()})})},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i,s){"use strict";function n(t){var e=/fade/i.test(t),i=/pop/i.test(t);return{animate:e||i,pop:i,fade:e}}var a=[];Foundation.libs.reveal={name:"reveal",version:"5.5.3",locked:!1,settings:{animation:"fadeAndPop",animation_speed:250,close_on_background_click:!0,close_on_esc:!0,dismiss_modal_class:"close-reveal-modal",multiple_opened:!1,bg_class:"reveal-modal-bg",root_element:"body",open:function(){},opened:function(){},close:function(){},closed:function(){},on_ajax_error:t.noop,bg:t(".reveal-modal-bg"),css:{open:{opacity:0,visibility:"visible",display:"block"},close:{opacity:1,visibility:"hidden",display:"none"}}},init:function(e,i,s){t.extend(!0,this.settings,i,s),this.bindings(i,s)},events:function(){var t=this,e=t.S;return e(this.scope).off(".reveal").on("click.fndtn.reveal","["+this.add_namespace("data-reveal-id")+"]:not([disabled])",function(i){if(i.preventDefault(),!t.locked){var s=e(this),n=s.data(t.data_attr("reveal-ajax")),a=s.data(t.data_attr("reveal-replace-content"));if(t.locked=!0,"undefined"==typeof n)t.open.call(t,s);else{var o=n===!0?s.attr("href"):n;t.open.call(t,s,{url:o},{replaceContentSel:a})}}}),e(i).on("click.fndtn.reveal",this.close_targets(),function(i){if(i.preventDefault(),!t.locked){var s=e("["+t.attr_name()+"].open").data(t.attr_name(!0)+"-init")||t.settings,n=e(i.target)[0]===e("."+s.bg_class)[0];if(n){if(!s.close_on_background_click)return;i.stopPropagation()}t.locked=!0,t.close.call(t,n?e("["+t.attr_name()+"].open:not(.toback)"):e(this).closest("["+t.attr_name()+"]"))}}),e("["+t.attr_name()+"]",this.scope).length>0?e(this.scope).on("open.fndtn.reveal",this.settings.open).on("opened.fndtn.reveal",this.settings.opened).on("opened.fndtn.reveal",this.open_video).on("close.fndtn.reveal",this.settings.close).on("closed.fndtn.reveal",this.settings.closed).on("closed.fndtn.reveal",this.close_video):e(this.scope).on("open.fndtn.reveal","["+t.attr_name()+"]",this.settings.open).on("opened.fndtn.reveal","["+t.attr_name()+"]",this.settings.opened).on("opened.fndtn.reveal","["+t.attr_name()+"]",this.open_video).on("close.fndtn.reveal","["+t.attr_name()+"]",this.settings.close).on("closed.fndtn.reveal","["+t.attr_name()+"]",this.settings.closed).on("closed.fndtn.reveal","["+t.attr_name()+"]",this.close_video),!0},key_up_on:function(){var t=this;return t.S("body").off("keyup.fndtn.reveal").on("keyup.fndtn.reveal",function(e){var i=t.S("["+t.attr_name()+"].open"),s=i.data(t.attr_name(!0)+"-init")||t.settings;s&&27===e.which&&s.close_on_esc&&!t.locked&&t.close.call(t,i)}),!0},key_up_off:function(){return this.S("body").off("keyup.fndtn.reveal"),!0},open:function(i,n){var o,r=this;i?"undefined"!=typeof i.selector?o=r.S("#"+i.data(r.data_attr("reveal-id"))).first():(o=r.S(this.scope),n=i):o=r.S(this.scope);var l=o.data(r.attr_name(!0)+"-init");if(l=l||this.settings,o.hasClass("open")&&i!==s&&i.attr("data-reveal-id")==o.attr("id"))return r.close(o);if(!o.hasClass("open")){var d=r.S("["+r.attr_name()+"].open");"undefined"==typeof o.data("css-top")&&o.data("css-top",parseInt(o.css("top"),10)).data("offset",this.cache_offset(o)),o.attr("tabindex","0").attr("aria-hidden","false"),this.key_up_on(o),o.on("open.fndtn.reveal",function(t){"fndtn.reveal"!==t.namespace}),o.on("open.fndtn.reveal").trigger("open.fndtn.reveal"),d.length<1&&this.toggle_bg(o,!0),"string"==typeof n&&(n={url:n});var c=function(){d.length>0&&(l.multiple_opened?r.to_back(d):r.hide(d,l.css.close)),l.multiple_opened&&a.push(o),r.show(o,l.css.open)};if("undefined"!=typeof n&&n.url){var h="undefined"!=typeof n.success?n.success:null;t.extend(n,{success:function(e,i,s){if(t.isFunction(h)){var n=h(e,i,s);"string"==typeof n&&(e=n)}"undefined"!=typeof options&&"undefined"!=typeof options.replaceContentSel?o.find(options.replaceContentSel).html(e):o.html(e),r.S(o).foundation("section","reflow"),r.S(o).children().foundation(),c()}}),l.on_ajax_error!==t.noop&&t.extend(n,{error:l.on_ajax_error}),t.ajax(n)}else c()}r.S(e).trigger("resize")},close:function(e){var e=e&&e.length?e:this.S(this.scope),i=this.S("["+this.attr_name()+"].open"),s=e.data(this.attr_name(!0)+"-init")||this.settings,n=this;
23795
23796if(i.length>0)if(e.removeAttr("tabindex","0").attr("aria-hidden","true"),this.locked=!0,this.key_up_off(e),e.trigger("close.fndtn.reveal"),(s.multiple_opened&&1===i.length||!s.multiple_opened||e.length>1)&&(n.toggle_bg(e,!1),n.to_front(e)),s.multiple_opened){var o=e.is(":not(.toback)");n.hide(e,s.css.close,s),o?a.pop():a=t.grep(a,function(t){var i=t[0]===e[0];return i&&n.to_front(e),!i}),a.length>0&&n.to_front(a[a.length-1])}else n.hide(i,s.css.close,s)},close_targets:function(){var t="."+this.settings.dismiss_modal_class;return this.settings.close_on_background_click?t+", ."+this.settings.bg_class:t},toggle_bg:function(e,i){0===this.S("."+this.settings.bg_class).length&&(this.settings.bg=t("<div />",{"class":this.settings.bg_class}).appendTo("body").hide());var n=this.settings.bg.filter(":visible").length>0;i!=n&&((i==s?n:!i)?this.hide(this.settings.bg):this.show(this.settings.bg))},show:function(i,s){if(s){var a=i.data(this.attr_name(!0)+"-init")||this.settings,o=a.root_element,r=this;if(0===i.parent(o).length){var l=i.wrap('<div style="display: none;" />').parent();i.on("closed.fndtn.reveal.wrapped",function(){i.detach().appendTo(l),i.unwrap().unbind("closed.fndtn.reveal.wrapped")}),i.detach().appendTo(o)}var d=n(a.animation);if(d.animate||(this.locked=!1),d.pop){s.top=t(e).scrollTop()-i.data("offset")+"px";var c={top:t(e).scrollTop()+i.data("css-top")+"px",opacity:1};return setTimeout(function(){return i.css(s).animate(c,a.animation_speed,"linear",function(){r.locked=!1,i.trigger("opened.fndtn.reveal")}).addClass("open")},a.animation_speed/2)}if(s.top=t(e).scrollTop()+i.data("css-top")+"px",d.fade){var c={opacity:1};return setTimeout(function(){return i.css(s).animate(c,a.animation_speed,"linear",function(){r.locked=!1,i.trigger("opened.fndtn.reveal")}).addClass("open")},a.animation_speed/2)}return i.css(s).show().css({opacity:1}).addClass("open").trigger("opened.fndtn.reveal")}var a=this.settings;return n(a.animation).fade?i.fadeIn(a.animation_speed/2):(this.locked=!1,i.show())},to_back:function(t){t.addClass("toback")},to_front:function(t){t.removeClass("toback")},hide:function(i,s){if(s){var a=i.data(this.attr_name(!0)+"-init"),o=this;a=a||this.settings;var r=n(a.animation);if(r.animate||(this.locked=!1),r.pop){var l={top:-t(e).scrollTop()-i.data("offset")+"px",opacity:0};return setTimeout(function(){return i.animate(l,a.animation_speed,"linear",function(){o.locked=!1,i.css(s).trigger("closed.fndtn.reveal")}).removeClass("open")},a.animation_speed/2)}if(r.fade){var l={opacity:0};return setTimeout(function(){return i.animate(l,a.animation_speed,"linear",function(){o.locked=!1,i.css(s).trigger("closed.fndtn.reveal")}).removeClass("open")},a.animation_speed/2)}return i.hide().css(s).removeClass("open").trigger("closed.fndtn.reveal")}var a=this.settings;return n(a.animation).fade?i.fadeOut(a.animation_speed/2):i.hide()},close_video:function(e){var i=t(".flex-video",e.target),s=t("iframe",i);s.length>0&&(s.attr("data-src",s[0].src),s.attr("src",s.attr("src")),i.hide())},open_video:function(e){var i=t(".flex-video",e.target),n=i.find("iframe");if(n.length>0){var a=n.attr("data-src");if("string"==typeof a)n[0].src=n.attr("data-src");else{var o=n[0].src;n[0].src=s,n[0].src=o}i.show()}},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},cache_offset:function(t){var e=t.show().height()+parseInt(t.css("top"),10)+t.scrollY;return t.hide(),e},off:function(){t(this.scope).off(".fndtn.reveal")},reflow:function(){}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.interchange={name:"interchange",version:"5.5.3",cache:{},images_loaded:!1,nodes_loaded:!1,settings:{load_attr:"interchange",named_queries:{"default":"only screen",small:Foundation.media_queries.small,"small-only":Foundation.media_queries["small-only"],medium:Foundation.media_queries.medium,"medium-only":Foundation.media_queries["medium-only"],large:Foundation.media_queries.large,"large-only":Foundation.media_queries["large-only"],xlarge:Foundation.media_queries.xlarge,"xlarge-only":Foundation.media_queries["xlarge-only"],xxlarge:Foundation.media_queries.xxlarge,landscape:"only screen and (orientation: landscape)",portrait:"only screen and (orientation: portrait)",retina:"only screen and (-webkit-min-device-pixel-ratio: 2),only screen and (min--moz-device-pixel-ratio: 2),only screen and (-o-min-device-pixel-ratio: 2/1),only screen and (min-device-pixel-ratio: 2),only screen and (min-resolution: 192dpi),only screen and (min-resolution: 2dppx)"},directives:{replace:function(e,i,s){if(null!==e&&/IMG/.test(e[0].nodeName)){var n=t.each(e,function(){this.src=i});if(new RegExp(i,"i").test(n))return;return e.attr("src",i),s(e[0].src)}var a=e.data(this.data_attr+"-last-path"),o=this;if(a!=i)return/\.(gif|jpg|jpeg|tiff|png)([?#].*)?/i.test(i)?(t(e).css("background-image","url("+i+")"),e.data("interchange-last-path",i),s(i)):t.get(i,function(t){e.html(t),e.data(o.data_attr+"-last-path",i),s()})}}},init:function(e,i,s){Foundation.inherit(this,"throttle random_str"),this.data_attr=this.set_data_attr(),t.extend(!0,this.settings,i,s),this.bindings(i,s),this.reflow()},get_media_hash:function(){var t="";for(var e in this.settings.named_queries)t+=matchMedia(this.settings.named_queries[e]).matches.toString();return t},events:function(){var i,s=this;return t(e).off(".interchange").on("resize.fndtn.interchange",s.throttle(function(){var t=s.get_media_hash();t!==i&&s.resize(),i=t},50)),this},resize:function(){var e=this.cache;if(!this.images_loaded||!this.nodes_loaded)return void setTimeout(t.proxy(this.resize,this),50);for(var i in e)if(e.hasOwnProperty(i)){var s=this.results(i,e[i]);s&&this.settings.directives[s.scenario[1]].call(this,s.el,s.scenario[0],function(t){if(arguments[0]instanceof Array)var e=arguments[0];else var e=Array.prototype.slice.call(arguments,0);return function(){t.el.trigger(t.scenario[1],e)}}(s))}},results:function(t,e){var i=e.length;if(i>0)for(var s=this.S("["+this.add_namespace("data-uuid")+'="'+t+'"]');i--;){var n,a=e[i][2];if(n=matchMedia(this.settings.named_queries.hasOwnProperty(a)?this.settings.named_queries[a]:a),n.matches)return{el:s,scenario:e[i]}}return!1},load:function(t,e){return("undefined"==typeof this["cached_"+t]||e)&&this["update_"+t](),this["cached_"+t]},update_images:function(){var t=this.S("img["+this.data_attr+"]"),e=t.length,i=e,s=0,n=this.data_attr;for(this.cache={},this.cached_images=[],this.images_loaded=0===e;i--;){if(s++,t[i]){var a=t[i].getAttribute(n)||"";a.length>0&&this.cached_images.push(t[i])}s===e&&(this.images_loaded=!0,this.enhance("images"))}return this},update_nodes:function(){var t=this.S("["+this.data_attr+"]").not("img"),e=t.length,i=e,s=0,n=this.data_attr;for(this.cached_nodes=[],this.nodes_loaded=0===e;i--;){s++;var a=t[i].getAttribute(n)||"";a.length>0&&this.cached_nodes.push(t[i]),s===e&&(this.nodes_loaded=!0,this.enhance("nodes"))}return this},enhance:function(i){for(var s=this["cached_"+i].length;s--;)this.object(t(this["cached_"+i][s]));return t(e).trigger("resize.fndtn.interchange")},convert_directive:function(t){var e=this.trim(t);return e.length>0?e:"replace"},parse_scenario:function(t){var e=t[0].match(/(.+),\s*(\w+)\s*$/),i=t[1].match(/(.*)\)/);if(e)var s=e[1],n=e[2];else var a=t[0].split(/,\s*$/),s=a[0],n="";return[this.trim(s),this.convert_directive(n),this.trim(i[1])]},object:function(t){var e=this.parse_data_attr(t),i=[],s=e.length;if(s>0)for(;s--;){var n=e[s].split(/,\s?\(/);if(n.length>1){var a=this.parse_scenario(n);i.push(a)}}return this.store(t,i)},store:function(t,e){var i=this.random_str(),s=t.data(this.add_namespace("uuid",!0));return this.cache[s]?this.cache[s]:(t.attr(this.add_namespace("data-uuid"),i),this.cache[i]=e)},trim:function(e){return"string"==typeof e?t.trim(e):e},set_data_attr:function(t){return t?this.namespace.length>0?this.namespace+"-"+this.settings.load_attr:this.settings.load_attr:this.namespace.length>0?"data-"+this.namespace+"-"+this.settings.load_attr:"data-"+this.settings.load_attr},parse_data_attr:function(t){for(var e=t.attr(this.attr_name()).split(/\[(.*?)\]/),i=e.length,s=[];i--;)e[i].replace(/[\W\d]+/,"").length>4&&s.push(e[i]);return s},reflow:function(){this.load("images",!0),this.load("nodes",!0)}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs["magellan-expedition"]={name:"magellan-expedition",version:"5.5.3",settings:{active_class:"active",threshold:0,destination_threshold:20,throttle_delay:30,fixed_top:0,offset_by_height:!0,duration:700,easing:"swing"},init:function(t,e,i){Foundation.inherit(this,"throttle"),this.bindings(e,i)},events:function(){var e=this,i=e.S,s=e.settings;e.set_expedition_position(),i(e.scope).off(".magellan").on("click.fndtn.magellan","["+e.add_namespace("data-magellan-arrival")+"] a[href*=#]",function(i){var s=this.hostname===location.hostname||!this.hostname,n=e.filterPathname(location.pathname)===e.filterPathname(this.pathname),a=this.hash.replace(/(:|\.|\/)/g,"\\$1"),o=this;if(s&&n&&a){i.preventDefault();var r=t(this).closest("["+e.attr_name()+"]"),l=r.data("magellan-expedition-init"),d=this.hash.split("#").join(""),c=t('a[name="'+d+'"]');0===c.length&&(c=t("#"+d));var h=c.offset().top-l.destination_threshold+1;l.offset_by_height&&(h-=r.outerHeight()),t("html, body").stop().animate({scrollTop:h},l.duration,l.easing,function(){history.pushState?history.pushState(null,null,o.pathname+o.search+"#"+d):location.hash=o.pathname+o.search+"#"+d})}}).on("scroll.fndtn.magellan",e.throttle(this.check_for_arrivals.bind(this),s.throttle_delay))},check_for_arrivals:function(){var t=this;t.update_arrivals(),t.update_expedition_positions()},set_expedition_position:function(){var e=this;t("["+this.attr_name()+"=fixed]",e.scope).each(function(){var i,s,n=t(this),a=n.data("magellan-expedition-init"),o=n.attr("styles");n.attr("style",""),i=n.offset().top+a.threshold,s=parseInt(n.data("magellan-fixed-top")),isNaN(s)||(e.settings.fixed_top=s),n.data(e.data_attr("magellan-top-offset"),i),n.attr("style",o)})},update_expedition_positions:function(){var i=this,s=t(e).scrollTop();t("["+this.attr_name()+"=fixed]",i.scope).each(function(){var e=t(this),n=e.data("magellan-expedition-init"),a=e.attr("style"),o=e.data("magellan-top-offset");if(s+i.settings.fixed_top>=o){var r=e.prev("["+i.add_namespace("data-magellan-expedition-clone")+"]");0===r.length&&(r=e.clone(),r.removeAttr(i.attr_name()),r.attr(i.add_namespace("data-magellan-expedition-clone"),""),e.before(r)),e.css({position:"fixed",top:n.fixed_top}).addClass("fixed")}else e.prev("["+i.add_namespace("data-magellan-expedition-clone")+"]").remove(),e.attr("style",a).css("position","").css("top","").removeClass("fixed")})},update_arrivals:function(){var i=this,s=t(e).scrollTop();t("["+this.attr_name()+"]",i.scope).each(function(){var e=t(this),n=e.data(i.attr_name(!0)+"-init"),a=i.offsets(e,s),o=e.find("["+i.add_namespace("data-magellan-arrival")+"]"),r=!1;a.each(function(t,s){if(s.viewport_offset>=s.top_offset){var a=e.find("["+i.add_namespace("data-magellan-arrival")+"]");return a.not(s.arrival).removeClass(n.active_class),s.arrival.addClass(n.active_class),r=!0,!0}}),r||o.removeClass(n.active_class)})},offsets:function(e,i){var s=this,n=e.data(s.attr_name(!0)+"-init"),a=i;return e.find("["+s.add_namespace("data-magellan-arrival")+"]").map(function(){var i=t(this).data(s.data_attr("magellan-arrival")),o=t("["+s.add_namespace("data-magellan-destination")+"="+i+"]");if(o.length>0){var r=o.offset().top-n.destination_threshold;return n.offset_by_height&&(r-=e.outerHeight()),r=Math.floor(r),{destination:o,arrival:t(this),top_offset:r,viewport_offset:a}}}).sort(function(t,e){return t.top_offset<e.top_offset?-1:t.top_offset>e.top_offset?1:0})},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},off:function(){this.S(this.scope).off(".magellan"),this.S(e).off(".magellan")},filterPathname:function(t){return t=t||"",t.replace(/^\//,"").replace(/(?:index|default).[a-zA-Z]{3,4}$/,"").replace(/\/$/,"")},reflow:function(){var e=this;t("["+e.add_namespace("data-magellan-expedition-clone")+"]",e.scope).remove()}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.accordion={name:"accordion",version:"5.5.3",settings:{content_class:"content",active_class:"active",multi_expand:!1,toggleable:!0,callback:function(){}},init:function(t,e,i){this.bindings(e,i)},events:function(e){var i=this,s=this.S;i.create(this.S(e)),s(this.scope).off(".fndtn.accordion").on("click.fndtn.accordion","["+this.attr_name()+"] > dd > a, ["+this.attr_name()+"] > li > a",function(e){var n=s(this).closest("["+i.attr_name()+"]"),a=i.attr_name()+"="+n.attr(i.attr_name()),o=n.data(i.attr_name(!0)+"-init")||i.settings,r=s("#"+this.href.split("#")[1]),l=t("> dd, > li",n),d=l.children("."+o.content_class),c=d.filter("."+o.active_class);return e.preventDefault(),n.attr(i.attr_name())&&(d=d.add("["+a+"] dd > ."+o.content_class+", ["+a+"] li > ."+o.content_class),l=l.add("["+a+"] dd, ["+a+"] li")),o.toggleable&&r.is(c)?(r.parent("dd, li").toggleClass(o.active_class,!1),r.toggleClass(o.active_class,!1),s(this).attr("aria-expanded",function(t,e){return"true"===e?"false":"true"}),o.callback(r),r.triggerHandler("toggled",[n]),void n.triggerHandler("toggled",[r])):(o.multi_expand||(d.removeClass(o.active_class),l.removeClass(o.active_class),l.children("a").attr("aria-expanded","fal
23796se")),r.addClass(o.active_class).parent().addClass(o.active_class),o.callback(r),r.triggerHandler("toggled",[n]),n.triggerHandler("toggled",[r]),void s(this).attr("aria-expanded","true"))})},create:function(e){var i=this,s=e,n=t("> .accordion-navigation",s),a=s.data(i.attr_name(!0)+"-init")||i.settings;n.children("a").attr("aria-expanded","false"),n.has("."+a.content_class+"."+a.active_class).addClass(a.active_class).children("a").attr("aria-expanded","true"),a.multi_expand&&e.attr("aria-multiselectable","true")},toggle:function(t){var t="undefined"!=typeof t?t:{},i="undefined"!=typeof t.selector?t.selector:"",s="undefined"!=typeof t.toggle_state?t.toggle_state:"",n="undefined"!=typeof t.$accordion?t.$accordion:this.S(this.scope).closest("["+this.attr_name()+"]"),a=n.find("> dd"+i+", > li"+i);if(a.length<1)return e.console&&console.error("Selection not found.",i),!1;var o=this.S,r=this.settings.active_class;a.each(function(){var t=o(this),e=t.hasClass(r);(e&&"close"===s||!e&&"open"===s||""===s)&&t.find("> a").trigger("click.fndtn.accordion")})},open:function(t){var t="undefined"!=typeof t?t:{};t.toggle_state="open",this.toggle(t)},close:function(t){var t="undefined"!=typeof t?t:{};t.toggle_state="close",this.toggle(t)},off:function(){},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.topbar={name:"topbar",version:"5.5.3",settings:{index:0,start_offset:0,sticky_class:"sticky",custom_back_text:!0,back_text:"Back",mobile_show_parent_link:!0,is_hover:!0,scrolltop:!0,sticky_on:"all",dropdown_autoclose:!0},init:function(e,i,s){Foundation.inherit(this,"add_custom_rule register_media throttle");var n=this;n.register_media("topbar","foundation-mq-topbar"),this.bindings(i,s),n.S("["+this.attr_name()+"]",this.scope).each(function(){{var e=t(this),i=e.data(n.attr_name(!0)+"-init");n.S("section, .top-bar-section",this)}e.data("index",0);var s=e.parent();s.hasClass("fixed")||n.is_sticky(e,s,i)?(n.settings.sticky_class=i.sticky_class,n.settings.sticky_topbar=e,e.data("height",s.outerHeight()),e.data("stickyoffset",s.offset().top)):e.data("height",e.outerHeight()),i.assembled||n.assemble(e),i.is_hover?n.S(".has-dropdown",e).addClass("not-click"):n.S(".has-dropdown",e).removeClass("not-click"),n.add_custom_rule(".f-topbar-fixed { padding-top: "+e.data("height")+"px }"),s.hasClass("fixed")&&n.S("body").addClass("f-topbar-fixed")})},is_sticky:function(t,e,i){var s=e.hasClass(i.sticky_class),n=matchMedia(Foundation.media_queries.small).matches,a=matchMedia(Foundation.media_queries.medium).matches,o=matchMedia(Foundation.media_queries.large).matches;return s&&"all"===i.sticky_on?!0:s&&this.small()&&-1!==i.sticky_on.indexOf("small")&&n&&!a&&!o?!0:s&&this.medium()&&-1!==i.sticky_on.indexOf("medium")&&n&&a&&!o?!0:s&&this.large()&&-1!==i.sticky_on.indexOf("large")&&n&&a&&o?!0:!1},toggle:function(i){var s,n=this;s=i?n.S(i).closest("["+this.attr_name()+"]"):n.S("["+this.attr_name()+"]");var a=s.data(this.attr_name(!0)+"-init"),o=n.S("section, .top-bar-section",s);n.breakpoint()&&(n.rtl?(o.css({right:"0%"}),t(">.name",o).css({right:"100%"})):(o.css({left:"0%"}),t(">.name",o).css({left:"100%"})),n.S("li.moved",o).removeClass("moved"),s.data("index",0),s.toggleClass("expanded").css("height","")),a.scrolltop?s.hasClass("expanded")?s.parent().hasClass("fixed")&&(a.scrolltop?(s.parent().removeClass("fixed"),s.addClass("fixed"),n.S("body").removeClass("f-topbar-fixed"),e.scrollTo(0,0)):s.parent().removeClass("expanded")):s.hasClass("fixed")&&(s.parent().addClass("fixed"),s.removeClass("fixed"),n.S("body").addClass("f-topbar-fixed")):(n.is_sticky(s,s.parent(),a)&&s.parent().addClass("fixed"),s.parent().hasClass("fixed")&&(s.hasClass("expanded")?(s.addClass("fixed"),s.parent().addClass("expanded"),n.S("body").addClass("f-topbar-fixed")):(s.removeClass("fixed"),s.parent().removeClass("expanded"),n.update_sticky_positioning())))},timer:null,events:function(){var i=this,s=this.S;s(this.scope).off(".topbar").on("click.fndtn.topbar","["+this.attr_name()+"] .toggle-topbar",function(t){t.preventDefault(),i.toggle(this)}).on("click.fndtn.topbar contextmenu.fndtn.topbar",'.top-bar .top-bar-section li a[href^="#"],['+this.attr_name()+'] .top-bar-section li a[href^="#"]',function(){var e=t(this).closest("li"),s=e.closest("["+i.attr_name()+"]"),n=s.data(i.attr_name(!0)+"-init");if(n.dropdown_autoclose&&n.is_hover){var a=t(this).closest(".hover");a.removeClass("hover")}!i.breakpoint()||e.hasClass("back")||e.hasClass("has-dropdown")||i.toggle()}).on("click.fndtn.topbar","["+this.attr_name()+"] li.has-dropdown",function(e){var n=s(this),a=s(e.target),o=n.closest("["+i.attr_name()+"]"),r=o.data(i.attr_name(!0)+"-init");return a.data("revealId")?void i.toggle():void(i.breakpoint()||(!r.is_hover||Modernizr.touch)&&(e.stopImmediatePropagation(),n.hasClass("hover")?(n.removeClass("hover").find("li").removeClass("hover"),n.parents("li.hover").removeClass("hover")):(n.addClass("hover"),t(n).siblings().removeClass("hover"),"A"===a[0].nodeName&&a.parent().hasClass("has-dropdown")&&e.preventDefault())))}).on("click.fndtn.topbar","["+this.attr_name()+"] .has-dropdown>a",function(t){if(i.breakpoint()){t.preventDefault();var e=s(this),n=e.closest("["+i.attr_name()+"]"),a=n.find("section, .to
23796p-bar-section"),o=(e.next(".dropdown").outerHeight(),e.closest("li"));n.data("index",n.data("index")+1),o.addClass("moved"),i.rtl?(a.css({right:-(100*n.data("index"))+"%"}),a.find(">.name").css({right:100*n.data("index")+"%"})):(a.css({left:-(100*n.data("index"))+"%"}),a.find(">.name").css({left:100*n.data("index")+"%"})),n.css("height",e.siblings("ul").outerHeight(!0)+n.data("height"))}}),s(e).off(".topbar").on("resize.fndtn.topbar",i.throttle(function(){i.resize.call(i)},50)).trigger("resize.fndtn.topbar").load(function(){s(this).trigger("resize.fndtn.topbar")}),s("body").off(".topbar").on("click.fndtn.topbar",function(t){var e=s(t.target).closest("li").closest("li.hover");e.length>0||s("["+i.attr_name()+"] li.hover").removeClass("hover")}),s(this.scope).on("click.fndtn.topbar","["+this.attr_name()+"] .has-dropdown .back",function(t){t.preventDefault();var e=s(this),n=e.closest("["+i.attr_name()+"]"),a=n.find("section, .top-bar-section"),o=(n.data(i.attr_name(!0)+"-init"),e.closest("li.moved")),r=o.parent();n.data("index",n.data("index")-1),i.rtl?(a.css({right:-(100*n.data("index"))+"%"}),a.find(">.name").css({right:100*n.data("index")+"%"})):(a.css({left:-(100*n.data("index"))+"%"}),a.find(">.name").css({left:100*n.data("index")+"%"})),0===n.data("index")?n.css("height",""):n.css("height",r.outerHeight(!0)+n.data("height")),setTimeout(function(){o.removeClass("moved")},300)}),s(this.scope).find(".dropdown a").focus(function(){t(this).parents(".has-dropdown").addClass("hover")}).blur(function(){t(this).parents(".has-dropdown").removeClass("hover")})},resize:function(){var t=this;t.S("["+this.attr_name()+"]").each(function(){var e,s=t.S(this),n=s.data(t.attr_name(!0)+"-init"),a=s.parent("."+t.settings.sticky_class);if(!t.breakpoint()){var o=s.hasClass("expanded");s.css("height","").removeClass("expanded").find("li").removeClass("hover"),o&&t.toggle(s)}t.is_sticky(s,a,n)&&(a.hasClass("fixed")?(a.removeClass("fixed"),e=a.offset().top,t.S(i.body).hasClass("f-topbar-fixed")&&(e-=s.data("height")),s.data("stickyoffset",e),a.addClass("fixed")):(e=a.offset().top,s.data("stickyoffset",e)))})},breakpoint:function(){return!matchMedia(Foundation.media_queries.topbar).matches},small:function(){return matchMedia(Foundation.media_queries.small).matches},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},assemble:function(e){var i=this,s=e.data(this.attr_name(!0)+"-init"),n=i.S("section, .top-bar-section",e);n.detach(),i.S(".has-dropdown>a",n).each(function(){var e,n=i.S(this),a=n.siblings(".dropdown"),o=n.attr("href");a.find(".title.back").length||(e=t(1==s.mobile_show_parent_link&&o?'<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5></li><li class="parent-link hide-for-medium-up"><a class="parent-link js-generated" href="'+o+'">'+n.html()+"</a></li>":'<li class="title back js-generated"><h5><a href="javascript:void(0)"></a></h5>'),t("h5>a",e).html(1==s.custom_back_text?s.back_text:"&laquo; "+n.html()),a.prepend(e))}),n.appendTo(e),this.sticky(),this.assembled(e)},assembled:function(e){e.data(this.attr_name(!0),t.extend({},e.data(this.attr_name(!0)),{assembled:!0}))},height:function(e){var i=0,s=this;return t("> li",e).each(function(){i+=s.S(this).outerHeight(!0)}),i},sticky:function(){var t=this;this.S(e).on("scroll",function(){t.update_sticky_positioning()})},update_sticky_positioning:function(){var t="."+this.settings.sticky_class,i=this.S(e),s=this;if(s.settings.sticky_topbar&&s.is_sticky(this.settings.sticky_topbar,this.settings.sticky_topbar.parent(),this.settings)){var n=this.settings.sticky_topbar.data("stickyoffset")+this.settings.start_offset;s.S(t).hasClass("expanded")||(i.scrollTop()>n?s.S(t).hasClass("fixed")||(s.S(t).addClass("fixed"),s.S("body").addClass("f-topbar-fixed")):i.scrollTop()<=n&&s.S(t).hasClass("fixed")&&(s.S(t).removeClass("fixed"),s.S("body").removeClass("f-topbar-fixed")))}},off:function(){this.S(this.scope).off(".fndtn.topbar"),this.S(e).off(".fndtn.topbar")},reflow:function(){}}}
vendor: 5,004 bytes, line 23796
23796(jQuery,window,window.document),function(t,e,i,s){"use strict";Foundation.libs.tab={name:"tab",version:"5.5.3",settings:{active_class:"active",callback:function(){},deep_linking:!1,scroll_to_content:!0,is_hover:!1},default_tab_hashes:[],init:function(t,e,i){var s=this,n=this.S;n("["+this.attr_name()+"] > .active > a",this.scope).each(function(){s.default_tab_hashes.push(this.hash)}),this.bindings(e,i),this.handle_location_hash_change()},events:function(){var t=this,i=this.S,s=function(e,s){var n=i(s).closest("["+t.attr_name()+"]").data(t.attr_name(!0)+"-init");if(!n.is_hover||Modernizr.touch){var a=e.keyCode||e.which;9!==a&&(e.preventDefault(),e.stopPropagation()),t.toggle_active_tab(i(s).parent())}};i(this.scope).off(".tab").on("keydown.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){var e=t.keyCode||t.which;if(13===e||32===e){var i=this;s(t,i)}}).on("click.fndtn.tab","["+this.attr_name()+"] > * > a",function(t){var e=this;s(t,e)}).on("mouseenter.fndtn.tab","["+this.attr_name()+"] > * > a",function(){var e=i(this).closest("["+t.attr_name()+"]").data(t.attr_name(!0)+"-init");e.is_hover&&t.toggle_active_tab(i(this).parent())}),i(e).on("hashchange.fndtn.tab",function(e){e.preventDefault(),t.handle_location_hash_change()})},handle_location_hash_change:function(){var e=this,i=this.S;i("["+this.attr_name()+"]",this.scope).each(function(){var n=i(this).data(e.attr_name(!0)+"-init");if(n.deep_linking){var a;if(a=n.scroll_to_content?e.scope.location.hash:e.scope.location.hash.replace("fndtn-",""),""!=a){var o=i(a);if(o.hasClass("content")&&o.parent().hasClass("tabs-content"))e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href="+a+"]").parent());else{var r=o.closest(".content").attr("id");r!=s&&e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href=#"+r+"]").parent(),a)}}else for(var l=0;l<e.default_tab_hashes.length;l++)e.toggle_active_tab(t("["+e.attr_name()+"] > * > a[href="+e.default_tab_hashes[l]+"]").parent())}})},toggle_active_tab:function(n,a){var o=this,r=o.S,l=n.closest("["+this.attr_name()+"]"),d=n.find("a"),c=n.children("a").first(),h="#"+c.attr("href").split("#")[1],u=r(h),f=n.siblings(),p=l.data(this.attr_name(!0)+"-init"),g=function(e){var s,n=t(this),a=t(this).parents("li").prev().children('[role="tab"]'),o=t(this).parents("li").next().children('[role="tab"]');switch(e.keyCode){case 37:s=a;break;case 39:s=o;break;default:s=!1}s.length&&(n.attr({tabindex:"-1","aria-selected":null}),s.attr({tabindex:"0","aria-selected":!0}).focus()),t('[role="tabpanel"]').attr("aria-hidden","true"),t("#"+t(i.activeElement).attr("href").substring(1)).attr("aria-hidden",null)},_=function(t){var i=p.scroll_to_content?o.default_tab_hashes[0]:"fndtn-"+o.default_tab_hashes[0].replace("#","");(t!==i||e.location.hash)&&(e.location.hash=t)};c.data("tab-content")&&(h="#"+c.data("tab-content").split("#")[1],u=r(h)),p.deep_linking&&(p.scroll_to_content?(_(a||h),a==s||a==h?n.parent()[0].scrollIntoView():r(h)[0].scrollIntoView()):_(a!=s?"fndtn-"+a.replace("#",""):"fndtn-"+h.replace("#",""))),n.addClass(p.active_class).triggerHandler("opened"),d.attr({"aria-selected":"true",tabindex:0}),f.removeClass(p.active_class),f.find("a").attr({"aria-selected":"false"}),u.siblings().removeClass(p.active_class).attr({"aria-hidden":"true"}),u.addClass(p.active_class).attr("aria-hidden","false").removeAttr("tabindex"),p.callback(n),u.triggerHandler("toggled",[u]),l.triggerHandler("toggled",[n]),d.off("keydown").on("keydown",g)},data_attr:function(t){return this.namespace.length>0?this.namespace+"-"+t:t},off:function(){},reflow:function(){}}}(jQuery,window,window.document),function(t,e,i){"use strict";Foundation.libs.abide={name:"abide",version:"5.5.3",settings:{live_validate:!0,validate_on_blur:!0,focus_on_invalid:!0,error_labels:!0,error_class:"error",timeout:1e3,patterns:{alpha:/^[a-zA-Z]+$/,alpha_numeric:/^[a-zA-Z0-9]+$/,integer:/^[-+]?\d+$/,number:/^[-+]?\d*(?:[\.\,]\d+)?$/,card:/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,cvv:/^([0-9]){3,4}$/,email:/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/,url:/^(https?|ftp|file|ssh):\/\/([-;:&=\+\$,\w]+@{1})?([-A-Za-z0-9\.]+)+:?(\d+)?((\/[-\+~%\/\.\w]+)?\??([-\+=&;%@\.\w]+)?#?([\w]+)?)?/,domain:/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,8}$/,datetime:/^([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))$/,date:/(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))$/,time:/^(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}$/,dateISO:/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/,month_day_year:/^(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.]\d{4}$/,day_month_year:/^(0[1-9]|[12][0-9]|3[01])[- \/.](0[1-9]|1[012])[- \/.]\d{4}$/,color:/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/}
23796,validators:{equalTo:function(t){var e=i.getElementById(t.getAttribute(this.add_namespace("data-equalto"))).value,s=t.value,n=e===s;return n}}},timer:null,init:function(t,e,i){this.bindings(e,i)},events:function(e){function i(t,e){clearTimeout(s.timer),s.timer=setTimeout(function(){s.validate([t],e)}.bind(t),a.timeout)}var s=this,n=s.S(e).attr("novalidate","novalidate"),a=n.data(this.attr_name(!0)+"-init")||{};this.invalid_attr=this.add_namespace("data-invalid"),n.off(".abide").on("submit.fndtn.abide",function(t){var e=/ajax/i.test(s.S(this).attr(s.attr_name()));return s.validate(s.S(this).find("input, textarea, select").not(":hidden, [data-abide-ignore]").get(),t,e)}).on("validate.fndtn.abide",function(t){"manual"===a.validate_on&&s.validate([t.target],t)}).on("reset",function(e){return s.reset(t(this),e)}).find("input, textarea, select").not(":hidden, [data-abide-ignore]").off(".abide").on("blur.fndtn.abide change.fndtn.abide",function(t){var e=this.getAttribute("id"),s=n.find('[data-equalto="'+e+'"]');a.validate_on_blur&&a.validate_on_blur===!0&&i(this,t),"undefined"!=typeof s.get(0)&&s.val().length&&i(s.get(0),t),"change"===a.validate_on&&i(this,t)}).on("keydown.fndtn.abide",function(t){var e=this.getAttribute("id"),s=n.find('[data-equalto="'+e+'"]');a.live_validate&&a.live_validate===!0&&9!=t.which&&i(this,t),"undefined"!=typeof s.get(0)&&s.val().length&&i(s.get(0),t),"tab"===a.validate_on&&9===t.which?i(this,t):"change"===a.validate_on&&i(this,t)}).on("focus",function(e){navigator.userAgent.match(/iPad|iPhone|Android|BlackBerry|Windows Phone|webOS/i)&&t("html, body").animate({scrollTop:t(e.target).offset().top},100)})},reset:function(e){var i=this;e.removeAttr(i.invalid_attr),t("["+i.invalid_attr+"]",e).removeAttr(i.invalid_attr),t("."+i.settings.error_class,e).not("small").removeClass(i.settings.error_class),t(":input",e).not(":button, :submit, :reset, :hidden, [data-abide-ignore]").val("").removeAttr(i.invalid_attr)},validate:function(t,e,i){for(var s=this.parse_patterns(t),n=s.length,a=this.S(t[0]).closest("form"),o=/submit/.test(e.type),r=0;n>r;r++)if(!s[r]&&(o||i))return this.settings.focus_on_invalid&&t[r].focus(),a.trigger("invalid.fndtn.abide"),this.S(t[r]).closest("form").attr(this.invalid_attr,""),!1;return(o||i)&&a.trigger("valid.fndtn.abide"),a.removeAttr(this.invalid_attr),i?!1:!0},parse_patterns:function(t){for(var e=t.length,i=[];e--;)i.push(this.pattern(t[e]));return this.check_validation_and_apply_styles(i)},pattern:function(t){var e=t.getAttribute("type"),i="string"==typeof t.getAttribute("required"),s=t.getAttribute("pattern")||"";return this.settings.patterns.hasOwnProperty(s)&&s.length>0?[t,this.settings.patterns[s],i]:s.length>0?[t,new RegExp(s),i]:this.settings.patterns.hasOwnProperty(e)?[t,this.settings.patterns[e],i]:(s=/.*/,[t,s,i])},check_validation_and_apply_styles:function(e){var i=e.length,s=[];if(0==i)return s;var n=this.S(e[0][0]).closest("[data-"+this.attr_name(!0)+"]");for(n.data(this.attr_name(!0)+"-init")||{};i--;){var a,o,r=e[i][0],l=e[i][2],d=r.value.trim(),c=this.S(r).parent(),h=r.getAttribute(this.add_namespace("data-abide-validator")),u="radio"===r.type,f="checkbox"===r.type,p=this.S('label[for="'+r.getAttribute("id")+'"]'),g=l?r.value.length>0:!0,_=[];if(r.getAttribute(this.add_namespace("data-equalto"))&&(h="equalTo"),a=c.is("label")?c.parent():c,u&&l)_.push(this.valid_radio(r,l));else if(f&&l)_.push(this.valid_checkbox(r,l));else if(h){for(var m=h.split(" "),v=!0,b=!0,x=0;x<m.length;x++)o=this.settings.validators[m[x]].apply(this,[r,l,a]),_.push(o),b=o&&v,v=o;b?(this.S(r).removeAttr(this.invalid_attr),a.removeClass("error"),p.length>0&&this.settings.error_labels&&p.removeClass(this.settings.error_class).removeAttr("role"),t(r).triggerHandler("valid")):(this.S(r).attr(this.invalid_attr,""),a.addClass("error"),p.length>0&&this.settings.error_labels&&p.addClass(this.settings.error_class).attr("role","alert"),t(r).triggerHandler("invalid"))}else if(_.push(e[i][1].test(d)&&g||!l&&r.value.length<1||t(r).attr("disabled")?!0:!1),_=[_.every(function(t){return t})],_[0])this.S(r).removeAttr(this.invalid_attr),r.setAttribute("aria-invalid","false"),r.removeAttribute("aria-describedby"),a.removeClass(this.settings.error_class),p.length>0&&this.settings.error_labels&&p.removeClass(this.settings.error_class).removeAttr("role"),t(r).triggerHandler("valid");else{this.S(r).attr(this.invalid_attr,""),r.setAttribute("aria-invalid","true");var y=a.find("small."+this.settings.error_class,"span."+this.settings.error_class),w=y.length>0?y[0].id:"";w.length>0&&r.setAttribute("aria-describedby",w),a.addClass(this.settings.error_class),p.length>0&&this.settings.error_labels&&p.addClass(this.settings.error_class).attr("role","alert"),t(r).triggerHandler("invalid")}s=s.concat(_)}return s},valid_checkbox:function(e,i){var e=this.S(e),s=e.is(":checked")||!i||e.get(0).getAttribute("disabled");return s?(e.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class),t(e).triggerHandler("valid")):(e.attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),t(e).triggerHandler("invalid")),s
23797
23798},valid_radio:function(e){for(var i=e.getAttribute("name"),s=this.S(e).closest("[data-"+this.attr_name(!0)+"]").find("[name='"+i+"']"),n=s.length,a=!1,o=!1,r=0;n>r;r++)s[r].getAttribute("disabled")?(o=!0,a=!0):s[r].checked?a=!0:o&&(a=!1);for(var r=0;n>r;r++)a?(this.S(s[r]).removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class),t(s[r]).triggerHandler("valid")):(this.S(s[r]).attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),t(s[r]).triggerHandler("invalid"));return a},valid_equal:function(t,e,s){var n=i.getElementById(t.getAttribute(this.add_namespace("data-equalto"))).value,a=t.value,o=n===a;return o?(this.S(t).removeAttr(this.invalid_attr),s.removeClass(this.settings.error_class),label.length>0&&settings.error_labels&&label.removeClass(this.settings.error_class)):(this.S(t).attr(this.invalid_attr,""),s.addClass(this.settings.error_class),label.length>0&&settings.error_labels&&label.addClass(this.settings.error_class)),o}
23798,valid_oneof:function(t,e,i,s){var t=this.S(t),n=this.S("["+this.add_namespace("data-oneof")+"]"),a=n.filter(":checked").length>0;if(a?t.removeAttr(this.invalid_attr).parent().removeClass(this.settings.error_class):t.attr(this.invalid_attr,"").parent().addClass(this.settings.error_class),!s){var o=this;n.each(function(){o.valid_oneof.call(o,this,null,null,!0)})}return a},reflow:function(){var t=this,e=t.S("["+this.attr_name()+"]").attr("novalidate","novalidate");t.S(e).each(function(e,i){t.events(i)})}}}(jQuery,window,window.document),function(t,e){"use strict";Foundation.libs.tooltip={name:"tooltip",version:"5.5.3",settings:{additional_inheritable_classes:[],tooltip_class:".tooltip",append_to:"body",touch_close_text:"Tap To Close",disable_for_touch:!1,hover_delay:200,fade_in_duration:150,fade_out_duration:150,show_on:"all",tip_template:function(t,e){return'<span data-selector="'+t+'" id="'+t+'" class="'+Foundation.libs.tooltip.settings.tooltip_class.substring(1)+'" role="tooltip">'+e+'<span class="nub"></span></span>'}},cache:{},init:function(t,e,i){Foundation.inherit(this,"random_str"),this.bindings(e,i)},should_show:function(e){var i=t.extend({},this.settings,this.data_options(e));return"all"===i.show_on?!0:this.small()&&"small"===i.show_on?!0:this.medium()&&"medium"===i.show_on?!0:this.large()&&"large"===i.show_on?!0:!1},medium:function(){return matchMedia(Foundation.media_queries.medium).matches},large:function(){return matchMedia(Foundation.media_queries.large).matches},events:function(e){function i(t,e,i){t.timer||(i?(t.timer=null,n.showTip(e)):t.timer=setTimeout(function(){t.timer=null,n.showTip(e)}.bind(t),n.settings.hover_delay))}function s(t,e){t.timer&&(clearTimeout(t.timer),t.timer=null),n.hide(e)}var n=this,a=n.S;n.create(this.S(e)),t(this.scope).off(".tooltip").on("mouseenter.fndtn.tooltip mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip","["+this.attr_name()+"]",function(e){var o=a(this),r=t.extend({},n.settings,n.data_options(o)),l=!1;if(Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&a(e.target).is("a"))return!1;if(/mouse/i.test(e.type)&&n.ie_touch(e))return!1;if(o.hasClass("open"))Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&e.preventDefault(),n.hide(o);else{if(r.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type))return;if(!r.disable_for_touch&&Modernizr.touch&&/touchstart|MSPointerDown/i.test(e.type)&&(e.preventDefault(),a(r.tooltip_class+".open").hide(),l=!0,t(".open["+n.attr_name()+"]").length>0)){var d=a(t(".open["+n.attr_name()+"]")[0]);n.hide(d)}/enter|over/i.test(e.type)?i(this,o):"mouseout"===e.type||"mouseleave"===e.type?s(this,o):i(this,o,!0)}}).on("mouseleave.fndtn.tooltip touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip","["+this.attr_name()+"].open",function(e){return/mouse/i.test(e.type)&&n.ie_touch(e)?!1:void(("touch"!=t(this).data("tooltip-open-event-type")||"mouseleave"!=e.type)&&("mouse"==t(this).data("tooltip-open-event-type")&&/MSPointerDown|touchstart/i.test(e.type)?n.convert_to_touch(t(this)):s(this,t(this))))}).on("DOMNodeRemoved DOMAttrModified","["+this.attr_name()+"]:not(a)",function(){s(this,a(this))})},ie_touch:function(){return!1},showTip:function(t){var e=this.getTip(t);return this.should_show(t,e)?this.show(t):void 0},getTip:function(e){var i=this.selector(e),s=t.extend({},this.settings,this.data_options(e)),n=null;return i&&(n=this.S('span[data-selector="'+i+'"]'+s.tooltip_class)),"object"==typeof n?n:!1},selector:function(t){var e=t.attr(this.attr_name())||t.attr("data-selector");return"string"!=typeof e&&(e=this.random_str(6),t.attr("data-selector",e).attr("aria-describedby",e)),e},create:function(i){var s=this,n=t.extend({},this.settings,this.data_options(i)),a=this.settings.tip_template;"string"==typeof n.tip_template&&e.hasOwnProperty(n.tip_template)&&(a=e[n.tip_template]);var o=t(a(this.selector(i),t("<div></div>").html(i.attr("title")).html())),r=this.inheritable_classes(i);o.addClass(r).appendTo(n.append_to),Modernizr.touch&&(o.append('<span class="tap-to-close">'+n.touch_close_text+"</span>"),o.on("touchstart.fndtn.tooltip MSPointerDown.fndtn.tooltip",function(){s.hide(i)})),i.removeAttr("title").attr("title","")},reposition:function(e,i,s){var n,a,o,r,l;i.css("visibility","hidden").show(),n=e.data("width"),a=i.children(".nub"),o=a.outerHeight(),r=a.outerWidth(),i.css(this.small
23798()?{width:"100%"}:{width:n?n:"auto"}),l=function(t,e,i,s,n){return t.css({top:e?e:"auto",bottom:s?s:"auto",left:n?n:"auto",right:i?i:"auto"}).end()};var d=e.offset().top,c=e.offset().left,h=e.outerHeight();if(l(i,d+h+10,"auto","auto",c),this.small())l(i,d+h+10,"auto","auto",12.5,t(this.scope).width()),i.addClass("tip-override"),l(a,-o,"auto","auto",c);else{Foundation.rtl&&(a.addClass("rtl"),c=c+e.outerWidth()-i.outerWidth()),l(i,d+h+10,"auto","auto",c),a.attr("style")&&a.removeAttr("style"),i.removeClass("tip-override");var u=i.outerHeight();s&&s.indexOf("tip-top")>-1?(Foundation.rtl&&a.addClass("rtl"),l(i,d-u,"auto","auto",c).removeClass("tip-override")):s&&s.indexOf("tip-left")>-1?(l(i,d+h/2-u/2,"auto","auto",c-i.outerWidth()-o).removeClass("tip-override"),a.removeClass("rtl")):s&&s.indexOf("tip-right")>-1&&(l(i,d+h/2-u/2,"auto","auto",c+e.outerWidth()+o).removeClass("tip-override"),a.removeClass("rtl"))}i.css("visibility","visible").hide()},small:function(){return matchMedia(Foundation.media_queries.small).matches&&!matchMedia(Foundation.media_queries.medium).matches},inheritable_classes:function(e){var i=t.extend({},this.settings,this.data_options(e)),s=["tip-top","tip-left","tip-bottom","tip-right","radius","round"].concat(i.additional_inheritable_classes),n=e.attr("class"),a=n?t.map(n.split(" "),function(e){return-1!==t.inArray(e,s)?e:void 0}).join(" "):"";return t.trim(a)},convert_to_touch:function(e){var i=this,s=i.getTip(e),n=t.extend({},i.settings,i.data_options(e));0===s.find(".tap-to-close").length&&(s.append('<span class="tap-to-close">'+n.touch_close_text+"</span>"),s.on("click.fndtn.tooltip.tapclose touchstart.fndtn.tooltip.tapclose MSPointerDown.fndtn.tooltip.tapclose",function(){i.hide(e)})),e.data("tooltip-open-event-type","touch")},show:function(t){var e=this.getTip(t);"touch"==t.data("tooltip-open-event-type")&&this.convert_to_touch(t),this.reposition(t,e,t.attr("class")),t.addClass("open"),e.fadeIn(this.settings.fade_in_duration)},hide:function(t){var e=this.getTip(t);e.fadeOut(this.settings.fade_out_duration,function(){e.find(".tap-to-close").remove(),e.off("click.fndtn.tooltip.tapclose MSPointerDown.fndtn.tapclose"),t.removeClass("open")})},off:function(){var e=this;this.S(this.scope).off(".fndtn.tooltip"),this.S(this.settings.tooltip_class).each(function(i){t("["+e.attr_name()+"]").eq(i).attr("title",t(this).text())}).remove()},reflow:function(){}}}(jQuery,window,window.document);
23799
23800
23801/*!
23802
23803 * jQuery Form Plugin
23804
23805 * version: 3.51.0-2014.06.20
23806
23807 * Requires jQuery v1.5 or later
23808
23809 * Copyright (c) 2014 M. Alsup
23810
23811 * Examples and documentation at: http://malsup.com/jquery/form/
23812
23813 * Project repository: https://github.com/malsup/form
23814
23815 * Dual licensed under the MIT and GPL licenses.
23816
23817 * https://github.com/malsup/form#copyright-and-license
23818
23819 */
23820
23821!function(e){"use strict";"function"==typeof define&&define.amd?define(["jquery"],e):e("undefined"!=typeof jQuery?jQuery:window.Zepto)}(function(e){"use strict";function t(t){var r=t.data;t.isDefaultPrevented()||(t.preventDefault(),e(t.target).ajaxSubmit(r))}function r(t){var r=t.target,a=e(r);if(!a.is("[type=submit],[type=image]")){var n=a.closest("[type=submit]");if(0===n.length)return;r=n[0]}var i=this;if(i.clk=r,"image"==r.type)if(void 0!==t.offsetX)i.clk_x=t.offsetX,i.clk_y=t.offsetY;else if("function"==typeof e.fn.offset){var o=a.offset();i.clk_x=t.pageX-o.left,i.clk_y=t.pageY-o.top}else i.clk_x=t.pageX-r.offsetLeft,i.clk_y=t.pageY-r.offsetTop;setTimeout(function(){i.clk=i.clk_x=i.clk_y=null},100)}function a(){if(e.fn.ajaxSubmit.debug){var t="[jquery.form] "+Array.prototype.join.call(arguments,"");window.console&&window.console.log?window.console.log(t):window.opera&&window.opera.postError&&window.opera.postError(t)}}var n={};n.fileapi=void 0!==e("<input type='file'/>").get(0).files,n.formdata=void 0!==window.FormData;var i=!!e.fn.prop;e.fn.attr2=function(){if(!i)return this.attr.apply(this,arguments);var e=this.prop.apply(this,arguments);return e&&e.jquery||"string"==typeof e?e:this.attr.apply(this,arguments)},e.fn.ajaxSubmit=function(t){function r(r){var a,n,i=e.param(r,t.traditional).split("&"),o=i.length,s=[];for(a=0;o>a;a++)i[a]=i[a].replace(/\+/g," "),n=i[a].split("="),s.push([decodeURIComponent(n[0]),decodeURIComponent(n[1])]);return s}function o(a){for(var n=new FormData,i=0;i<a.length;i++)n.append(a[i].name,a[i].value);if(t.extraData){var o=r(t.extraData);for(i=0;i<o.length;i++)o[i]&&n.append(o[i][0],o[i][1])}t.data=null;var s=e.extend(!0,{},e.ajaxSettings,t,{contentType:!1,processData:!1,cache:!1,type:u||"POST"});t.uploadProgress&&(s.xhr=function(){var r=e.ajaxSettings.xhr();return r.upload&&r.upload.addEventListener("progress",function(e){var r=0,a=e.loaded||e.position,n=e.total;e.lengthComputable&&(r=Math.ceil(a/n*100)),t.uploadProgress(e,a,n,r)},!1),r}),s.data=null;var c=s.beforeSend;return s.beforeSend=function(e,r){r.data=t.formData?t.formData:n,c&&c.call(this,e,r)},e.ajax(s)}function s(r){function n(e){var t=null;try{e.contentWindow&&(t=e.contentWindow.document)}catch(r){a("cannot get iframe.contentWindow document: "+r)}if(t)return t;try{t=e.contentDocument?e.contentDocument:e.document}catch(r){a("cannot get iframe.contentDocument: "+r),t=e.document}return t}function o(){function t(){try{var e=n(g).readyState;a("state = "+e),e&&"uninitialized"==e.toLowerCase()&&setTimeout(t,50)}catch(r){a("Server abort: ",r," (",r.name,")"),s(k),j&&clearTimeout(j),j=void 0}}
23821var r=f.attr2("target"),i=f.attr2("action"),o="multipart/form-data",c=f.attr("enctype")||f.attr("encoding")||o;w.setAttribute("target",p),(!u||/post/i.test(u))&&w.setAttribute("method","POST"),i!=m.url&&w.setAttribute("action",m.url),m.skipEncodingOverride||u&&!/post/i.test(u)||f.attr({encoding:"multipart/form-data",enctype:"multipart/form-data"}),m.timeout&&(j=setTimeout(function(){T=!0,s(D)},m.timeout));var l=[];try{if(m.extraData)for(var d in m.extraData)m.extraData.hasOwnProperty(d)&&l.push(e.isPlainObject(m.extraData[d])&&m.extraData[d].hasOwnProperty("name")&&m.extraData[d].hasOwnProperty("value")?e('<input type="hidden" name="'+m.extraData[d].name+'">').val(m.extraData[d].value).appendTo(w)[0]:e('<input type="hidden" name="'+d+'">').val(m.extraData[d]).appendTo(w)[0]);m.iframeTarget||v.appendTo("body"),g.attachEvent?g.attachEvent("onload",s):g.addEventListener("load",s,!1),setTimeout(t,15);try{w.submit()}catch(h){var x=document.createElement("form").submit;x.apply(w)}}finally{w.setAttribute("action",i),w.setAttribute("enctype",c),r?w.setAttribute("target",r):f.removeAttr("target"),e(l).remove()}}function s(t){if(!x.aborted&&!F){if(M=n(g),M||(a("cannot access response document"),t=k),t===D&&x)return x.abort("timeout"),void S.reject(x,"timeout");if(t==k&&x)return x.abort("server abort"),void S.reject(x,"error","server abort");if(M&&M.location.href!=m.iframeSrc||T){g.detachEvent?g.detachEvent("onload",s):g.removeEventListener("load",s,!1);var r,i="success";try{if(T)throw"timeout";var o="xml"==m.dataType||M.XMLDocument||e.isXMLDoc(M);if(a("isXml="+o),!o&&window.opera&&(null===M.body||!M.body.innerHTML)&&--O)return a("requeing onLoad callback, DOM not available"),void setTimeout(s,250);var u=M.body?M.body:M.documentElement;x.responseText=u?u.innerHTML:null,x.responseXML=M.XMLDocument?M.XMLDocument:M,o&&(m.dataType="xml"),x.getResponseHeader=function(e){var t={"content-type":m.dataType};return t[e.toLowerCase()]},u&&(x.status=Number(u.getAttribute("status"))||x.status,x.statusText=u.getAttribute("statusText")||x.statusText);var c=(m.dataType||"").toLowerCase(),l=/(json|script|text)/.test(c);if(l||m.textarea){var f=M.getElementsByTagName("textarea")[0];if(f)x.responseText=f.value,x.status=Number(f.getAttribute("status"))||x.status,x.statusText=f.getAttribute("statusText")||x.statusText;else if(l){var p=M.getElementsByTagName("pre")[0],h=M.getElementsByTagName("body")[0];p?x.responseText=p.textContent?p.textContent:p.innerText:h&&(x.responseText=h.textContent?h.textContent:h.innerText)}}else"xml"==c&&!x.responseXML&&x.responseText&&(x.responseXML=X(x.responseText));try{E=_(x,c,m)}catch(y){i="parsererror",x.error=r=y||i}}catch(y){a("error caught: ",y),i="error",x.error=r=y||i}x.aborted&&(a("upload aborted"),i=null),x.status&&(i=x.status>=200&&x.status<300||304===x.status?"success":"error"),"success"===i?(m.success&&m.success.call(m.context,E,"success",x),S.resolve(x.responseText,"success",x),d&&e.event.trigger("ajaxSuccess",[x,m])):i&&(void 0===r&&(r=x.statusText),m.error&&m.error.call(m.context,x,i,r),S.reject(x,"error",r),d&&e.event.trigger("ajaxError",[x,m,r])),d&&e.event.trigger("ajaxComplete",[x,m]),d&&!--e.active&&e.event.trigger("ajaxStop"),m.complete&&m.complete.call(m.context,x,i),F=!0,m.timeout&&clearTimeout(j),setTimeout(function(){m.iframeTarget?v.attr("src",m.iframeSrc):v.remove(),x.responseXML=null},100)}}}var c,l,m,d,p,v,g,x,y,b,T,j,w=f[0],S=e.Deferred();if(S.abort=function(e){x.abort(e)},r)for(l=0;l<h.length;l++)c=e(h[l]),i?c.prop("disabled",!1):c.removeAttr("disabled");if(m=e.extend(!0,{},e.ajaxSettings,t),m.context=m.context||m,p="jqFormIO"+(new Date).getTime(),m.iframeTarget?(v=e(m.iframeTarget),b=v.attr2("name"),b?p=b:v.attr2("name",p)):(v=e('<iframe name="'+p+'" src="'+m.iframeSrc+'" />'),v.css({position:"absolute",top:"-1000px",left:"-1000px"})),g=v[0],x={aborted:0,responseText:null,responseXML:null,status:0,statusText:"n/a",getAllResponseHeaders:function(){},getResponseHeader:function(){},setRequestHeader:function(){},abort:function(t){var r="timeout"===t?"timeout":"aborted";a("aborting upload... "+r),this.aborted=1;try{g.contentWindow.document.execCommand&&g.contentWindow.document.execCommand("Stop")}catch(n){}v.attr("src",m.iframeSrc),x.error=r,m.error&&m.error.call(m.context,x,r,t),d&&e.event.trigger("ajaxError",[x,m,r]),m.complete&&m.complete.call(m.context,x,r)}},d=m.global,d&&0===e.active++&&e.event.trigger("ajaxStart"),d&&e.event.trigger("ajaxSend",[x,m]),m.beforeSend&&m.beforeSend.c
23821all(m.context,x,m)===!1)return m.global&&e.active--,S.reject(),S;if(x.aborted)return S.reject(),S;y=w.clk,y&&(b=y.name,b&&!y.disabled&&(m.extraData=m.extraData||{},m.extraData[b]=y.value,"image"==y.type&&(m.extraData[b+".x"]=w.clk_x,m.extraData[b+".y"]=w.clk_y)));var D=1,k=2,A=e("meta[name=csrf-token]").attr("content"),L=e("meta[name=csrf-param]").attr("content");L&&A&&(m.extraData=m.extraData||{},m.extraData[L]=A),m.forceSync?o():setTimeout(o,10);var E,M,F,O=50,X=e.parseXML||function(e,t){return window.ActiveXObject?(t=new ActiveXObject("Microsoft.XMLDOM"),t.async="false",t.loadXML(e)):t=(new DOMParser).parseFromString(e,"text/xml"),t&&t.documentElement&&"parsererror"!=t.documentElement.nodeName?t:null},C=e.parseJSON||function(e){return window.eval("("+e+")")},_=function(t,r,a){var n=t.getResponseHeader("content-type")||"",i="xml"===r||!r&&n.indexOf("xml")>=0,o=i?t.responseXML:t.responseText;return i&&"parsererror"===o.documentElement.nodeName&&e.error&&e.error("parsererror"),a&&a.dataFilter&&(o=a.dataFilter(o,r)),"string"==typeof o&&("json"===r||!r&&n.indexOf("json")>=0?o=C(o):("script"===r||!r&&n.indexOf("javascript")>=0)&&e.globalEval(o)),o};return S}if(!this.length)return a("ajaxSubmit: skipping submit process - no element selected"),this;var u,c,l,f=this;"function"==typeof t?t={success:t}:void 0===t&&(t={}),u=t.type||this.attr2("method"),c=t.url||this.attr2("action"),l="string"==typeof c?e.trim(c):"",l=l||window.location.href||"",l&&(l=(l.match(/^([^#]+)/)||[])[1]),t=e.extend(!0,{url:l,success:e.ajaxSettings.success,type:u||e.ajaxSettings.type,iframeSrc:/^https/i.test(window.location.href||"")?"javascript:false":"about:blank"},t);var m={};if(this.trigger("form-pre-serialize",[this,t,m]),m.veto)return a("ajaxSubmit: submit vetoed via form-pre-serialize trigger"),this;if(t.beforeSerialize&&t.beforeSerialize(this,t)===!1)return a("ajaxSubmit: submit aborted via beforeSerialize callback"),this;var d=t.traditional;void 0===d&&(d=e.ajaxSettings.traditional);var p,h=[],v=this.formToArray(t.semantic,h);if(t.data&&(t.extraData=t.data,p=e.param(t.data,d)),t.beforeSubmit&&t.beforeSubmit(v,this,t)===!1)return a("ajaxSubmit: submit aborted via beforeSubmit callback"),this;if(this.trigger("form-submit-validate",[v,this,t,m]),m.veto)return a("ajaxSubmit: submit vetoed via form-submit-validate trigger"),this;var g=e.param(v,d);p&&(g=g?g+"&"+p:p),"GET"==t.type.toUpperCase()?(t.url+=(t.url.indexOf("?")>=0?"&":"?")+g,t.data=null):t.data=g;var x=[];if(t.resetForm&&x.push(function(){f.resetForm()}),t.clearForm&&x.push(function(){f.clearForm(t.includeHidden)}),!t.dataType&&t.target){var y=t.success||function(){};x.push(function(r){var a=t.replaceTarget?"replaceWith":"html";e(t.target)[a](r).each(y,arguments)})}else t.success&&x.push(t.success);if(t.success=function(e,r,a){for(var n=t.context||this,i=0,o=x.length;o>i;i++)x[i].apply(n,[e,r,a||f,f])},t.error){var b=t.error;t.error=function(e,r,a){var n=t.context||this;b.apply(n,[e,r,a,f])}}if(t.complete){var T=t.complete;t.complete=function(e,r){var a=t.context||this;T.apply(a,[e,r,f])}}var j=e("input[type=file]:enabled",this).filter(function(){return""!==e(this).val()}),w=j.length>0,S="multipart/form-data",D=f.attr("enctype")==S||f.attr("encoding")==S,k=n.fileapi&&n.formdata;a("fileAPI :"+k);var A,L=(w||D)&&!k;t.iframe!==!1&&(t.iframe||L)?t.closeKeepAlive?e.get(t.closeKeepAlive,function(){A=s(v)}):A=s(v):A=(w||D)&&k?o(v):e.ajax(t),f.removeData("jqxhr").data("jqxhr",A);for(var E=0;E<h.length;E++)h[E]=null;return this.trigger("form-submit-notify",[this,t]),this},e.fn.ajaxForm=function(n){if(n=n||{},n.delegation=n.delegation&&e.isFunction(e.fn.on),!n.delegation&&0===this.length){var i={s:this.selector,c:this.context};return!e.isReady&&i.s?(a("DOM not ready, queuing ajaxForm"),e(function(){e(i.s,i.c).ajaxForm(n)}),this):(a("terminating; zero elements found by selector"+(e.isReady?"":" (DOM not ready)")),this)}return n.delegation?(e(document).off("submit.form-plugin",this.selector,t).off("click.form-plugin",this.selector,r).on("submit.form-plugin",this.selector,n,t).on("click.form-plugin",this.selector,n,r),this):this.ajaxFormUnbind().bind("submit.form-plugin",n,t).bind("click.form-plugin",n,r)},e.fn.ajaxFormUnbind=function(){return this.unbind("submit.form-plugin click.form-plugin")},e.fn.formToArray=function(t,r){var a=[];if(0===this.length)return a;var i,o=this[0],s=this.attr("id"),u=t?o.getElementsByTagName("*"):o.elements;if(u&&!/MSIE [678]/.test(navigator.userAgent)&&(u=e(u).get()),s&&(i=e(':input[form="'+s+'"]').get(),i.length&&(u=(u||[]).concat(i))),!u||!u.length)return a;var c,l,f,m,d,p,h;for(c=0,p=u.length;p>c;c++)if(d=u[c],f=d.name,f&&!d.disabled)if(t&&o.clk&&"image"==d.type)o.clk==d&&(a.push({name:f,value:e(d).val(),type:d.type}),a.push({name:f+".x",value:o.clk_x},{name:f+".y",value:o.clk_y}));else if(m=e.fieldValue(d,!0),m&&m.constructor==Array)for(r&&r.push(d),l=0,h=m.length;h>l;l++)a.push({name:f,value:m[l]});else if(n.fileapi&&"file"==d.type){r&&r.push(d);var v=d.files;if(v.length)for(l=0;l<v.length;l++)a.push({name:f,value:v[l],type:d.type});else a.push({name:f,value:"",type:d.type})}else null!==m&&"undefined"!=typeof m&&(r&&r.push(d),a.push({name:f,value:m,type:d.type,required:d.required}));if(!t&&o.clk){var g=e(o.clk),x=g[0];f=x.name,f&&!x.disabled&&"image"==x.type&&(a.push({name:f,value:g.val()}),a.push({name:f+".x",value:o.clk_x},{name:f+".y",value:o.clk_y}))}return a}
23821,e.fn.formSerialize=function(t){return e.param(this.formToArray(t))},e.fn.fieldSerialize=function(t){var r=[];return this.each(function(){var a=this.name;if(a){var n=e.fieldValue(this,t);if(n&&n.constructor==Array)for(var i=0,o=n.length;o>i;i++)r.push({name:a,value:n[i]});else null!==n&&"undefined"!=typeof n&&r.push({name:this.name,value:n})}}),e.param(r)},e.fn.fieldValue=function(t){for(var r=[],a=0,n=this.length;n>a;a++){var i=this[a],o=e.fieldValue(i,t);null===o||"undefined"==typeof o||o.constructor==Array&&!o.length||(o.constructor==Array?e.merge(r,o):r.push(o))}return r},e.fieldValue=function(t,r){var a=t.name,n=t.type,i=t.tagName.toLowerCase();if(void 0===r&&(r=!0),r&&(!a||t.disabled||"reset"==n||"button"==n||("checkbox"==n||"radio"==n)&&!t.checked||("submit"==n||"image"==n)&&t.form&&t.form.clk!=t||"select"==i&&-1==t.selectedIndex))return null;if("select"==i){var o=t.selectedIndex;if(0>o)return null;for(var s=[],u=t.options,c="select-one"==n,l=c?o+1:u.length,f=c?o:0;l>f;f++){var m=u[f];if(m.selected){var d=m.value;if(d||(d=m.attributes&&m.attributes.value&&!m.attributes.value.specified?m.text:m.value),c)return d;s.push(d)}}return s}return e(t).val()},e.fn.clearForm=function(t){return this.each(function(){e("input,select,textarea",this).clearFields(t)})},e.fn.clearFields=e.fn.clearInputs=function(t){var r=/^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i;return this.each(function(){var a=this.type,n=this.tagName.toLowerCase();r.test(a)||"textarea"==n?this.value="":"checkbox"==a||"radio"==a?this.checked=!1:"select"==n?this.selectedIndex=-1:"file"==a?/MSIE/.test(navigator.userAgent)?e(this).replaceWith(e(this).clone(!0)):e(this).val(""):t&&(t===!0&&/hidden/.test(a)||"string"==typeof t&&e(this).is(t))&&(this.value="")})},e.fn.resetForm=function(){return this.each(function(){("function"==typeof this.reset||"object"==typeof this.reset&&!this.reset.nodeType)&&this.reset()})},e.fn.enable=function(e){return void 0===e&&(e=!0),this.each(function(){this.disabled=!e})},e.fn.selected=function(t){return void 0===t&&(t=!0),this.each(function(){var r=this.type;if("checkbox"==r||"radio"==r)this.checked=t;else if("option"==this.tagName.toLowerCase()){var a=e(this).parent("select");t&&a[0]&&"select-one"==a[0].type&&a.find("option").selected(!1),this.selected=t}})},e.fn.ajaxSubmit.debug=!1});
23822/*! Magnific Popup - v1.0.0 - 2015-12-16
23823
23824* http://dimsemenov.com/plugins/magnific-popup/
23825
23826* Copyright (c) 2015 Dmitry Semenov; */
23827
23828!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):window.jQuery||window.Zepto)}(function(a){var b,c,d,e,f,g,h="Close",i="BeforeClose",j="AfterClose",k="BeforeAppend",l="MarkupParse",m="Open",n="Change",o="mfp",p="."+o,q="mfp-ready",r="mfp-removing",s="mfp-prevent-close",t=function(){},u=!!window.jQuery,v=a(window),w=function(a,c){b.ev.on(o+a+p,c)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(c,d){b.ev.triggerHandler(o+c,d),b.st.callbacks&&(c=c.charAt(0).toLowerCase()+c.slice(1),b.st.callbacks[c]&&b.st.callbacks[c].apply(b,a.isArray(d)?d:[d]))},z=function(c){return c===g&&b.currTemplate.closeBtn||(b.currTemplate.closeBtn=a(b.st.closeMarkup.replace("%title%",b.st.tClose)),g=c),b.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(b=new t,b.init(),a.magnificPopup.instance=b)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(void 0!==a.transition)return!0;for(;b.length;)if(b.pop()+"Transition"in a)return!0;return!1};t.prototype={constructor:t,init:function(){var c=navigator.appVersion;b.isIE7=-1!==c.indexOf("MSIE 7."),b.isIE8=-1!==c.indexOf("MSIE 8."),b.isLowIE=b.isIE7||b.isIE8,b.isAndroid=/android/gi.test(c),b.isIOS=/iphone|ipad|ipod/gi.test(c),b.supportsTransition=B(),b.probablyMobile=b.isAndroid||b.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),d=a(document),b.popupsCache={}},open:function(c){var e;if(c.isObj===!1){b.items=c.items.toArray(),b.index=0;var g,h=c.items;for(e=0;e<h.length;e++)if(g=h[e],g.parsed&&(g=g.el[0]),g===c.el[0]){b.index=e;break}}else b.items=a.isArray(c.items)?c.items:[c.items],b.index=c.index||0;if(b.isOpen)return void b.updateItemHTML();b.types=[],f="",c.mainEl&&c.mainEl.length?b.ev=c.mainEl.eq(0):b.ev=d,c.key?(b.popupsCache[c.key]||(b.popupsCache[c.key]={}),b.currTemplate=b.popupsCache[c.key]):b.currTemplate={},b.st=a.extend(!0,{},a.magnificPopup.defaults,c),b.fixedContentPos="auto"===b.st.fixedContentPos?!b.probablyMobile:b.st.fixedContentPos,b.st.modal&&(b.st.closeOnContentClick=!1,b.st.closeOnBgClick=!1,b.st.showCloseBtn=!1,b.st.enableEscapeKey=!1),b.bgOverlay||(b.bgOverlay=x("bg").on("click"+p,function(){b.close()}),b.wrap=x("wrap").attr("tabindex",-1).on("click"+p,function(a){b._checkIfClose(a.target)&&b.close()}),b.container=x("container",b.wrap)),b.contentContainer=x("content"),b.st.preloader&&(b.preloader=x("preloader",b.container,b.st.tLoading));var i=a.magnificPopup.modules;for(e=0;e<i.length;e++){var j=i[e];j=j.charAt(0).toUpperCase()+j.slice(1),b["init"+j].call(b)}y("BeforeOpen"),b.st.showCloseBtn&&(b.st.closeBtnInside?(w(l,function(a,b,c,d){c.close_replaceWith=z(d.type)}),f+=" mfp-close-btn-in"):b.wrap.append(z())),b.st.alignTop&&(f+=" mfp-align-top"),b.fixedContentPos?b.wrap.css({overflow:b.st.overflowY,overflowX:"hidden",overflowY:b.
23828st.overflowY}):b.wrap.css({top:v.scrollTop(),position:"absolute"}),(b.st.fixedBgPos===!1||"auto"===b.st.fixedBgPos&&!b.fixedContentPos)&&b.bgOverlay.css({height:d.height(),position:"absolute"}),b.st.enableEscapeKey&&d.on("keyup"+p,function(a){27===a.keyCode&&b.close()}),v.on("resize"+p,function(){b.updateSize()}),b.st.closeOnContentClick||(f+=" mfp-auto-cursor"),f&&b.wrap.addClass(f);var k=b.wH=v.height(),n={};if(b.fixedContentPos&&b._hasScrollBar(k)){var o=b._getScrollbarSize();o&&(n.marginRight=o)}b.fixedContentPos&&(b.isIE7?a("body, html").css("overflow","hidden"):n.overflow="hidden");var r=b.st.mainClass;return b.isIE7&&(r+=" mfp-ie7"),r&&b._addClassToMFP(r),b.updateItemHTML(),y("BuildControls"),a("html").css(n),b.bgOverlay.add(b.wrap).prependTo(b.st.prependTo||a(document.body)),b._lastFocusedEl=document.activeElement,setTimeout(function(){b.content?(b._addClassToMFP(q),b._setFocus()):b.bgOverlay.addClass(q),d.on("focusin"+p,b._onFocusIn)},16),b.isOpen=!0,b.updateSize(k),y(m),c},close:function(){b.isOpen&&(y(i),b.isOpen=!1,b.st.removalDelay&&!b.isLowIE&&b.supportsTransition?(b._addClassToMFP(r),setTimeout(function(){b._close()},b.st.removalDelay)):b._close())},_close:function(){y(h);var c=r+" "+q+" ";if(b.bgOverlay.detach(),b.wrap.detach(),b.container.empty(),b.st.mainClass&&(c+=b.st.mainClass+" "),b._removeClassFromMFP(c),b.fixedContentPos){var e={marginRight:""};b.isIE7?a("body, html").css("overflow",""):e.overflow="",a("html").css(e)}d.off("keyup"+p+" focusin"+p),b.ev.off(p),b.wrap.attr("class","mfp-wrap").removeAttr("style"),b.bgOverlay.attr("class","mfp-bg"),b.container.attr("class","mfp-container"),!b.st.showCloseBtn||b.st.closeBtnInside&&b.currTemplate[b.currItem.type]!==!0||b.currTemplate.closeBtn&&b.currTemplate.closeBtn.detach(),b.st.autoFocusLast&&b._lastFocusedEl&&a(b._lastFocusedEl).focus(),b.currItem=null,b.content=null,b.currTemplate=null,b.prevHeight=0,y(j)},updateSize:function(a){if(b.isIOS){var c=document.documentElement.clientWidth/window.innerWidth,d=window.innerHeight*c;b.wrap.css("height",d),b.wH=d}else b.wH=a||v.height();b.fixedContentPos||b.wrap.css("height",b.wH),y("Resize")},updateItemHTML:function(){var c=b.items[b.index];b.contentContainer.detach(),b.content&&b.content.detach(),c.parsed||(c=b.parseEl(b.index));var d=c.type;if(y("BeforeChange",[b.currItem?b.currItem.type:"",d]),b.currItem=c,!b.currTemplate[d]){var f=b.st[d]?b.st[d].markup:!1;y("FirstMarkupParse",f),f?b.currTemplate[d]=a(f):b.currTemplate[d]=!0}e&&e!==c.type&&b.container.removeClass("mfp-"+e+"-holder");var g=b["get"+d.charAt(0).toUpperCase()+d.slice(1)](c,b.currTemplate[d]);b.appendContent(g,d),c.preloaded=!0,y(n,c),e=c.type,b.container.prepend(b.contentContainer),y("AfterChange")},appendContent:function(a,c){b.content=a,a?b.st.showCloseBtn&&b.st.closeBtnInside&&b.currTemplate[c]===!0?b.content.find(".mfp-close").length||b.content.append(z()):b.content=a:b.content="",y(k),b.container.addClass("mfp-"+c+"-holder"),b.contentContainer.append(b.content)},parseEl:function(c){var d,e=b.items[c];if(e.tagName?e={el:a(e)}:(d=e.type,e={data:e,src:e.src}),e.el){for(var f=b.types,g=0;g<f.length;g++)if(e.el.hasClass("mfp-"+f[g])){d=f[g];break}e.src=e.el.attr("data-mfp-src"),e.src||(e.src=e.el.attr("href"))}return e.type=d||b.st.type||"inline",e.index=c,e.parsed=!0,b.items[c]=e,y("ElementParse",e),b.items[c]},addGroup:function(a,c){var d=function(d){d.mfpEl=this,b._openClick(d,a,c)};c||(c={});var e="click.magnificPopup";c.mainEl=a,c.items?(c.isObj=!0,a.off(e).on(e,d)):(c.isObj=!1,c.delegate?a.off(e).on(e,c.delegate,d):(c.items=a,a.off(e).on(e,d)))},_openClick:function(c,d,e){var f=void 0!==e.midClick?e.midClick:a.magnificPopup.defaults.midClick;if(f||!(2===c.which||c.ctrlKey||c.metaKey||c.altKey||c.shiftKey)){var g=void 0!==e.disableOn?e.disableOn:a.magnificPopup.defaults.disableOn;if(g)if(a.isFunction(g)){if(!g.call(b))return!0}else if(v.width()<g)return!0;c.type&&(c.preventDefault(),b.isOpen&&c.stopPropagation()),e.el=a(c.mfpEl),e.delegate&&(e.items=d.find(e.delegate)),b.open(e)}},updateStatus:function(a,d){if(b.preloader){c!==a&&b.container.removeClass("mfp-s-"+c),d||"loading"!==a||(d=b.st.tLoading);var e={status:a,text:d};y("UpdateStatus",e),a=e.status,d=e.text,b.preloader.html(d),b.preloader.find("a").on("click",function(a){a.stopImmediatePropagation()}),b.container.addClass("mfp-s-"+a),c=a}},_checkIfClose:function(c){if(!a(c).hasClass(s)){var d=b.st.closeOnContentClick,e=b.st.closeOnBgClick;if(d&&e)return!0;
23828if(!b.content||a(c).hasClass("mfp-close")||b.preloader&&c===b.preloader[0])return!0;if(c===b.content[0]||a.contains(b.content[0],c)){if(d)return!0}else if(e&&a.contains(document,c))return!0;return!1}},_addClassToMFP:function(a){b.bgOverlay.addClass(a),b.wrap.addClass(a)},_removeClassFromMFP:function(a){this.bgOverlay.removeClass(a),b.wrap.removeClass(a)},_hasScrollBar:function(a){return(b.isIE7?d.height():document.body.scrollHeight)>(a||v.height())},_setFocus:function(){(b.st.focus?b.content.find(b.st.focus).eq(0):b.wrap).focus()},_onFocusIn:function(c){return c.target===b.wrap[0]||a.contains(b.wrap[0],c.target)?void 0:(b._setFocus(),!1)},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(l,[b,c,d]),a.each(c,function(a,c){if(void 0===c||c===!1)return!0;if(e=a.split("_"),e.length>1){var d=b.find(p+"-"+e[0]);if(d.length>0){var f=e[1];"replaceWith"===f?d[0]!==c[0]&&d.replaceWith(c):"img"===f?d.is("img")?d.attr("src",c):d.replaceWith('<img src="'+c+'" class="'+d.attr("class")+'" />'):d.attr(e[1],c)}}else b.find(p+"-"+a).html(c)})},_getScrollbarSize:function(){if(void 0===b.scrollbarSize){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),b.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return b.scrollbarSize}},a.magnificPopup={instance:null,proto:t.prototype,modules:[],open:function(b,c){return A(),b=b?a.extend(!0,{},b):{},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'<button title="%title%" type="button" class="mfp-close">&#215;</button>',tClose:"Close (Esc)",tLoading:"Loading...",autoFocusLast:!0}},a.fn.magnificPopup=function(c){A();var d=a(this);if("string"==typeof c)if("open"===c){var e,f=u?d.data("magnificPopup"):d[0].magnificPopup,g=parseInt(arguments[1],10)||0;f.items?e=f.items[g]:(e=d,f.delegate&&(e=e.find(f.delegate)),e=e.eq(g)),b._openClick({mfpEl:e},d,f)}else b.isOpen&&b[c].apply(b,Array.prototype.slice.call(arguments,1));else c=a.extend(!0,{},c),u?d.data("magnificPopup",c):d[0].magnificPopup=c,b.addGroup(d,c);return d};var C,D,E,F="inline",G=function(){E&&(D.after(E.addClass(C)).detach(),E=null)};a.magnificPopup.registerModule(F,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){b.types.push(F),w(h+"."+F,function(){G()})},getInline:function(c,d){if(G(),c.src){var e=b.st.inline,f=a(c.src);if(f.length){var g=f[0].parentNode;g&&g.tagName&&(D||(C=e.hiddenClass,D=x(C),C="mfp-"+C),E=f.after(D).detach().removeClass(C)),b.updateStatus("ready")}else b.updateStatus("error",e.tNotFound),f=a("<div>");return c.inlineElement=f,f}return b.updateStatus("ready"),b._parseMarkup(d,{},c),d}}});var H,I="ajax",J=function(){H&&a(document.body).removeClass(H)},K=function(){J(),b.req&&b.req.abort()};a.magnificPopup.registerModule(I,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'<a href="%url%">The content</a> could not be loaded.'},proto:{initAjax:function(){b.types.push(I),H=b.st.ajax.cursor,w(h+"."+I,K),w("BeforeChange."+I,K)},getAjax:function(c){H&&a(document.body).addClass(H),b.updateStatus("loading");var d=a.extend({url:c.src,success:function(d,e,f){var g={data:d,xhr:f};y("ParseAjax",g),b.appendContent(a(g.data),I),c.finished=!0,J(),b._setFocus(),setTimeout(function(){b.wrap.addClass(q)},16),b.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),c.finished=c.loadError=!0,b.updateStatus("error",b.st.ajax.tError.replace("%url%",c.src))}},b.st.ajax.settings);return b.req=a.ajax(d),""}}});var L,M=function(c){if(c.data&&void 0!==c.data.title)return c.data.title;
23828var d=b.st.image.titleSrc;if(d){if(a.isFunction(d))return d.call(b,c);if(c.el)return c.el.attr(d)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'<div class="mfp-figure"><div class="mfp-close"></div><figure><div class="mfp-img"></div><figcaption><div class="mfp-bottom-bar"><div class="mfp-title"></div><div class="mfp-counter"></div></div></figcaption></figure></div>',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'<a href="%url%">The image</a> could not be loaded.'},proto:{initImage:function(){var c=b.st.image,d=".image";b.types.push("image"),w(m+d,function(){"image"===b.currItem.type&&c.cursor&&a(document.body).addClass(c.cursor)}),w(h+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),v.off("resize"+p)}),w("Resize"+d,b.resizeImage),b.isLowIE&&w("AfterChange",b.resizeImage)},resizeImage:function(){var a=b.currItem;if(a&&a.img&&b.st.image.verticalFit){var c=0;b.isLowIE&&(c=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",b.wH-c)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(b.content&&b.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var c=0,d=a.img[0],e=function(f){L&&clearInterval(L),L=setInterval(function(){return d.naturalWidth>0?void b._onImageHasSize(a):(c>200&&clearInterval(L),c++,void(3===c?e(10):40===c?e(50):100===c&&e(500)))},f)};e(1)},getImage:function(c,d){var e=0,f=function(){c&&(c.img[0].complete?(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("ready")),c.hasSize=!0,c.loaded=!0,y("ImageLoadComplete")):(e++,200>e?setTimeout(f,100):g()))},g=function(){c&&(c.img.off(".mfploader"),c===b.currItem&&(b._onImageHasSize(c),b.updateStatus("error",h.tError.replace("%url%",c.src))),c.hasSize=!0,c.loaded=!0,c.loadError=!0)},h=b.st.image,i=d.find(".mfp-img");if(i.length){var j=document.createElement("img");j.className="mfp-img",c.el&&c.el.find("img").length&&(j.alt=c.el.find("img").attr("alt")),c.img=a(j).on("load.mfploader",f).on("error.mfploader",g),j.src=c.src,i.is("img")&&(c.img=c.img.clone()),j=c.img[0],j.naturalWidth>0?c.hasSize=!0:j.width||(c.hasSize=!1)}return b._parseMarkup(d,{title:M(c),img_replaceWith:c.img},c),b.resizeImage(),c.hasSize?(L&&clearInterval(L),c.loadError?(d.addClass("mfp-loading"),b.updateStatus("error",h.tError.replace("%url%",c.src))):(d.removeClass("mfp-loading"),b.updateStatus("ready")),d):(b.updateStatus("loading"),c.loading=!0,c.hasSize||(c.imgHidden=!0,d.addClass("mfp-loading"),b.findImageSize(c)),d)}}});var N,O=function(){return void 0===N&&(N=void 0!==document.createElement("p").style.MozTransform),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a,c=b.st.zoom,d=".zoom";if(c.enabled&&b.supportsTransition){var e,f,g=c.duration,j=function(a){var b=a.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+c.duration/1e3+"s "+c.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,b.css(e),b},k=function(){b.content.css("visibility","visible")};w("BuildControls"+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.content.css("visibility","hidden"),a=b._getItemToZoom(),!a)return void k();f=j(a),f.css(b._getOffset()),b.wrap.append(f),e=setTimeout(function(){f.css(b._getOffset(!0)),e=setTimeout(function(){k(),setTimeout(function(){f.remove(),a=f=null,y("ZoomAnimationEnded")},16)},g)},16)}}),w(i+d,function(){if(b._allowZoom()){if(clearTimeout(e),b.st.removalDelay=g,!a){if(a=b._getItemToZoom(),!a)return;f=j(a)}f.css(b._getOffset(!0)),b.wrap.append(f),b.content.css("visibility","hidden"),setTimeout(function(){f.css(b._getOffset())},16)}}),w(h+d,function(){b._allowZoom()&&(k(),f&&f.remove(),a=null)})}},_allowZoom:function(){return"image"===b.currItem.type},_getItemToZoom:function(){return b.currItem.hasSize?b.currItem.img:!1},_getOffset:function(c){var d;d=c?b.currItem.img:b.st.zoom.opener(b.currItem.el||b.currItem);var e=d.offset(),f=parseInt(d.css("padding-top"),10),g=parseInt(d.css("padding-bottom"),10);e.top-=a(window).scrollTop()-f;var h={width:d.width(),height:(u?d.innerHeight():d[0].offsetHeight)-g-f};return O()?h["-moz-transform"]=h.transform="translate("+e.left+"px,"+e.top+"px)":(h.left=e.left,h.top=e.top),h}}});
23828var P="iframe",Q="//about:blank",R=function(a){if(b.currTemplate[P]){var c=b.currTemplate[P].find("iframe");c.length&&(a||(c[0].src=Q),b.isIE8&&c.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'<div class="mfp-iframe-scaler"><div class="mfp-close"></div><iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe></div>',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){b.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(h+"."+P,function(){R()})},getIframe:function(c,d){var e=c.src,f=b.st.iframe;a.each(f.patterns,function(){return e.indexOf(this.index)>-1?(this.id&&(e="string"==typeof this.id?e.substr(e.lastIndexOf(this.id)+this.id.length,e.length):this.id.call(this,e)),e=this.src.replace("%id%",e),!1):void 0});var g={};return f.srcAction&&(g[f.srcAction]=e),b._parseMarkup(d,g,c),b.updateStatus("ready"),d}}});var S=function(a){var c=b.items.length;return a>c-1?a-c:0>a?c+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=b.st.gallery,e=".mfp-gallery",g=Boolean(a.fn.mfpFastClick);return b.direction=!0,c&&c.enabled?(f+=" mfp-gallery",w(m+e,function(){c.navigateByImgClick&&b.wrap.on("click"+e,".mfp-img",function(){return b.items.length>1?(b.next(),!1):void 0}),d.on("keydown"+e,function(a){37===a.keyCode?b.prev():39===a.keyCode&&b.next()})}),w("UpdateStatus"+e,function(a,c){c.text&&(c.text=T(c.text,b.currItem.index,b.items.length))}),w(l+e,function(a,d,e,f){var g=b.items.length;e.counter=g>1?T(c.tCounter,f.index,g):""}),w("BuildControls"+e,function(){if(b.items.length>1&&c.arrows&&!b.arrowLeft){var d=c.arrowMarkup,e=b.arrowLeft=a(d.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(s),f=b.arrowRight=a(d.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(s),h=g?"mfpFastClick":"click";e[h](function(){b.prev()}),f[h](function(){b.next()}),b.isIE7&&(x("b",e[0],!1,!0),x("a",e[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),b.container.append(e.add(f))}}),w(n+e,function(){b._preloadTimeout&&clearTimeout(b._preloadTimeout),b._preloadTimeout=setTimeout(function(){b.preloadNearbyImages(),b._preloadTimeout=null},16)}),void w(h+e,function(){d.off(e),b.wrap.off("click"+e),b.arrowLeft&&g&&b.arrowLeft.add(b.arrowRight).destroyMfpFastClick(),b.arrowRight=b.arrowLeft=null})):!1},next:function(){b.direction=!0,b.index=S(b.index+1),b.updateItemHTML()},prev:function(){b.direction=!1,b.index=S(b.index-1),b.updateItemHTML()},goTo:function(a){b.direction=a>=b.index,b.index=a,b.updateItemHTML()},preloadNearbyImages:function(){var a,c=b.st.gallery.preload,d=Math.min(c[0],b.items.length),e=Math.min(c[1],b.items.length);for(a=1;a<=(b.direction?e:d);a++)b._preloadItem(b.index+a);for(a=1;a<=(b.direction?d:e);a++)b._preloadItem(b.index-a)},_preloadItem:function(c){if(c=S(c),!b.items[c].preloaded){var d=b.items[c];d.parsed||(d=b.parseEl(c)),y("LazyLoad",d),"image"===d.type&&(d.img=a('<img class="mfp-img" />').on("load.mfploader",function(){d.hasSize=!0}).on("error.mfploader",function(){d.hasSize=!0,d.loadError=!0,y("LazyLoadError",d)}).attr("src",d.src)),d.preloaded=!0}}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=b.st.retina,c=a.ratio;c=isNaN(c)?c():c,c>1&&(w("ImageHasSize."+U,function(a,b){b.img.css({"max-width":b.img[0].naturalWidth/c,width:"100%"})}),w("ElementParse."+U,function(b,d){d.src=a.replaceSrc(d,c)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){v.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g,h=a(this);if(c){var i,j,k,l,m,n;h.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,v.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0],(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)&&(l=!0,d())}).on("touchend"+f,function(a){d(),l||n>1||(g=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){g=!1},b),e())})})}h.on("click"+f,function(){g||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&v.off("touchmove"+f+" touchend"+f)}}(),A()});
23829/*! waitForImages jQuery Plugin - v2.0.2 - 2015-06-02
23830
23831* https://github.com/alexanderdickson/waitForImages
23832
23833* Copyright (c) 2015 Alex Dickson; Licensed MIT */
23834
23835;(function (factory) {
23836
23837    if (typeof define === 'function' && define.amd) {
23838
23839        // AMD. Register as an anonymous module.
23840
23841        define(['jquery'], factory);
23842
23843    } else if (typeof exports === 'object') {
23844
23845        // CommonJS / nodejs module
23846
23847        module.exports = factory(require('jquery'));
23848
23849    } else {
23850
23851        // Browser globals
23852
23853        factory(jQuery);
23854
23855    }
23856
23857}(function ($) {
23858
23859    // Namespace all events.
23860
23861    var eventNamespace = 'waitForImages';
23862
23863
23864
23865    // CSS properties which contain references to images.
23866
23867    $.waitForImages = {
23868
23869        hasImageProperties: [
23870
23871            'backgroundImage',
23872
23873            'listStyleImage',
23874
23875            'borderImage',
23876
23877            'borderCornerImage',
23878
23879            'cursor'
23880
23881        ],
23882
23883        hasImageAttributes: ['srcset']
23884
23885    };
23886
23887
23888
23889    // Custom selector to find all `img` elements with a valid `src` attribute.
23890
23891    $.expr[':']['has-src'] = function (obj) {
23892
23893        // Ensure we are dealing with an `img` element with a valid
23894
23895        // `src` attribute.
23896
23897        return $(obj).is('img[src][src!=""]');
23898
23899    };
23900
23901
23902
23903    // Custom selector to find images which are not already cached by the
23904
23905    // browser.
23906
23907    $.expr[':'].uncached = function (obj) {
23908
23909        // Ensure we are dealing with an `img` element with a valid
23910
23911        // `src` attribute.
23912
23913        if (!$(obj).is(':has-src')) {
23914
23915            return false;
23916
23917        }
23918
23919
23920
23921        return !obj.complete;
23922
23923    };
23924
23925
23926
23927    $.fn.waitForImages = function () {
23928
23929
23930
23931        var allImgsLength = 0;
23932
23933        var allImgsLoaded = 0;
23934
23935        var deferred = $.Deferred();
23936
23937
23938
23939        var finishedCallback;
23940
23941        var eachCallback;
23942
23943        var waitForAll;
23944
23945
23946
23947        // Handle options object (if passed).
23948
23949        if ($.isPlainObject(arguments[0])) {
23950
23951
23952
23953            waitForAll = arguments[0].waitForAll;
23954
23955            eachCallback = arguments[0].each;
23956
23957            finishedCallback = arguments[0].finished;
23958
23959
23960
23961        } else {
23962
23963
23964
23965            // Handle if using deferred object and only one param was passed in.
23966
23967            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
23968
23969                waitForAll = arguments[0];
23970
23971            } else {
23972
23973                finishedCallback = arguments[0];
23974
23975                eachCallback = arguments[1];
23976
23977                waitForAll = arguments[2];
23978
23979            }
23980
23981
23982
23983        }
23984
23985
23986
23987        // Handle missing callbacks.
23988
23989        finishedCallback = finishedCallback || $.noop;
23990
23991        eachCallback = eachCallback || $.noop;
23992
23993
23994
23995        // Convert waitForAll to Boolean
23996
23997        waitForAll = !! waitForAll;
23998
23999
24000
24001        // Ensure callbacks are functions.
24002
24003        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
24004
24005            throw new TypeError('An invalid callback was supplied.');
24006
24007        }
24008
24009
24010
24011        this.each(function () {
24012
24013            // Build a list of all imgs, dependent on what images will
24014
24015            // be considered.
24016
24017            var obj = $(this);
24018
24019            var allImgs = [];
24020
24021            // CSS properties which may contain an image.
24022
24023            var hasImgProperties = $.waitForImages.hasImageProperties || [];
24024
24025            // Element attributes which may contain an image.
24026
24027            var hasImageAttributes = $.waitForImages.hasImageAttributes || [];
24028
24029            // To match `url()` references.
24030
24031            // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
24032
24033            var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
24034
24035
24036
24037            if (waitForAll) {
24038
24039
24040
24041                // Get all elements (including the original), as any one of
24042
24043                // them could have a background image.
24044
24045                obj.find('*').addBack().each(function () {
24046
24047                    var element = $(this);
24048
24049
24050
24051                    // If an `img` element, add it. But keep iterating in
24052
24053                    // case it has a background image too.
24054
24055                    if (element.is('img:has-src')) {
24056
24057                        allImgs.push({
24058
24059                            src: element.attr('src'),
24060
24061                            element: element[0]
24062
24063                        });
24064
24065                    }
24066
24067
24068
24069                    $.each(hasImgProperties, function (i, property) {
24070
24071                        var propertyValue = element.css(property);
24072
24073                        var match;
24074
24075
24076
24077                        // If it doesn't contain this property, skip.
24078
24079                        if (!propertyValue) {
24080
24081                            return true;
24082
24083                        }
24084
24085
24086
24087                        // Get all url() of this element.
24088
24089                        while (match = matchUrl.exec(propertyValue)) {
24090
24091                            allImgs.push({
24092
24093                                src: match[2],
24094
24095                                element: element[0]
24096
24097                            });
24098
24099                        }
24100
24101                    });
24102
24103
24104
24105                    $.each(hasImageAttributes, function (i, attribute) {
24106
24107                        var attributeValue = element.attr(attribute);
24108
24109                        var attributeValues;
24110
24111
24112
24113                        // If it doesn't contain this property, skip.
24114
24115                        if (!attributeValue) {
24116
24117                            return true;
24118
24119                        }
24120
24121
24122
24123                        // Check for multiple comma separated images
24124
24125                        attributeValues = attributeValue.split(',');
24126
24127
24128
24129                        $.each(attributeValues, function(i, value) {
24130
24131                            // Trim value and get string before first
24132
24133                            // whitespace (for use with srcset).
24134
24135                            value = $.trim(value).split(' ')[0];
24136
24137                            allImgs.push({
24138
24139                                src: value,
24140
24141                                element: element[0]
24142
24143                            });
24144
24145                        });
24146
24147                    });
24148
24149                });
24150
24151            } else {
24152
24153                // For images only, the task is simpler.
24154
24155                obj.find('img:has-src')
24156
24157                    .each(function () {
24158
24159                    allImgs.push({
24160
24161                        src: this.src,
24162
24163                        element: this
24164
24165                    });
24166
24167                });
24168
24169            }
24170
24171
24172
24173            allImgsLength = allImgs.length;
24174
24175            allImgsLoaded = 0;
24176
24177
24178
24179            // If no images found, don't bother.
24180
24181            if (allImgsLength === 0) {
24182
24183                finishedCallback.call(obj[0]);
24184
24185                deferred.resolveWith(obj[0]);
24186
24187            }
24188
24189
24190
24191            $.each(allImgs, function (i, img) {
24192
24193
24194
24195                var image = new Image();
24196
24197                var events =
24198
24199                  'load.' + eventNamespace + ' error.' + eventNamespace;
24200
24201
24202
24203                // Handle the image loading and error with the same callback.
24204
24205                $(image).one(events, function me (event) {
24206
24207                    // If an error occurred with loading the image, set the
24208
24209                    // third argument accordingly.
24210
24211                    var eachArguments = [
24212
24213                        allImgsLoaded,
24214
24215                        allImgsLength,
24216
24217                        event.type == 'load'
24218
24219                    ];
24220
24221                    allImgsLoaded++;
24222
24223
24224
24225                    eachCallback.apply(img.element, eachArguments);
24226
24227                    deferred.notifyWith(img.element, eachArguments);
24228
24229
24230
24231                    // Unbind the event listeners. I use this in addition to
24232
24233                    // `one` as one of those events won't be called (either
24234
24235                    // 'load' or 'error' will be called).
24236
24237                    $(this).off(events, me);
24238
24239
24240
24241                    if (allImgsLoaded == allImgsLength) {
24242
24243                        finishedCallback.call(obj[0]);
24244
24245                        deferred.resolveWith(obj[0]);
24246
24247                        return false;
24248
24249                    }
24250
24251
24252
24253                });
24254
24255
24256
24257                image.src = img.src;
24258
24259            });
24260
24261        });
24262
24263
24264
24265        return deferred.promise();
24266
24267
24268
24269    };
24270
24271}));
24272
24273
24274/*!
24275
24276 * JavaScript Cookie v2.0.4
24277
24278 * https://github.com/js-cookie/js-cookie
24279
24280 *
24281
24282 * Copyright 2006, 2015 Klaus Hartl & Fagner Brack
24283
24284 * Released under the MIT license
24285
24286 */
24287
24288(function (factory) {
24289
24290	if (typeof define === 'function' && define.amd) {
24291
24292		define(factory);
24293
24294	} else if (typeof exports === 'object') {
24295
24296		module.exports = factory();
24297
24298	} else {
24299
24300		var _OldCookies = window.Cookies;
24301
24302		var api = window.Cookies = factory();
24303
24304		api.noConflict = function () {
24305
24306			window.Cookies = _OldCookies;
24307
24308			return api;
24309
24310		};
24311
24312	}
24313
24314}(function () {
24315
24316	function extend () {
24317
24318		var i = 0;
24319
24320		var result = {};
24321
24322		for (; i < arguments.length; i++) {
24323
24324			var attributes = arguments[ i ];
24325
24326			for (var key in attributes) {
24327
24328				result[key] = attributes[key];
24329
24330			}
24331
24332		}
24333
24334		return result;
24335
24336	}
24337
24338
24339
24340	function init (converter) {
24341
24342		function api (key, value, attributes) {
24343
24344			var result;
24345
24346
24347
24348			// Write
24349
24350
24351
24352			if (arguments.length > 1) {
24353
24354				attributes = extend({
24355
24356					path: '/'
24357
24358				}, api.defaults, attributes);
24359
24360
24361
24362				if (typeof attributes.expires === 'number') {
24363
24364					var expires = new Date();
24365
24366					expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
24367
24368					attributes.expires = expires;
24369
24370				}
24371
24372
24373
24374				try {
24375
24376					result = JSON.stringify(value);
24377
24378					if (/^[\{\[]/.test(result)) {
24379
24380						value = result;
24381
24382					}
24383
24384				} catch (e) {}
24385
24386
24387
24388				if (!converter.write) {
24389
24390					value = encodeURIComponent(String(value))
24391
24392						.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
24393
24394				} else {
24395
24396					value = converter.write(value, key);
24397
24398				}
24399
24400
24401
24402				key = encodeURIComponent(String(key));
24403
24404				key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
24405
24406				key = key.replace(/[\(\)]/g, escape);
24407
24408
24409
24410				return (document.cookie = [
24411
24412					key, '=', value,
24413
24414					attributes.expires && '; expires=' + attributes.expires.toUTCString(), // use expires attribute, max-age is not supported by IE
24415
24416					attributes.path    && '; path=' + attributes.path,
24417
24418					attributes.domain  && '; domain=' + attributes.domain,
24419
24420					attributes.secure ? '; secure' : ''
24421
24422				].join(''));
24423
24424			}
24425
24426
24427
24428			// Read
24429
24430
24431
24432			if (!key) {
24433
24434				result = {};
24435
24436			}
24437
24438
24439
24440			// To prevent the for loop in the first place assign an empty array
24441
24442			// in case there are no cookies at all. Also prevents odd result when
24443
24444			// calling "get()"
24445
24446			var cookies = document.cookie ? document.cookie.split('; ') : [];
24447
24448			var rdecode = /(%[0-9A-Z]{2})+/g;
24449
24450			var i = 0;
24451
24452
24453
24454			for (; i < cookies.length; i++) {
24455
24456				var parts = cookies[i].split('=');
24457
24458				var name = parts[0].replace(rdecode, decodeURIComponent);
24459
24460				var cookie = parts.slice(1).join('=');
24461
24462
24463
24464				if (cookie.charAt(0) === '"') {
24465
24466					cookie = cookie.slice(1, -1);
24467
24468				}
24469
24470
24471
24472				try {
24473
24474					cookie = converter.read ?
24475
24476						converter.read(cookie, name) : converter(cookie, name) ||
24477
24478						cookie.replace(rdecode, decodeURIComponent);
24479
24480
24481
24482					if (this.json) {
24483
24484						try {
24485
24486							cookie = JSON.parse(cookie);
24487
24488						} catch (e) {}
24489
24490					}
24491
24492
24493
24494					if (key === name) {
24495
24496						result = cookie;
24497
24498						break;
24499
24500					}
24501
24502
24503
24504					if (!key) {
24505
24506						result[name] = cookie;
24507
24508					}
24509
24510				} catch (e) {}
24511
24512			}
24513
24514
24515
24516			return result;
24517
24518		}
24519
24520
24521
24522		api.get = api.set = api;
24523
24524		api.getJSON = function () {
24525
24526			return api.apply({
24527
24528				json: true
24529
24530			}, [].slice.call(arguments));
24531
24532		};
24533
24534		api.defaults = {};
24535
24536
24537
24538		api.remove = function (key, attributes) {
24539
24540			api(key, '', extend(attributes, {
24541
24542				expires: -1
24543
24544			}));
24545
24546		};
24547
24548
24549
24550		api.withConverter = init;
24551
24552
24553
24554		return api;
24555
24556	}
24557
24558
24559
24560	return init(function () {});
24561
24562}));
24563
24564
24565/*!
24566
24567 * Masonry PACKAGED v3.3.2
24568
24569 * Cascading grid layout library
24570
24571 * http://masonry.desandro.com
24572
24573 * MIT License
24574
24575 * by David DeSandro
24576
24577 */
24578
24579
24580
24581!function(a){function b(){}function c(a){function c(b){b.prototype.option||(b.prototype.option=function(b){a.isPlainObject(b)&&(this.options=a.extend(!0,this.options,b))})}function e(b,c){a.fn[b]=function(e){if("string"==typeof e){for(var g=d.c
24581all(arguments,1),h=0,i=this.length;i>h;h++){var j=this[h],k=a.data(j,b);if(k)if(a.isFunction(k[e])&&"_"!==e.charAt(0)){var l=k[e].apply(k,g);if(void 0!==l)return l}else f("no such method '"+e+"' for "+b+" instance");else f("cannot call methods on "+b+" prior to initialization; attempted to call '"+e+"'")}return this}return this.each(function(){var d=a.data(this,b);d?(d.option(e),d._init()):(d=new c(this,e),a.data(this,b,d))})}}if(a){var f="undefined"==typeof console?b:function(a){console.error(a)};return a.bridget=function(a,b){c(b),e(a,b)},a.bridget}}var d=Array.prototype.slice;"function"==typeof define&&define.amd?define("jquery-bridget/jquery.bridget",["jquery"],c):c("object"==typeof exports?require("jquery"):a.jQuery)}(window),function(a){function b(b){var c=a.event;return c.target=c.target||c.srcElement||b,c}var c=document.documentElement,d=function(){};c.addEventListener?d=function(a,b,c){a.addEventListener(b,c,!1)}:c.attachEvent&&(d=function(a,c,d){a[c+d]=d.handleEvent?function(){var c=b(a);d.handleEvent.call(d,c)}:function(){var c=b(a);d.call(a,c)},a.attachEvent("on"+c,a[c+d])});var e=function(){};c.removeEventListener?e=function(a,b,c){a.removeEventListener(b,c,!1)}:c.detachEvent&&(e=function(a,b,c){a.detachEvent("on"+b,a[b+c]);try{delete a[b+c]}catch(d){a[b+c]=void 0}});var f={bind:d,unbind:e};"function"==typeof define&&define.amd?define("eventie/eventie",f):"object"==typeof exports?module.exports=f:a.eventie=f}(window),function(){function a(){}function b(a,b){for(var c=a.length;c--;)if(a[c].listener===b)return c;return-1}function c(a){return function(){return this[a].apply(this,arguments)}}var d=a.prototype,e=this,f=e.EventEmitter;d.getListeners=function(a){var b,c,d=this._getEvents();if(a instanceof RegExp){b={};for(c in d)d.hasOwnProperty(c)&&a.test(c)&&(b[c]=d[c])}else b=d[a]||(d[a]=[]);return b},d.flattenListeners=function(a){var b,c=[];for(b=0;b<a.length;b+=1)c.push(a[b].listener);return c},d.getListenersAsObject=function(a){var b,c=this.getListeners(a);return c instanceof Array&&(b={},b[a]=c),b||c},d.addListener=function(a,c){var d,e=this.getListenersAsObject(a),f="object"==typeof c;for(d in e)e.hasOwnProperty(d)&&-1===b(e[d],c)&&e[d].push(f?c:{listener:c,once:!1});return this},d.on=c("addListener"),d.addOnceListener=function(a,b){return this.addListener(a,{listener:b,once:!0})},d.once=c("addOnceListener"),d.defineEvent=function(a){return this.getListeners(a),this},d.defineEvents=function(a){for(var b=0;b<a.length;b+=1)this.defineEvent(a[b]);return this},d.removeListener=function(a,c){var d,e,f=this.getListenersAsObject(a);for(e in f)f.hasOwnProperty(e)&&(d=b(f[e],c),-1!==d&&f[e].splice(d,1));return this},d.off=c("removeListener"),d.addListeners=function(a,b){return this.manipulateListeners(!1,a,b)},d.removeListeners=function(a,b){return this.manipulateListeners(!0,a,b)},d.manipulateListeners=function(a,b,c){var d,e,f=a?this.removeListener:this.addListener,g=a?this.removeListeners:this.addListeners;if("object"!=typeof b||b instanceof RegExp)for(d=c.length;d--;)f.call(this,b,c[d]);else for(d in b)b.hasOwnProperty(d)&&(e=b[d])&&("function"==typeof e?f.call(this,d,e):g.call(this,d,e));return this},d.removeEvent=function(a){var b,c=typeof a,d=this._getEvents();if("string"===c)delete d[a];else if(a instanceof RegExp)for(b in d)d.hasOwnProperty(b)&&a.test(b)&&delete d[b];else delete this._events;return this},d.removeAllListeners=c("removeEvent"),d.emitEvent=function(a,b){var c,d,e,f,g=this.getListenersAsObject(a);for(e in g)if(g.hasOwnProperty(e))for(d=g[e].length;d--;)c=g[e][d],c.once===!0&&this.removeListener(a,c.listener),f=c.listener.apply(this,b||[]),f===this._getOnceReturnValue()&&this.removeListener(a,c.listener);return this},d.trigger=c("emitEvent"),d.emit=function(a){var b=Array.prototype.slice.call(arguments,1);return this.emitEvent(a,b)},d.setOnceReturnValue=function(a){return this._onceReturnValue=a,this},d._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},d._getEvents=function(){return this._events||(this._events={})},a.noConflict=function(){return e.EventEmitter=f,a},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return a}):"object"==typeof module&&module.exports?module.exports=a:e.EventEmitter=a}.call(this),function(a){function b(a){if(a){if("string"==typeof d[a])return a;a=a.charAt(0).toUpperCase()+a.slice(1);for(var b,e=0,f=c.length;f>e;e++)if(b=c[e]+a,"string"==typeof d[b])return b}}var c="Webkit Moz ms Ms O".split(" "),d=document.documentElement.style;"function"==typeof define&&define.amd?define("get-style-property/get-style-property",[],function(){return b}):"object"==typeof exports?module.exports=b:a.getStyleProperty=b}(window),function(a){function b(a){var b=parseFloat(a),c=-1===a.indexOf("%")&&!isNaN(b);return c&&b}function c(){}function d(){for(var a={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},b=0,c=g.length;c>b;b++){var d=g[b];a[d]=0}return a}function e(c){function e(){if(!m){m=!0;var d=a.getComputedStyle;if(j=function(){var a=d?function(a){return d(a,null)}:function(a){return a.currentStyle};return function(b){var c=a(b);return c||f("Style returned "+c+". Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1"),c}}(),k=c("boxSizing")){var e=document.createElement("div");e.style.width="200px",e.style.padding="1px 2px 3px 4px",e.style.borderStyle="solid",e.style.borderWidth="1px 2px 3px 4px",e.style[k]="border-box";var g=document.body||document.documentElement;g.appendChild(e);var h=j(e);l=200===b(h.width),g.removeChild(e)}}}
24581function h(a){if(e(),"string"==typeof a&&(a=document.querySelector(a)),a&&"object"==typeof a&&a.nodeType){var c=j(a);if("none"===c.display)return d();var f={};f.width=a.offsetWidth,f.height=a.offsetHeight;for(var h=f.isBorderBox=!(!k||!c[k]||"border-box"!==c[k]),m=0,n=g.length;n>m;m++){var o=g[m],p=c[o];p=i(a,p);var q=parseFloat(p);f[o]=isNaN(q)?0:q}var r=f.paddingLeft+f.paddingRight,s=f.paddingTop+f.paddingBottom,t=f.marginLeft+f.marginRight,u=f.marginTop+f.marginBottom,v=f.borderLeftWidth+f.borderRightWidth,w=f.borderTopWidth+f.borderBottomWidth,x=h&&l,y=b(c.width);y!==!1&&(f.width=y+(x?0:r+v));var z=b(c.height);return z!==!1&&(f.height=z+(x?0:s+w)),f.innerWidth=f.width-(r+v),f.innerHeight=f.height-(s+w),f.outerWidth=f.width+t,f.outerHeight=f.height+u,f}}function i(b,c){if(a.getComputedStyle||-1===c.indexOf("%"))return c;var d=b.style,e=d.left,f=b.runtimeStyle,g=f&&f.left;return g&&(f.left=b.currentStyle.left),d.left=c,c=d.pixelLeft,d.left=e,g&&(f.left=g),c}var j,k,l,m=!1;return h}var f="undefined"==typeof console?c:function(a){console.error(a)},g=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"];"function"==typeof define&&define.amd?define("get-size/get-size",["get-style-property/get-style-property"],e):"object"==typeof exports?module.exports=e(require("desandro-get-style-property")):a.getSize=e(a.getStyleProperty)}(window),function(a){function b(a){"function"==typeof a&&(b.isReady?a():g.push(a))}function c(a){var c="readystatechange"===a.type&&"complete"!==f.readyState;b.isReady||c||d()}function d(){b.isReady=!0;for(var a=0,c=g.length;c>a;a++){var d=g[a];d()}}function e(e){return"complete"===f.readyState?d():(e.bind(f,"DOMContentLoaded",c),e.bind(f,"readystatechange",c),e.bind(a,"load",c)),b}var f=a.document,g=[];b.isReady=!1,"function"==typeof define&&define.amd?define("doc-ready/doc-ready",["eventie/eventie"],e):"object"==typeof exports?module.exports=e(require("eventie")):a.docReady=e(a.eventie)}(window),function(a){function b(a,b){return a[g](b)}function c(a){if(!a.parentNode){var b=document.createDocumentFragment();b.appendChild(a)}}function d(a,b){c(a);for(var d=a.parentNode.querySelectorAll(b),e=0,f=d.length;f>e;e++)if(d[e]===a)return!0;return!1}function e(a,d){return c(a),b(a,d)}var f,g=function(){if(a.matches)return"matches";if(a.matchesSelector)return"matchesSelector";for(var b=["webkit","moz","ms","o"],c=0,d=b.length;d>c;c++){var e=b[c],f=e+"MatchesSelector";if(a[f])return f}}();if(g){var h=document.createElement("div"),i=b(h,"div");f=i?b:e}else f=d;"function"==typeof define&&define.amd?define("matches-selector/matches-selector",[],function(){return f}):"object"==typeof exports?module.exports=f:window.matchesSelector=f}(Element.prototype),function(a,b){"function"==typeof define&&define.amd?define("fizzy-ui-utils/utils",["doc-ready/doc-ready","matches-selector/matches-selector"],function(c,d){return b(a,c,d)}):"object"==typeof exports?module.exports=b(a,require("doc-ready"),require("desandro-matches-selector")):a.fizzyUIUtils=b(a,a.docReady,a.matchesSelector)}(window,function(a,b,c){var d={};d.extend=function(a,b){for(var c in b)a[c]=b[c];return a},d.modulo=function(a,b){return(a%b+b)%b};var e=Object.prototype.toString;d.isArray=function(a){return"[object Array]"==e.call(a)},d.makeArray=function(a){var b=[];if(d.isArray(a))b=a;else if(a&&"number"==typeof a.length)for(var c=0,e=a.length;e>c;c++)b.push(a[c]);else b.push(a);return b},d.indexOf=Array.prototype.indexOf?function(a,b){return a.indexOf(b)}:function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},d.removeFrom=function(a,b){var c=d.indexOf(a,b);-1!=c&&a.splice(c,1)},d.isElement="function"==typeof HTMLElement||"object"==typeof HTMLElement?function(a){return a instanceof HTMLElement}:function(a){return a&&"object"==typeof a&&1==a.nodeType&&"string"==typeof a.nodeName},d.setText=function(){function a(a,c){b=b||(void 0!==document.documentElement.textContent?"textContent":"innerText"),a[b]=c}var b;return a}(),d.getParent=function(a,b){for(;a!=document.body;)if(a=a.parentNode,c(a,b))return a},d.getQueryElement=function(a){return"string"==typeof a?document.querySelector(a):a},d.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},d.filterFindElements=function(a,b){a=d.makeArray(a);for(var e=[],f=0,g=a.length;g>f;f++){var h=a[f];if(d.isElement(h))if(b){c(h,b)&&e.push(h);for(var i=h.querySelectorAll(b),j=0,k=i.length;k>j;j++)e.push(i[j])}else e.push(h)}return e},d.debounceMethod=function(a,b,c){var d=a.prototype[b],e=b+"Timeout";a.prototype[b]=function(){var a=this[e];a&&clearTimeout(a);var b=arguments,f=this;this[e]=setTimeout(function(){d.apply(f,b),delete f[e]},c||100)}},d.toDashed=function(a){return a.replace(/(.)([A-Z])/g,function(a,b,c){return b+"-"+c}).toLowerCase()};var f=a.console;return d.htmlInit=function(c,e){b(function(){for(var b=d.toDashed(e),g=document.querySelectorAll(".js-"+b),h="data-"+b+"-options",i=0,j=g.length;j>i;i++){var k,l=g[i],m=l.getAttribute(h);try{k=m&&JSON.parse(m)}catch(n){f&&f.error("Error parsing "+h+" on "+l.nodeName.toLowerCase()+(l.id?"#"+l.id:"")+": "+n);continue}var o=new c(l,k),p=a.jQuery;p&&p.data(l,e,o)}})},d}),function(a,b){"function"==typeof define&&define.amd?define("outlayer/item",["eventEmitter/EventEmitter","get-size/get-size","get-style-property/get-style-property","fizzy-ui-utils/utils"],function(c,d,e,f){return b(a,c,d,e,f)}):"object"==typeof exports?module.exports=b(a,require("wolfy87-eventemitter"),require("get-size"),require("desandro-get-style-property"),require("fizzy-ui-utils")):(a.Outlayer={}
24581,a.Outlayer.Item=b(a,a.EventEmitter,a.getSize,a.getStyleProperty,a.fizzyUIUtils))}(window,function(a,b,c,d,e){function f(a){for(var b in a)return!1;return b=null,!0}function g(a,b){a&&(this.element=a,this.layout=b,this.position={x:0,y:0},this._create())}function h(a){return a.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()})}var i=a.getComputedStyle,j=i?function(a){return i(a,null)}:function(a){return a.currentStyle},k=d("transition"),l=d("transform"),m=k&&l,n=!!d("perspective"),o={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"}[k],p=["transform","transition","transitionDuration","transitionProperty"],q=function(){for(var a={},b=0,c=p.length;c>b;b++){var e=p[b],f=d(e);f&&f!==e&&(a[e]=f)}return a}();e.extend(g.prototype,b.prototype),g.prototype._create=function(){this._transn={ingProperties:{},clean:{},onEnd:{}},this.css({position:"absolute"})},g.prototype.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},g.prototype.getSize=function(){this.size=c(this.element)},g.prototype.css=function(a){var b=this.element.style;for(var c in a){var d=q[c]||c;b[d]=a[c]}},g.prototype.getPosition=function(){var a=j(this.element),b=this.layout.options,c=b.isOriginLeft,d=b.isOriginTop,e=a[c?"left":"right"],f=a[d?"top":"bottom"],g=this.layout.size,h=-1!=e.indexOf("%")?parseFloat(e)/100*g.width:parseInt(e,10),i=-1!=f.indexOf("%")?parseFloat(f)/100*g.height:parseInt(f,10);h=isNaN(h)?0:h,i=isNaN(i)?0:i,h-=c?g.paddingLeft:g.paddingRight,i-=d?g.paddingTop:g.paddingBottom,this.position.x=h,this.position.y=i},g.prototype.layoutPosition=function(){var a=this.layout.size,b=this.layout.options,c={},d=b.isOriginLeft?"paddingLeft":"paddingRight",e=b.isOriginLeft?"left":"right",f=b.isOriginLeft?"right":"left",g=this.position.x+a[d];c[e]=this.getXValue(g),c[f]="";var h=b.isOriginTop?"paddingTop":"paddingBottom",i=b.isOriginTop?"top":"bottom",j=b.isOriginTop?"bottom":"top",k=this.position.y+a[h];c[i]=this.getYValue(k),c[j]="",this.css(c),this.emitEvent("layout",[this])},g.prototype.getXValue=function(a){var b=this.layout.options;return b.percentPosition&&!b.isHorizontal?a/this.layout.size.width*100+"%":a+"px"},g.prototype.getYValue=function(a){var b=this.layout.options;return b.percentPosition&&b.isHorizontal?a/this.layout.size.height*100+"%":a+"px"},g.prototype._transitionTo=function(a,b){this.getPosition();var c=this.position.x,d=this.position.y,e=parseInt(a,10),f=parseInt(b,10),g=e===this.position.x&&f===this.position.y;if(this.setPosition(a,b),g&&!this.isTransitioning)return void this.layoutPosition();var h=a-c,i=b-d,j={};j.transform=this.getTranslate(h,i),this.transition({to:j,onTransitionEnd:{transform:this.layoutPosition},isCleaning:!0})},g.prototype.getTranslate=function(a,b){var c=this.layout.options;return a=c.isOriginLeft?a:-a,b=c.isOriginTop?b:-b,n?"translate3d("+a+"px, "+b+"px, 0)":"translate("+a+"px, "+b+"px)"},g.prototype.goTo=function(a,b){this.setPosition(a,b),this.layoutPosition()},g.prototype.moveTo=m?g.prototype._transitionTo:g.prototype.goTo,g.prototype.setPosition=function(a,b){this.position.x=parseInt(a,10),this.position.y=parseInt(b,10)},g.prototype._nonTransition=function(a){this.css(a.to),a.isCleaning&&this._removeStyles(a.to);for(var b in a.onTransitionEnd)a.onTransitionEnd[b].call(this)},g.prototype._transition=function(a){if(!parseFloat(this.layout.options.transitionDuration))return void this._nonTransition(a);var b=this._transn;for(var c in a.onTransitionEnd)b.onEnd[c]=a.onTransitionEnd[c];for(c in a.to)b.ingProperties[c]=!0,a.isCleaning&&(b.clean[c]=!0);if(a.from){this.css(a.from);var d=this.element.offsetHeight;d=null}this.enableTransition(a.to),this.css(a.to),this.isTransitioning=!0};var r="opacity,"+h(q.transform||"transform");g.prototype.enableTransition=function(){this.isTransitioning||(this.css({transitionProperty:r,transitionDuration:this.layout.options.transitionDuration}),this.element.addEventListener(o,this,!1))},g.prototype.transition=g.prototype[k?"_transition":"_nonTransition"],g.prototype.onwebkitTransitionEnd=function(a){this.ontransitionend(a)},g.prototype.onotransitionend=function(a){this.ontransitionend(a)};var s={"-webkit-transform":"transform","-moz-transform":"transform","-o-transform":"transform"};
24581g.prototype.ontransitionend=function(a){if(a.target===this.element){var b=this._transn,c=s[a.propertyName]||a.propertyName;if(delete b.ingProperties[c],f(b.ingProperties)&&this.disableTransition(),c in b.clean&&(this.element.style[a.propertyName]="",delete b.clean[c]),c in b.onEnd){var d=b.onEnd[c];d.call(this),delete b.onEnd[c]}this.emitEvent("transitionEnd",[this])}},g.prototype.disableTransition=function(){this.removeTransitionStyles(),this.element.removeEventListener(o,this,!1),this.isTransitioning=!1},g.prototype._removeStyles=function(a){var b={};for(var c in a)b[c]="";this.css(b)};var t={transitionProperty:"",transitionDuration:""};return g.prototype.removeTransitionStyles=function(){this.css(t)},g.prototype.removeElem=function(){this.element.parentNode.removeChild(this.element),this.css({display:""}),this.emitEvent("remove",[this])},g.prototype.remove=function(){if(!k||!parseFloat(this.layout.options.transitionDuration))return void this.removeElem();var a=this;this.once("transitionEnd",function(){a.removeElem()}),this.hide()},g.prototype.reveal=function(){delete this.isHidden,this.css({display:""});var a=this.layout.options,b={},c=this.getHideRevealTransitionEndProperty("visibleStyle");b[c]=this.onRevealTransitionEnd,this.transition({from:a.hiddenStyle,to:a.visibleStyle,isCleaning:!0,onTransitionEnd:b})},g.prototype.onRevealTransitionEnd=function(){this.isHidden||this.emitEvent("reveal")},g.prototype.getHideRevealTransitionEndProperty=function(a){var b=this.layout.options[a];if(b.opacity)return"opacity";for(var c in b)return c},g.prototype.hide=function(){this.isHidden=!0,this.css({display:""});var a=this.layout.options,b={},c=this.getHideRevealTransitionEndProperty("hiddenStyle");b[c]=this.onHideTransitionEnd,this.transition({from:a.visibleStyle,to:a.hiddenStyle,isCleaning:!0,onTransitionEnd:b})},g.prototype.onHideTransitionEnd=function(){this.isHidden&&(this.css({display:"none"}),this.emitEvent("hide"))},g.prototype.destroy=function(){this.css({position:"",left:"",right:"",top:"",bottom:"",transition:"",transform:""})},g}),function(a,b){"function"==typeof define&&define.amd?define("outlayer/outlayer",["eventie/eventie","eventEmitter/EventEmitter","get-size/get-size","fizzy-ui-utils/utils","./item"],function(c,d,e,f,g){return b(a,c,d,e,f,g)}):"object"==typeof exports?module.exports=b(a,require("eventie"),require("wolfy87-eventemitter"),require("get-size"),require("fizzy-ui-utils"),require("./item")):a.Outlayer=b(a,a.eventie,a.EventEmitter,a.getSize,a.fizzyUIUtils,a.Outlayer.Item)}(window,function(a,b,c,d,e,f){function g(a,b){var c=e.getQueryElement(a);if(!c)return void(h&&h.error("Bad element for "+this.constructor.namespace+": "+(c||a)));this.element=c,i&&(this.$element=i(this.element)),this.options=e.extend({},this.constructor.defaults),this.option(b);var d=++k;this.element.outlayerGUID=d,l[d]=this,this._create(),this.options.isInitLayout&&this.layout()}var h=a.console,i=a.jQuery,j=function(){},k=0,l={};return g.namespace="outlayer",g.Item=f,g.defaults={containerStyle:{position:"relative"},isInitLayout:!0,isOriginLeft:!0,isOriginTop:!0,isResizeBound:!0,isResizingContainer:!0,transitionDuration:"0.4s",hiddenStyle:{opacity:0,transform:"scale(0.001)"},visibleStyle:{opacity:1,transform:"scale(1)"}},e.extend(g.prototype,c.prototype),g.prototype.option=function(a){e.extend(this.options,a)},g.prototype._create=function(){this.reloadItems(),this.stamps=[],this.stamp(this.options.stamp),e.extend(this.element.style,this.options.containerStyle),this.options.isResizeBound&&this.bindResize()},g.prototype.reloadItems=function(){this.items=this._itemize(this.element.children)},g.prototype._itemize=function(a){for(var b=this._filterFindItemElements(a),c=this.constructor.Item,d=[],e=0,f=b.length;f>e;e++){var g=b[e],h=new c(g,this);d.push(h)}return d},g.prototype._filterFindItemElements=function(a){return e.filterFindElements(a,this.options.itemSelector)},g.prototype.getItemElements=function(){for(var a=[],b=0,c=this.items.length;c>b;b++)a.push(this.items[b].element);return a},g.prototype.layout=function(){this._resetLayout(),this._manageStamps();var a=void 0!==this.options.isLayoutInstant?this.options.isLayoutInstant:!this._isLayoutInited;this.layoutItems(this.items,a),this._isLayoutInited=!0},g.prototype._init=g.prototype.layout,g.prototype._resetLayout=function(){this.get
24581Size()},g.prototype.getSize=function(){this.size=d(this.element)},g.prototype._getMeasurement=function(a,b){var c,f=this.options[a];f?("string"==typeof f?c=this.element.querySelector(f):e.isElement(f)&&(c=f),this[a]=c?d(c)[b]:f):this[a]=0},g.prototype.layoutItems=function(a,b){a=this._getItemsForLayout(a),this._layoutItems(a,b),this._postLayout()},g.prototype._getItemsForLayout=function(a){for(var b=[],c=0,d=a.length;d>c;c++){var e=a[c];e.isIgnored||b.push(e)}return b},g.prototype._layoutItems=function(a,b){if(this._emitCompleteOnItems("layout",a),a&&a.length){for(var c=[],d=0,e=a.length;e>d;d++){var f=a[d],g=this._getItemLayoutPosition(f);g.item=f,g.isInstant=b||f.isLayoutInstant,c.push(g)}this._processLayoutQueue(c)}},g.prototype._getItemLayoutPosition=function(){return{x:0,y:0}},g.prototype._processLayoutQueue=function(a){for(var b=0,c=a.length;c>b;b++){var d=a[b];this._positionItem(d.item,d.x,d.y,d.isInstant)}},g.prototype._positionItem=function(a,b,c,d){d?a.goTo(b,c):a.moveTo(b,c)},g.prototype._postLayout=function(){this.resizeContainer()},g.prototype.resizeContainer=function(){if(this.options.isResizingContainer){var a=this._getContainerSize();a&&(this._setContainerMeasure(a.width,!0),this._setContainerMeasure(a.height,!1))}},g.prototype._getContainerSize=j,g.prototype._setContainerMeasure=function(a,b){if(void 0!==a){var c=this.size;c.isBorderBox&&(a+=b?c.paddingLeft+c.paddingRight+c.borderLeftWidth+c.borderRightWidth:c.paddingBottom+c.paddingTop+c.borderTopWidth+c.borderBottomWidth),a=Math.max(a,0),this.element.style[b?"width":"height"]=a+"px"}},g.prototype._emitCompleteOnItems=function(a,b){function c(){e.dispatchEvent(a+"Complete",null,[b])}function d(){g++,g===f&&c()}var e=this,f=b.length;if(!b||!f)return void c();for(var g=0,h=0,i=b.length;i>h;h++){var j=b[h];j.once(a,d)}},g.prototype.dispatchEvent=function(a,b,c){var d=b?[b].concat(c):c;if(this.emitEvent(a,d),i)if(this.$element=this.$element||i(this.element),b){var e=i.Event(b);e.type=a,this.$element.trigger(e,c)}else this.$element.trigger(a,c)},g.prototype.ignore=function(a){var b=this.getItem(a);b&&(b.isIgnored=!0)},g.prototype.unignore=function(a){var b=this.getItem(a);b&&delete b.isIgnored},g.prototype.stamp=function(a){if(a=this._find(a)){this.stamps=this.stamps.concat(a);for(var b=0,c=a.length;c>b;b++){var d=a[b];this.ignore(d)}}},g.prototype.unstamp=function(a){if(a=this._find(a))for(var b=0,c=a.length;c>b;b++){var d=a[b];e.removeFrom(this.stamps,d),this.unignore(d)}},g.prototype._find=function(a){return a?("string"==typeof a&&(a=this.element.querySelectorAll(a)),a=e.makeArray(a)):void 0},g.prototype._manageStamps=function(){if(this.stamps&&this.stamps.length){this._getBoundingRect();for(var a=0,b=this.stamps.length;b>a;a++){var c=this.stamps[a];this._manageStamp(c)}}},g.prototype._getBoundingRect=function(){var a=this.element.getBoundingClientRect(),b=this.size;this._boundingRect={left:a.left+b.paddingLeft+b.borderLeftWidth,top:a.top+b.paddingTop+b.borderTopWidth,right:a.right-(b.paddingRight+b.borderRightWidth),bottom:a.bottom-(b.paddingBottom+b.borderBottomWidth)}},g.prototype._manageStamp=j,g.prototype._getElementOffset=function(a){var b=a.getBoundingClientRect(),c=this._boundingRect,e=d(a),f={left:b.left-c.left-e.marginLeft,top:b.top-c.top-e.marginTop,right:c.right-b.right-e.marginRight,bottom:c.bottom-b.bottom-e.marginBottom};return f},g.prototype.handleEvent=function(a){var b="on"+a.type;this[b]&&this[b](a)},g.prototype.bindResize=function(){this.isResizeBound||(b.bind(a,"resize",this),this.isResizeBound=!0)},g.prototype.unbindResize=function(){this.isResizeBound&&b.unbind(a,"resize",this),this.isResizeBound=!1},g.prototype.onresize=function(){function a(){b.resize(),delete b.resizeTimeout}this.resizeTimeout&&clearTimeout(this.resizeTimeout);var b=this;this.resizeTimeout=setTimeout(a,100)},g.prototype.resize=function(){this.isResizeBound&&this.needsResizeLayout()&&this.layout()},g.prototype.needsResizeLayout=function(){var a=d(this.element),b=this.size&&a;return b&&a.innerWidth!==this.size.innerWidth},g.prototype.addItems=function(a){var b=this._itemize(a);return b.length&&(this.items=this.items.concat(b)),b},g.prototype.appended=function(a){var b=this.addItems(a);b.length&&(this.layoutItems(b,!0),this.reveal(b))},g.prototype.prepended=function(a){var b=this._itemize(a);if(b.length){var c=this.items.slice(0);this.items=b.concat(c),this._resetLayout(),this._manageStamps(),this.layoutItems(b,!0),this.reveal(b),this.layoutItems(c)}},g.prototype.reveal=function(a){this._emitCompleteOnItems("reveal",a);for(var b=a&&a.length,c=0;b&&b>c;c++){var d=a[c];d.reveal()}},g.prototype.hide=function(a){this._emitCompleteOnItems("hide",a);for(var b=a&&a.length,c=0;b&&b>c;c++){var d=a[c];d.hide()}},g.prototype.revealItemElements=function(a){var b=this.getItems(a);this.reveal(b)},g.prototype.hideItemElements=function(a){var b=this.getItems(a);this.hide(b)},g.prototype.getItem=function(a){for(var b=0,c=this.items.length;c>b;b++){var d=this.items[b];if(d.element===a)return d}},g.prototype.getItems=function(a){a=e.makeArray(a);for(var b=[],c=0,d=a.length;d>c;c++){var f=a[c],g=this.getItem(f);g&&b.push(g)}return b},g.prototype.remove=function(a){var b=this.getItems(a);if(this._emitCompleteOnItems("remove",b),b&&b.length)for(var c=0,d=b.length;d>c;c++){var f=b[c];f.remove(),e.removeFrom(this.items,f)}},g.prototype.destroy=function(){var a=this.element.style;a.height="",a.position="",a.width="";for(var b=0,c=this.items.length;c>b;b++){var d=this.items[b];d.destroy()}this.unbindResize();var e=this.element.outlayerGUID;delete l[e],delete this.element.outlayerGUID,i&&i.removeData(this.element,this.constructor.namespace)},g.data=function(a){a=e.getQueryElement(a);var b=a&&a.outlayerGUID;return b&&l[b]}
24581,g.create=function(a,b){function c(){g.apply(this,arguments)}return Object.create?c.prototype=Object.create(g.prototype):e.extend(c.prototype,g.prototype),c.prototype.constructor=c,c.defaults=e.extend({},g.defaults),e.extend(c.defaults,b),c.prototype.settings={},c.namespace=a,c.data=g.data,c.Item=function(){f.apply(this,arguments)},c.Item.prototype=new f,e.htmlInit(c,a),i&&i.bridget&&i.bridget(a,c),c},g.Item=f,g}),function(a,b){"function"==typeof define&&define.amd?define(["outlayer/outlayer","get-size/get-size","fizzy-ui-utils/utils"],b):"object"==typeof exports?module.exports=b(require("outlayer"),require("get-size"),require("fizzy-ui-utils")):a.Masonry=b(a.Outlayer,a.getSize,a.fizzyUIUtils)}(window,function(a,b,c){var d=a.create("masonry");return d.prototype._resetLayout=function(){this.getSize(),this._getMeasurement("columnWidth","outerWidth"),this._getMeasurement("gutter","outerWidth"),this.measureColumns();var a=this.cols;for(this.colYs=[];a--;)this.colYs.push(0);this.maxY=0},d.prototype.measureColumns=function(){if(this.getContainerWidth(),!this.columnWidth){var a=this.items[0],c=a&&a.element;this.columnWidth=c&&b(c).outerWidth||this.containerWidth}var d=this.columnWidth+=this.gutter,e=this.containerWidth+this.gutter,f=e/d,g=d-e%d,h=g&&1>g?"round":"floor";f=Math[h](f),this.cols=Math.max(f,1)},d.prototype.getContainerWidth=function(){var a=this.options.isFitWidth?this.element.parentNode:this.element,c=b(a);this.containerWidth=c&&c.innerWidth},d.prototype._getItemLayoutPosition=function(a){a.getSize();var b=a.size.outerWidth%this.columnWidth,d=b&&1>b?"round":"ceil",e=Math[d](a.size.outerWidth/this.columnWidth);e=Math.min(e,this.cols);for(var f=this._getColGroup(e),g=Math.min.apply(Math,f),h=c.indexOf(f,g),i={x:this.columnWidth*h,y:g},j=g+a.size.outerHeight,k=this.cols+1-f.length,l=0;k>l;l++)this.colYs[h+l]=j;return i},d.prototype._getColGroup=function(a){if(2>a)return this.colYs;for(var b=[],c=this.cols+1-a,d=0;c>d;d++){var e=this.colYs.slice(d,d+a);b[d]=Math.max.apply(Math,e)}return b},d.prototype._manageStamp=function(a){var c=b(a),d=this._getElementOffset(a),e=this.options.isOriginLeft?d.left:d.right,f=e+c.outerWidth,g=Math.floor(e/this.columnWidth);g=Math.max(0,g);var h=Math.floor(f/this.columnWidth);h-=f%this.columnWidth?0:1,h=Math.min(this.cols-1,h);for(var i=(this.options.isOriginTop?d.top:d.bottom)+c.outerHeight,j=g;h>=j;j++)this.colYs[j]=Math.max(i,this.colYs[j])},d.prototype._getContainerSize=function(){this.maxY=Math.max.apply(Math,this.colYs);var a={height:this.maxY};return this.options.isFitWidth&&(a.width=this._getContainerFitWidth()),a},d.prototype._getContainerFitWidth=function(){for(var a=0,b=this.cols;--b&&0===this.colYs[b];)a++;return(this.cols-a)*this.columnWidth-this.gutter},d.prototype.needsResizeLayout=function(){var a=this.containerWidth;return this.getContainerWidth(),a!==this.containerWidth},d});
24582/* NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress
24583
24584 * @license MIT */
24585
24586
24587
24588;(function(root, factory) {
24589
24590
24591
24592  if (typeof define === 'function' && define.amd) {
24593
24594    define(factory);
24595
24596  } else if (typeof exports === 'object') {
24597
24598    module.exports = factory();
24599
24600  } else {
24601
24602    root.NProgress = factory();
24603
24604  }
24605
24606
24607
24608})(this, function() {
24609
24610  var NProgress = {};
24611
24612
24613
24614  NProgress.version = '0.2.0';
24615
24616
24617
24618  var Settings = NProgress.settings = {
24619
24620    minimum: 0.08,
24621
24622    easing: 'ease',
24623
24624    positionUsing: '',
24625
24626    speed: 200,
24627
24628    trickle: true,
24629
24630    trickleRate: 0.02,
24631
24632    trickleSpeed: 800,
24633
24634    showSpinner: true,
24635
24636    barSelector: '[role="bar"]',
24637
24638    spinnerSelector: '[role="spinner"]',
24639
24640    parent: 'body',
24641
24642    template: '<div class="bar" role="bar"><div class="peg"></div></div><div class="spinner" role="spinner"><div class="spinner-icon"></div></div>'
24643
24644  };
24645
24646
24647
24648  /**
24649
24650   * Updates configuration.
24651
24652   *
24653
24654   *     NProgress.configure({
24655
24656   *       minimum: 0.1
24657
24658   *     });
24659
24660   */
24661
24662  NProgress.configure = function(options) {
24663
24664    var key, value;
24665
24666    for (key in options) {
24667
24668      value = options[key];
24669
24670      if (value !== undefined && options.hasOwnProperty(key)) Settings[key] = value;
24671
24672    }
24673
24674
24675
24676    return this;
24677
24678  };
24679
24680
24681
24682  /**
24683
24684   * Last number.
24685
24686   */
24687
24688
24689
24690  NProgress.status = null;
24691
24692
24693
24694  /**
24695
vendor: 9,088 bytes, lines 24696-25401
24696   * Sets the progress bar status, where `n` is a number from `0.0` to `1.0`.
24697
24698   *
24699
24700   *     NProgress.set(0.4);
24701
24702   *     NProgress.set(1.0);
24703
24704   */
24705
24706
24707
24708  NProgress.set = function(n) {
24709
24710    var started = NProgress.isStarted();
24711
24712
24713
24714    n = clamp(n, Settings.minimum, 1);
24715
24716    NProgress.status = (n === 1 ? null : n);
24717
24718
24719
24720    var progress = NProgress.render(!started),
24721
24722        bar      = progress.querySelector(Settings.barSelector),
24723
24724        speed    = Settings.speed,
24725
24726        ease     = Settings.easing;
24727
24728
24729
24730    progress.offsetWidth; /* Repaint */
24731
24732
24733
24734    queue(function(next) {
24735
24736      // Set positionUsing if it hasn't already been set
24737
24738      if (Settings.positionUsing === '') Settings.positionUsing = NProgress.getPositioningCSS();
24739
24740
24741
24742      // Add transition
24743
24744      css(bar, barPositionCSS(n, speed, ease));
24745
24746
24747
24748      if (n === 1) {
24749
24750        // Fade out
24751
24752        css(progress, { 
24753
24754          transition: 'none', 
24755
24756          opacity: 1 
24757
24758        });
24759
24760        progress.offsetWidth; /* Repaint */
24761
24762
24763
24764        setTimeout(function() {
24765
24766          css(progress, { 
24767
24768            transition: 'all ' + speed + 'ms linear', 
24769
24770            opacity: 0 
24771
24772          });
24773
24774          setTimeout(function() {
24775
24776            NProgress.remove();
24777
24778            next();
24779
24780          }, speed);
24781
24782        }, speed);
24783
24784      } else {
24785
24786        setTimeout(next, speed);
24787
24788      }
24789
24790    });
24791
24792
24793
24794    return this;
24795
24796  };
24797
24798
24799
24800  NProgress.isStarted = function() {
24801
24802    return typeof NProgress.status === 'number';
24803
24804  };
24805
24806
24807
24808  /**
24809
24810   * Shows the progress bar.
24811
24812   * This is the same as setting the status to 0%, except that it doesn't go backwards.
24813
24814   *
24815
24816   *     NProgress.start();
24817
24818   *
24819
24820   */
24821
24822  NProgress.start = function() {
24823
24824    if (!NProgress.status) NProgress.set(0);
24825
24826
24827
24828    var work = function() {
24829
24830      setTimeout(function() {
24831
24832        if (!NProgress.status) return;
24833
24834        NProgress.trickle();
24835
24836        work();
24837
24838      }, Settings.trickleSpeed);
24839
24840    };
24841
24842
24843
24844    if (Settings.trickle) work();
24845
24846
24847
24848    return this;
24849
24850  };
24851
24852
24853
24854  /**
24855
24856   * Hides the progress bar.
24857
24858   * This is the *sort of* the same as setting the status to 100%, with the
24859
24860   * difference being `done()` makes some placebo effect of some realistic motion.
24861
24862   *
24863
24864   *     NProgress.done();
24865
24866   *
24867
24868   * If `true` is passed, it will show the progress bar even if its hidden.
24869
24870   *
24871
24872   *     NProgress.done(true);
24873
24874   */
24875
24876
24877
24878  NProgress.done = function(force) {
24879
24880    if (!force && !NProgress.status) return this;
24881
24882
24883
24884    return NProgress.inc(0.3 + 0.5 * Math.random()).set(1);
24885
24886  };
24887
24888
24889
24890  /**
24891
24892   * Increments by a random amount.
24893
24894   */
24895
24896
24897
24898  NProgress.inc = function(amount) {
24899
24900    var n = NProgress.status;
24901
24902
24903
24904    if (!n) {
24905
24906      return NProgress.start();
24907
24908    } else {
24909
24910      if (typeof amount !== 'number') {
24911
24912        amount = (1 - n) * clamp(Math.random() * n, 0.1, 0.95);
24913
24914      }
24915
24916
24917
24918      n = clamp(n + amount, 0, 0.994);
24919
24920      return NProgress.set(n);
24921
24922    }
24923
24924  };
24925
24926
24927
24928  NProgress.trickle = function() {
24929
24930    return NProgress.inc(Math.random() * Settings.trickleRate);
24931
24932  };
24933
24934
24935
24936  /**
24937
24938   * Waits for all supplied jQuery promises and
24939
24940   * increases the progress as the promises resolve.
24941
24942   *
24943
24944   * @param $promise jQUery Promise
24945
24946   */
24947
24948  (function() {
24949
24950    var initial = 0, current = 0;
24951
24952
24953
24954    NProgress.promise = function($promise) {
24955
24956      if (!$promise || $promise.state() === "resolved") {
24957
24958        return this;
24959
24960      }
24961
24962
24963
24964      if (current === 0) {
24965
24966        NProgress.start();
24967
24968      }
24969
24970
24971
24972      initial++;
24973
24974      current++;
24975
24976
24977
24978      $promise.always(function() {
24979
24980        current--;
24981
24982        if (current === 0) {
24983
24984            initial = 0;
24985
24986            NProgress.done();
24987
24988        } else {
24989
24990            NProgress.set((initial - current) / initial);
24991
24992        }
24993
24994      });
24995
24996
24997
24998      return this;
24999
25000    };
25001
25002
25003
25004  })();
25005
25006
25007
25008  /**
25009
25010   * (Internal) renders the progress bar markup based on the `template`
25011
25012   * setting.
25013
25014   */
25015
25016
25017
25018  NProgress.render = function(fromStart) {
25019
25020    if (NProgress.isRendered()) return document.getElementById('nprogress');
25021
25022
25023
25024    addClass(document.documentElement, 'nprogress-busy');
25025
25026    
25027
25028    var progress = document.createElement('div');
25029
25030    progress.id = 'nprogress';
25031
25032    progress.innerHTML = Settings.template;
25033
25034
25035
25036    var bar      = progress.querySelector(Settings.barSelector),
25037
25038        perc     = fromStart ? '-100' : toBarPerc(NProgress.status || 0),
25039
25040        parent   = document.querySelector(Settings.parent),
25041
25042        spinner;
25043
25044    
25045
25046    css(bar, {
25047
25048      transition: 'all 0 linear',
25049
25050      transform: 'translate3d(' + perc + '%,0,0)'
25051
25052    });
25053
25054
25055
25056    if (!Settings.showSpinner) {
25057
25058      spinner = progress.querySelector(Settings.spinnerSelector);
25059
25060      spinner && removeElement(spinner);
25061
25062    }
25063
25064
25065
25066    if (parent != document.body) {
25067
25068      addClass(parent, 'nprogress-custom-parent');
25069
25070    }
25071
25072
25073
25074    parent.appendChild(progress);
25075
25076    return progress;
25077
25078  };
25079
25080
25081
25082  /**
25083
25084   * Removes the element. Opposite of render().
25085
25086   */
25087
25088
25089
25090  NProgress.remove = function() {
25091
25092    removeClass(document.documentElement, 'nprogress-busy');
25093
25094    removeClass(document.querySelector(Settings.parent), 'nprogress-custom-parent');
25095
25096    var progress = document.getElementById('nprogress');
25097
25098    progress && removeElement(progress);
25099
25100  };
25101
25102
25103
25104  /**
25105
25106   * Checks if the progress bar is rendered.
25107
25108   */
25109
25110
25111
25112  NProgress.isRendered = function() {
25113
25114    return !!document.getElementById('nprogress');
25115
25116  };
25117
25118
25119
25120  /**
25121
25122   * Determine which positioning CSS rule to use.
25123
25124   */
25125
25126
25127
25128  NProgress.getPositioningCSS = function() {
25129
25130    // Sniff on document.body.style
25131
25132    var bodyStyle = document.body.style;
25133
25134
25135
25136    // Sniff prefixes
25137
25138    var vendorPrefix = ('WebkitTransform' in bodyStyle) ? 'Webkit' :
25139
25140                       ('MozTransform' in bodyStyle) ? 'Moz' :
25141
25142                       ('msTransform' in bodyStyle) ? 'ms' :
25143
25144                       ('OTransform' in bodyStyle) ? 'O' : '';
25145
25146
25147
25148    if (vendorPrefix + 'Perspective' in bodyStyle) {
25149
25150      // Modern browsers with 3D support, e.g. Webkit, IE10
25151
25152      return 'translate3d';
25153
25154    } else if (vendorPrefix + 'Transform' in bodyStyle) {
25155
25156      // Browsers without 3D support, e.g. IE9
25157
25158      return 'translate';
25159
25160    } else {
25161
25162      // Browsers without translate() support, e.g. IE7-8
25163
25164      return 'margin';
25165
25166    }
25167
25168  };
25169
25170
25171
25172  /**
25173
25174   * Helpers
25175
25176   */
25177
25178
25179
25180  function clamp(n, min, max) {
25181
25182    if (n < min) return min;
25183
25184    if (n > max) return max;
25185
25186    return n;
25187
25188  }
25189
25190
25191
25192  /**
25193
25194   * (Internal) converts a percentage (`0..1`) to a bar translateX
25195
25196   * percentage (`-100%..0%`).
25197
25198   */
25199
25200
25201
25202  function toBarPerc(n) {
25203
25204    return (-1 + n) * 100;
25205
25206  }
25207
25208
25209
25210
25211
25212  /**
25213
25214   * (Internal) returns the correct CSS for changing the bar's
25215
25216   * position given an n percentage, and speed and ease from Settings
25217
25218   */
25219
25220
25221
25222  function barPositionCSS(n, speed, ease) {
25223
25224    var barCSS;
25225
25226
25227
25228    if (Settings.positionUsing === 'translate3d') {
25229
25230      barCSS = { transform: 'translate3d('+toBarPerc(n)+'%,0,0)' };
25231
25232    } else if (Settings.positionUsing === 'translate') {
25233
25234      barCSS = { transform: 'translate('+toBarPerc(n)+'%,0)' };
25235
25236    } else {
25237
25238      barCSS = { 'margin-left': toBarPerc(n)+'%' };
25239
25240    }
25241
25242
25243
25244    barCSS.transition = 'all '+speed+'ms '+ease;
25245
25246
25247
25248    return barCSS;
25249
25250  }
25251
25252
25253
25254  /**
25255
25256   * (Internal) Queues a function to be executed.
25257
25258   */
25259
25260
25261
25262  var queue = (function() {
25263
25264    var pending = [];
25265
25266    
25267
25268    function next() {
25269
25270      var fn = pending.shift();
25271
25272      if (fn) {
25273
25274        fn(next);
25275
25276      }
25277
25278    }
25279
25280
25281
25282    return function(fn) {
25283
25284      pending.push(fn);
25285
25286      if (pending.length == 1) next();
25287
25288    };
25289
25290  })();
25291
25292
25293
25294  /**
25295
25296   * (Internal) Applies css properties to an element, similar to the jQuery 
25297
25298   * css method.
25299
25300   *
25301
25302   * While this helper does assist with vendor prefixed property names, it 
25303
25304   * does not perform any manipulation of values prior to setting styles.
25305
25306   */
25307
25308
25309
25310  var css = (function() {
25311
25312    var cssPrefixes = [ 'Webkit', 'O', 'Moz', 'ms' ],
25313
25314        cssProps    = {};
25315
25316
25317
25318    function camelCase(string) {
25319
25320      return string.replace(/^-ms-/, 'ms-').replace(/-([\da-z])/gi, function(match, letter) {
25321
25322        return letter.toUpperCase();
25323
25324      });
25325
25326    }
25327
25328
25329
25330    function getVendorProp(name) {
25331
25332      var style = document.body.style;
25333
25334      if (name in style) return name;
25335
25336
25337
25338      var i = cssPrefixes.length,
25339
25340          capName = name.charAt(0).toUpperCase() + name.slice(1),
25341
25342          vendorName;
25343
25344      while (i--) {
25345
25346        vendorName = cssPrefixes[i] + capName;
25347
25348        if (vendorName in style) return vendorName;
25349
25350      }
25351
25352
25353
25354      return name;
25355
25356    }
25357
25358
25359
25360    function getStyleProp(name) {
25361
25362      name = camelCase(name);
25363
25364      return cssProps[name] || (cssProps[name] = getVendorProp(name));
25365
25366    }
25367
25368
25369
25370    function applyCss(element, prop, value) {
25371
25372      prop = getStyleProp(prop);
25373
25374      element.style[prop] = value;
25375
25376    }
25377
25378
25379
25380    return function(element, properties) {
25381
25382      var args = arguments,
25383
25384          prop, 
25385
25386          value;
25387
25388
25389
25390      if (args.length == 2) {
25391
25392        for (prop in properties) {
25393
25394          value = properties[prop];
25395
25396          if (value !== undefined && properties.hasOwnProperty(prop)) applyCss(element, prop, value);
25397
25398        }
25399
25400      } else {
25401
25402        applyCss(element, args[1], args[2]);
25403
25404      }
25405
25406    }
25407
25408  })();
25409
25410
25411
25412  /**
25413
25414   * (Internal) Determines if an element or space separated list of class names contains a class name.
25415
25416   */
25417
25418
25419
25420  function hasClass(element, name) {
25421
25422    var list = typeof element == 'string' ? element : classList(element);
25423
25424    return list.indexOf(' ' + name + ' ') >= 0;
25425
25426  }
25427
25428
25429
25430  /**
25431
25432   * (Internal) Adds a class to an element.
25433
25434   */
25435
25436
25437
25438  function addClass(element, name) {
25439
25440    var oldList = classList(element),
25441
25442        newList = oldList + name;
25443
25444
25445
25446    if (hasClass(oldList, name)) return; 
25447
25448
25449
25450    // Trim the opening space.
25451
25452    element.className = newList.substring(1);
25453
25454  }
25455
25456
25457
25458  /**
25459
25460   * (Internal) Removes a class from an element.
25461
25462   */
25463
25464
25465
25466  function removeClass(element, name) {
25467
25468    var oldList = classList(element),
25469
25470        newList;
25471
25472
25473
25474    if (!hasClass(element, name)) return;
25475
25476
25477
25478    // Replace the class name.
25479
25480    newList = oldList.replace(' ' + name + ' ', ' ');
25481
25482
25483
25484    // Trim the opening and closing spaces.
25485
25486    element.className = newList.substring(1, newList.length - 1);
25487
25488  }
25489
25490
25491
25492  /**
25493
25494   * (Internal) Gets a space separated list of the class names on the element. 
25495
25496   * The list is wrapped with a single space on each end to facilitate finding 
25497
25498   * matches within the list.
25499
25500   */
25501
25502
25503
25504  function classList(element) {
25505
25506    return (' ' + (element.className || '') + ' ').replace(/\s+/gi, ' ');
25507
25508  }
25509
25510
25511
25512  /**
25513
25514   * (Internal) Removes an element from the DOM.
25515
25516   */
25517
25518
25519
25520  function removeElement(element) {
25521
25522    element && element.parentNode && element.parentNode.removeChild(element);
25523
25524  }
25525
25526
25527
25528  return NProgress;
25529
25530});
25531
25532
25533
25534
25535/*
25536
25537     _ _      _       _
25538
25539 ___| (_) ___| | __  (_)___
25540
25541/ __| | |/ __| |/ /  | / __|
25542
25543\__ \ | | (__|   < _ | \__ \
25544
25545|___/_|_|\___|_|\_(_)/ |___/
25546
25547                   |__/
25548
25549
25550
25551 Version: 1.8.0
25552
25553  Author: Ken Wheeler
25554
25555 Website: http://kenwheeler.github.io
25556
25557    Docs: http://kenwheeler.github.io/slick
25558
25559    Repo: http://github.com/kenwheeler/slick
25560
25561  Issues: http://github.com/kenwheeler/slick/issues
25562
25563
25564
25565 */
25566
25567/* global window, document, define, jQuery, setInterval, clearInterval */
25568
25569;(function(factory) {
25570
25571    'use strict';
25572
25573    if (typeof define === 'function' && define.amd) {
25574
25575        define(['jquery'], factory);
25576
25577    } else if (typeof exports !== 'undefined') {
25578
25579        module.exports = factory(require('jquery'));
25580
25581    } else {
25582
25583        factory(jQuery);
25584
25585    }
25586
25587
25588
25589}(function($) {
25590
25591    'use strict';
25592
25593    var Slick = window.Slick || {};
25594
25595
25596
25597    Slick = (function() {
25598
25599
25600
25601        var instanceUid = 0;
25602
25603
25604
25605        function Slick(element, settings) {
25606
25607
25608
25609            var _ = this, dataSettings;
25610
25611
25612
25613            _.defaults = {
25614
25615                accessibility: true,
25616
25617                adaptiveHeight: false,
25618
25619                appendArrows: $(element),
25620
25621                appendDots: $(element),
25622
25623                arrows: true,
25624
25625                asNavFor: null,
25626
25627                prevArrow: '<button class="slick-prev" aria-label="Previous" type="button">Previous</button>',
25628
25629                nextArrow: '<button class="slick-next" aria-label="Next" type="button">Next</button>',
25630
25631                autoplay: false,
25632
25633                autoplaySpeed: 3000,
25634
25635                centerMode: false,
25636
25637                centerPadding: '50px',
25638
25639                cssEase: 'ease',
25640
25641                customPaging: function(slider, i) {
25642
25643                    return $('<button type="button" />').text(i + 1);
25644
25645                },
25646
25647                dots: false,
25648
25649                dotsClass: 'slick-dots',
25650
25651                draggable: true,
25652
25653                easing: 'linear',
25654
25655                edgeFriction: 0.35,
25656
25657                fade: false,
25658
25659                focusOnSelect: false,
25660
25661                focusOnChange: false,
25662
25663                infinite: true,
25664
25665                initialSlide: 0,
25666
25667                lazyLoad: 'ondemand',
25668
25669                mobileFirst: false,
25670
25671                pauseOnHover: true,
25672
25673                pauseOnFocus: true,
25674
25675                pauseOnDotsHover: false,
25676
25677                respondTo: 'window',
25678
25679                responsive: null,
25680
25681                rows: 1,
25682
25683                rtl: false,
25684
25685                slide: '',
25686
25687                slidesPerRow: 1,
25688
25689                slidesToShow: 1,
25690
25691                slidesToScroll: 1,
25692
25693                speed: 500,
25694
25695                swipe: true,
25696
25697                swipeToSlide: false,
25698
25699                touchMove: true,
25700
25701                touchThreshold: 5,
25702
25703                useCSS: true,
25704
25705                useTransform: true,
25706
25707                variableWidth: false,
25708
25709                vertical: false,
25710
25711                verticalSwiping: false,
25712
25713                waitForAnimate: true,
25714
25715                zIndex: 1000
25716
25717            };
25718
25719
25720
25721            _.initials = {
25722
25723                animating: false,
25724
25725                dragging: false,
25726
25727                autoPlayTimer: null,
25728
25729                currentDirection: 0,
25730
25731                currentLeft: null,
25732
25733                currentSlide: 0,
25734
25735                direction: 1,
25736
25737                $dots: null,
25738
25739                listWidth: null,
25740
25741                listHeight: null,
25742
25743                loadIndex: 0,
25744
25745                $nextArrow: null,
25746
25747                $prevArrow: null,
25748
25749                scrolling: false,
25750
25751                slideCount: null,
25752
25753                slideWidth: null,
25754
25755                $slideTrack: null,
25756
25757                $slides: null,
25758
25759                sliding: false,
25760
25761                slideOffset: 0,
25762
25763                swipeLeft: null,
25764
25765                swiping: false,
25766
25767                $list: null,
25768
25769                touchObject: {},
25770
25771                transformsEnabled: false,
25772
vendor: 83,404 bytes, lines 25773-31199
25773                unslicked: false
25774
25775            };
25776
25777
25778
25779            $.extend(_, _.initials);
25780
25781
25782
25783            _.activeBreakpoint = null;
25784
25785            _.animType = null;
25786
25787            _.animProp = null;
25788
25789            _.breakpoints = [];
25790
25791            _.breakpointSettings = [];
25792
25793            _.cssTransitions = false;
25794
25795            _.focussed = false;
25796
25797            _.interrupted = false;
25798
25799            _.hidden = 'hidden';
25800
25801            _.paused = true;
25802
25803            _.positionProp = null;
25804
25805            _.respondTo = null;
25806
25807            _.rowCount = 1;
25808
25809            _.shouldClick = true;
25810
25811            _.$slider = $(element);
25812
25813            _.$slidesCache = null;
25814
25815            _.transformType = null;
25816
25817            _.transitionType = null;
25818
25819            _.visibilityChange = 'visibilitychange';
25820
25821            _.windowWidth = 0;
25822
25823            _.windowTimer = null;
25824
25825
25826
25827            dataSettings = $(element).data('slick') || {};
25828
25829
25830
25831            _.options = $.extend({}, _.defaults, settings, dataSettings);
25832
25833
25834
25835            _.currentSlide = _.options.initialSlide;
25836
25837
25838
25839            _.originalSettings = _.options;
25840
25841
25842
25843            if (typeof document.mozHidden !== 'undefined') {
25844
25845                _.hidden = 'mozHidden';
25846
25847                _.visibilityChange = 'mozvisibilitychange';
25848
25849            } else if (typeof document.webkitHidden !== 'undefined') {
25850
25851                _.hidden = 'webkitHidden';
25852
25853                _.visibilityChange = 'webkitvisibilitychange';
25854
25855            }
25856
25857
25858
25859            _.autoPlay = $.proxy(_.autoPlay, _);
25860
25861            _.autoPlayClear = $.proxy(_.autoPlayClear, _);
25862
25863            _.autoPlayIterator = $.proxy(_.autoPlayIterator, _);
25864
25865            _.changeSlide = $.proxy(_.changeSlide, _);
25866
25867            _.clickHandler = $.proxy(_.clickHandler, _);
25868
25869            _.selectHandler = $.proxy(_.selectHandler, _);
25870
25871            _.setPosition = $.proxy(_.setPosition, _);
25872
25873            _.swipeHandler = $.proxy(_.swipeHandler, _);
25874
25875            _.dragHandler = $.proxy(_.dragHandler, _);
25876
25877            _.keyHandler = $.proxy(_.keyHandler, _);
25878
25879
25880
25881            _.instanceUid = instanceUid++;
25882
25883
25884
25885            // A simple way to check for HTML strings
25886
25887            // Strict HTML recognition (must start with <)
25888
25889            // Extracted from jQuery v1.11 source
25890
25891            _.htmlExpr = /^(?:\s*(<[\w\W]+>)[^>]*)$/;
25892
25893
25894
25895
25896
25897            _.registerBreakpoints();
25898
25899            _.init(true);
25900
25901
25902
25903        }
25904
25905
25906
25907        return Slick;
25908
25909
25910
25911    }());
25912
25913
25914
25915    Slick.prototype.activateADA = function() {
25916
25917        var _ = this;
25918
25919
25920
25921        _.$slideTrack.find('.slick-active').attr({
25922
25923            'aria-hidden': 'false'
25924
25925        }).find('a, input, button, select').attr({
25926
25927            'tabindex': '0'
25928
25929        });
25930
25931
25932
25933    };
25934
25935
25936
25937    Slick.prototype.addSlide = Slick.prototype.slickAdd = function(markup, index, addBefore) {
25938
25939
25940
25941        var _ = this;
25942
25943
25944
25945        if (typeof(index) === 'boolean') {
25946
25947            addBefore = index;
25948
25949            index = null;
25950
25951        } else if (index < 0 || (index >= _.slideCount)) {
25952
25953            return false;
25954
25955        }
25956
25957
25958
25959        _.unload();
25960
25961
25962
25963        if (typeof(index) === 'number') {
25964
25965            if (index === 0 && _.$slides.length === 0) {
25966
25967                $(markup).appendTo(_.$slideTrack);
25968
25969            } else if (addBefore) {
25970
25971                $(markup).insertBefore(_.$slides.eq(index));
25972
25973            } else {
25974
25975                $(markup).insertAfter(_.$slides.eq(index));
25976
25977            }
25978
25979        } else {
25980
25981            if (addBefore === true) {
25982
25983                $(markup).prependTo(_.$slideTrack);
25984
25985            } else {
25986
25987                $(markup).appendTo(_.$slideTrack);
25988
25989            }
25990
25991        }
25992
25993
25994
25995        _.$slides = _.$slideTrack.children(this.options.slide);
25996
25997
25998
25999        _.$slideTrack.children(this.options.slide).detach();
26000
26001
26002
26003        _.$slideTrack.append(_.$slides);
26004
26005
26006
26007        _.$slides.each(function(index, element) {
26008
26009            $(element).attr('data-slick-index', index);
26010
26011        });
26012
26013
26014
26015        _.$slidesCache = _.$slides;
26016
26017
26018
26019        _.reinit();
26020
26021
26022
26023    };
26024
26025
26026
26027    Slick.prototype.animateHeight = function() {
26028
26029        var _ = this;
26030
26031        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
26032
26033            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
26034
26035            _.$list.animate({
26036
26037                height: targetHeight
26038
26039            }, _.options.speed);
26040
26041        }
26042
26043    };
26044
26045
26046
26047    Slick.prototype.animateSlide = function(targetLeft, callback) {
26048
26049
26050
26051        var animProps = {},
26052
26053            _ = this;
26054
26055
26056
26057        _.animateHeight();
26058
26059
26060
26061        if (_.options.rtl === true && _.options.vertical === false) {
26062
26063            targetLeft = -targetLeft;
26064
26065        }
26066
26067        if (_.transformsEnabled === false) {
26068
26069            if (_.options.vertical === false) {
26070
26071                _.$slideTrack.animate({
26072
26073                    left: targetLeft
26074
26075                }, _.options.speed, _.options.easing, callback);
26076
26077            } else {
26078
26079                _.$slideTrack.animate({
26080
26081                    top: targetLeft
26082
26083                }, _.options.speed, _.options.easing, callback);
26084
26085            }
26086
26087
26088
26089        } else {
26090
26091
26092
26093            if (_.cssTransitions === false) {
26094
26095                if (_.options.rtl === true) {
26096
26097                    _.currentLeft = -(_.currentLeft);
26098
26099                }
26100
26101                $({
26102
26103                    animStart: _.currentLeft
26104
26105                }).animate({
26106
26107                    animStart: targetLeft
26108
26109                }, {
26110
26111                    duration: _.options.speed,
26112
26113                    easing: _.options.easing,
26114
26115                    step: function(now) {
26116
26117                        now = Math.ceil(now);
26118
26119                        if (_.options.vertical === false) {
26120
26121                            animProps[_.animType] = 'translate(' +
26122
26123                                now + 'px, 0px)';
26124
26125                            _.$slideTrack.css(animProps);
26126
26127                        } else {
26128
26129                            animProps[_.animType] = 'translate(0px,' +
26130
26131                                now + 'px)';
26132
26133                            _.$slideTrack.css(animProps);
26134
26135                        }
26136
26137                    },
26138
26139                    complete: function() {
26140
26141                        if (callback) {
26142
26143                            callback.call();
26144
26145                        }
26146
26147                    }
26148
26149                });
26150
26151
26152
26153            } else {
26154
26155
26156
26157                _.applyTransition();
26158
26159                targetLeft = Math.ceil(targetLeft);
26160
26161
26162
26163                if (_.options.vertical === false) {
26164
26165                    animProps[_.animType] = 'translate3d(' + targetLeft + 'px, 0px, 0px)';
26166
26167                } else {
26168
26169                    animProps[_.animType] = 'translate3d(0px,' + targetLeft + 'px, 0px)';
26170
26171                }
26172
26173                _.$slideTrack.css(animProps);
26174
26175
26176
26177                if (callback) {
26178
26179                    setTimeout(function() {
26180
26181
26182
26183                        _.disableTransition();
26184
26185
26186
26187                        callback.call();
26188
26189                    }, _.options.speed);
26190
26191                }
26192
26193
26194
26195            }
26196
26197
26198
26199        }
26200
26201
26202
26203    };
26204
26205
26206
26207    Slick.prototype.getNavTarget = function() {
26208
26209
26210
26211        var _ = this,
26212
26213            asNavFor = _.options.asNavFor;
26214
26215
26216
26217        if ( asNavFor && asNavFor !== null ) {
26218
26219            asNavFor = $(asNavFor).not(_.$slider);
26220
26221        }
26222
26223
26224
26225        return asNavFor;
26226
26227
26228
26229    };
26230
26231
26232
26233    Slick.prototype.asNavFor = function(index) {
26234
26235
26236
26237        var _ = this,
26238
26239            asNavFor = _.getNavTarget();
26240
26241
26242
26243        if ( asNavFor !== null && typeof asNavFor === 'object' ) {
26244
26245            asNavFor.each(function() {
26246
26247                var target = $(this).slick('getSlick');
26248
26249                if(!target.unslicked) {
26250
26251                    target.slideHandler(index, true);
26252
26253                }
26254
26255            });
26256
26257        }
26258
26259
26260
26261    };
26262
26263
26264
26265    Slick.prototype.applyTransition = function(slide) {
26266
26267
26268
26269        var _ = this,
26270
26271            transition = {};
26272
26273
26274
26275        if (_.options.fade === false) {
26276
26277            transition[_.transitionType] = _.transformType + ' ' + _.options.speed + 'ms ' + _.options.cssEase;
26278
26279        } else {
26280
26281            transition[_.transitionType] = 'opacity ' + _.options.speed + 'ms ' + _.options.cssEase;
26282
26283        }
26284
26285
26286
26287        if (_.options.fade === false) {
26288
26289            _.$slideTrack.css(transition);
26290
26291        } else {
26292
26293            _.$slides.eq(slide).css(transition);
26294
26295        }
26296
26297
26298
26299    };
26300
26301
26302
26303    Slick.prototype.autoPlay = function() {
26304
26305
26306
26307        var _ = this;
26308
26309
26310
26311        _.autoPlayClear();
26312
26313
26314
26315        if ( _.slideCount > _.options.slidesToShow ) {
26316
26317            _.autoPlayTimer = setInterval( _.autoPlayIterator, _.options.autoplaySpeed );
26318
26319        }
26320
26321
26322
26323    };
26324
26325
26326
26327    Slick.prototype.autoPlayClear = function() {
26328
26329
26330
26331        var _ = this;
26332
26333
26334
26335        if (_.autoPlayTimer) {
26336
26337            clearInterval(_.autoPlayTimer);
26338
26339        }
26340
26341
26342
26343    };
26344
26345
26346
26347    Slick.prototype.autoPlayIterator = function() {
26348
26349
26350
26351        var _ = this,
26352
26353            slideTo = _.currentSlide + _.options.slidesToScroll;
26354
26355
26356
26357        if ( !_.paused && !_.interrupted && !_.focussed ) {
26358
26359
26360
26361            if ( _.options.infinite === false ) {
26362
26363
26364
26365                if ( _.direction === 1 && ( _.currentSlide + 1 ) === ( _.slideCount - 1 )) {
26366
26367                    _.direction = 0;
26368
26369                }
26370
26371
26372
26373                else if ( _.direction === 0 ) {
26374
26375
26376
26377                    slideTo = _.currentSlide - _.options.slidesToScroll;
26378
26379
26380
26381                    if ( _.currentSlide - 1 === 0 ) {
26382
26383                        _.direction = 1;
26384
26385                    }
26386
26387
26388
26389                }
26390
26391
26392
26393            }
26394
26395
26396
26397            _.slideHandler( slideTo );
26398
26399
26400
26401        }
26402
26403
26404
26405    };
26406
26407
26408
26409    Slick.prototype.buildArrows = function() {
26410
26411
26412
26413        var _ = this;
26414
26415
26416
26417        if (_.options.arrows === true ) {
26418
26419
26420
26421            _.$prevArrow = $(_.options.prevArrow).addClass('slick-arrow');
26422
26423            _.$nextArrow = $(_.options.nextArrow).addClass('slick-arrow');
26424
26425
26426
26427            if( _.slideCount > _.options.slidesToShow ) {
26428
26429
26430
26431                _.$prevArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
26432
26433                _.$nextArrow.removeClass('slick-hidden').removeAttr('aria-hidden tabindex');
26434
26435
26436
26437                if (_.htmlExpr.test(_.options.prevArrow)) {
26438
26439                    _.$prevArrow.prependTo(_.options.appendArrows);
26440
26441                }
26442
26443
26444
26445                if (_.htmlExpr.test(_.options.nextArrow)) {
26446
26447                    _.$nextArrow.appendTo(_.options.appendArrows);
26448
26449                }
26450
26451
26452
26453                if (_.options.infinite !== true) {
26454
26455                    _.$prevArrow
26456
26457                        .addClass('slick-disabled')
26458
26459                        .attr('aria-disabled', 'true');
26460
26461                }
26462
26463
26464
26465            } else {
26466
26467
26468
26469                _.$prevArrow.add( _.$nextArrow )
26470
26471
26472
26473                    .addClass('slick-hidden')
26474
26475                    .attr({
26476
26477                        'aria-disabled': 'true',
26478
26479                        'tabindex': '-1'
26480
26481                    });
26482
26483
26484
26485            }
26486
26487
26488
26489        }
26490
26491
26492
26493    };
26494
26495
26496
26497    Slick.prototype.buildDots = function() {
26498
26499
26500
26501        var _ = this,
26502
26503            i, dot;
26504
26505
26506
26507        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
26508
26509
26510
26511            _.$slider.addClass('slick-dotted');
26512
26513
26514
26515            dot = $('<ul />').addClass(_.options.dotsClass);
26516
26517
26518
26519            for (i = 0; i <= _.getDotCount(); i += 1) {
26520
26521                dot.append($('<li />').append(_.options.customPaging.call(this, _, i)));
26522
26523            }
26524
26525
26526
26527            _.$dots = dot.appendTo(_.options.appendDots);
26528
26529
26530
26531            _.$dots.find('li').first().addClass('slick-active');
26532
26533
26534
26535        }
26536
26537
26538
26539    };
26540
26541
26542
26543    Slick.prototype.buildOut = function() {
26544
26545
26546
26547        var _ = this;
26548
26549
26550
26551        _.$slides =
26552
26553            _.$slider
26554
26555                .children( _.options.slide + ':not(.slick-cloned)')
26556
26557                .addClass('slick-slide');
26558
26559
26560
26561        _.slideCount = _.$slides.length;
26562
26563
26564
26565        _.$slides.each(function(index, element) {
26566
26567            $(element)
26568
26569                .attr('data-slick-index', index)
26570
26571                .data('originalStyling', $(element).attr('style') || '');
26572
26573        });
26574
26575
26576
26577        _.$slider.addClass('slick-slider');
26578
26579
26580
26581        _.$slideTrack = (_.slideCount === 0) ?
26582
26583            $('<div class="slick-track"/>').appendTo(_.$slider) :
26584
26585            _.$slides.wrapAll('<div class="slick-track"/>').parent();
26586
26587
26588
26589        _.$list = _.$slideTrack.wrap(
26590
26591            '<div class="slick-list"/>').parent();
26592
26593        _.$slideTrack.css('opacity', 0);
26594
26595
26596
26597        if (_.options.centerMode === true || _.options.swipeToSlide === true) {
26598
26599            _.options.slidesToScroll = 1;
26600
26601        }
26602
26603
26604
26605        $('img[data-lazy]', _.$slider).not('[src]').addClass('slick-loading');
26606
26607
26608
26609        _.setupInfinite();
26610
26611
26612
26613        _.buildArrows();
26614
26615
26616
26617        _.buildDots();
26618
26619
26620
26621        _.updateDots();
26622
26623
26624
26625
26626
26627        _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);
26628
26629
26630
26631        if (_.options.draggable === true) {
26632
26633            _.$list.addClass('draggable');
26634
26635        }
26636
26637
26638
26639    };
26640
26641
26642
26643    Slick.prototype.buildRows = function() {
26644
26645
26646
26647        var _ = this, a, b, c, newSlides, numOfSlides, originalSlides,slidesPerSection;
26648
26649
26650
26651        newSlides = document.createDocumentFragment();
26652
26653        originalSlides = _.$slider.children();
26654
26655
26656
26657        if(_.options.rows > 0) {
26658
26659
26660
26661            slidesPerSection = _.options.slidesPerRow * _.options.rows;
26662
26663            numOfSlides = Math.ceil(
26664
26665                originalSlides.length / slidesPerSection
26666
26667            );
26668
26669
26670
26671            for(a = 0; a < numOfSlides; a++){
26672
26673                var slide = document.createElement('div');
26674
26675                for(b = 0; b < _.options.rows; b++) {
26676
26677                    var row = document.createElement('div');
26678
26679                    for(c = 0; c < _.options.slidesPerRow; c++) {
26680
26681                        var target = (a * slidesPerSection + ((b * _.options.slidesPerRow) + c));
26682
26683                        if (originalSlides.get(target)) {
26684
26685                            row.appendChild(originalSlides.get(target));
26686
26687                        }
26688
26689                    }
26690
26691                    slide.appendChild(row);
26692
26693                }
26694
26695                newSlides.appendChild(slide);
26696
26697            }
26698
26699
26700
26701            _.$slider.empty().append(newSlides);
26702
26703            _.$slider.children().children().children()
26704
26705                .css({
26706
26707                    'width':(100 / _.options.slidesPerRow) + '%',
26708
26709                    'display': 'inline-block'
26710
26711                });
26712
26713
26714
26715        }
26716
26717
26718
26719    };
26720
26721
26722
26723    Slick.prototype.checkResponsive = function(initial, forceUpdate) {
26724
26725
26726
26727        var _ = this,
26728
26729            breakpoint, targetBreakpoint, respondToWidth, triggerBreakpoint = false;
26730
26731        var sliderWidth = _.$slider.width();
26732
26733        var windowWidth = window.innerWidth || $(window).width();
26734
26735
26736
26737        if (_.respondTo === 'window') {
26738
26739            respondToWidth = windowWidth;
26740
26741        } else if (_.respondTo === 'slider') {
26742
26743            respondToWidth = sliderWidth;
26744
26745        } else if (_.respondTo === 'min') {
26746
26747            respondToWidth = Math.min(windowWidth, sliderWidth);
26748
26749        }
26750
26751
26752
26753        if ( _.options.responsive &&
26754
26755            _.options.responsive.length &&
26756
26757            _.options.responsive !== null) {
26758
26759
26760
26761            targetBreakpoint = null;
26762
26763
26764
26765            for (breakpoint in _.breakpoints) {
26766
26767                if (_.breakpoints.hasOwnProperty(breakpoint)) {
26768
26769                    if (_.originalSettings.mobileFirst === false) {
26770
26771                        if (respondToWidth < _.breakpoints[breakpoint]) {
26772
26773                            targetBreakpoint = _.breakpoints[breakpoint];
26774
26775                        }
26776
26777                    } else {
26778
26779                        if (respondToWidth > _.breakpoints[breakpoint]) {
26780
26781                            targetBreakpoint = _.breakpoints[breakpoint];
26782
26783                        }
26784
26785                    }
26786
26787                }
26788
26789            }
26790
26791
26792
26793            if (targetBreakpoint !== null) {
26794
26795                if (_.activeBreakpoint !== null) {
26796
26797                    if (targetBreakpoint !== _.activeBreakpoint || forceUpdate) {
26798
26799                        _.activeBreakpoint =
26800
26801                            targetBreakpoint;
26802
26803                        if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
26804
26805                            _.unslick(targetBreakpoint);
26806
26807                        } else {
26808
26809                            _.options = $.extend({}, _.originalSettings,
26810
26811                                _.breakpointSettings[
26812
26813                                    targetBreakpoint]);
26814
26815                            if (initial === true) {
26816
26817                                _.currentSlide = _.options.initialSlide;
26818
26819                            }
26820
26821                            _.refresh(initial);
26822
26823                        }
26824
26825                        triggerBreakpoint = targetBreakpoint;
26826
26827                    }
26828
26829                } else {
26830
26831                    _.activeBreakpoint = targetBreakpoint;
26832
26833                    if (_.breakpointSettings[targetBreakpoint] === 'unslick') {
26834
26835                        _.unslick(targetBreakpoint);
26836
26837                    } else {
26838
26839                        _.options = $.extend({}, _.originalSettings,
26840
26841                            _.breakpointSettings[
26842
26843                                targetBreakpoint]);
26844
26845                        if (initial === true) {
26846
26847                            _.currentSlide = _.options.initialSlide;
26848
26849                        }
26850
26851                        _.refresh(initial);
26852
26853                    }
26854
26855                    triggerBreakpoint = targetBreakpoint;
26856
26857                }
26858
26859            } else {
26860
26861                if (_.activeBreakpoint !== null) {
26862
26863                    _.activeBreakpoint = null;
26864
26865                    _.options = _.originalSettings;
26866
26867                    if (initial === true) {
26868
26869                        _.currentSlide = _.options.initialSlide;
26870
26871                    }
26872
26873                    _.refresh(initial);
26874
26875                    triggerBreakpoint = targetBreakpoint;
26876
26877                }
26878
26879            }
26880
26881
26882
26883            // only trigger breakpoints during an actual break. not on initialize.
26884
26885            if( !initial && triggerBreakpoint !== false ) {
26886
26887                _.$slider.trigger('breakpoint', [_, triggerBreakpoint]);
26888
26889            }
26890
26891        }
26892
26893
26894
26895    };
26896
26897
26898
26899    Slick.prototype.changeSlide = function(event, dontAnimate) {
26900
26901
26902
26903        var _ = this,
26904
26905            $target = $(event.currentTarget),
26906
26907            indexOffset, slideOffset, unevenOffset;
26908
26909
26910
26911        // If target is a link, prevent default action.
26912
26913        if($target.is('a')) {
26914
26915            event.preventDefault();
26916
26917        }
26918
26919
26920
26921        // If target is not the <li> element (ie: a child), find the <li>.
26922
26923        if(!$target.is('li')) {
26924
26925            $target = $target.closest('li');
26926
26927        }
26928
26929
26930
26931        unevenOffset = (_.slideCount % _.options.slidesToScroll !== 0);
26932
26933        indexOffset = unevenOffset ? 0 : (_.slideCount - _.currentSlide) % _.options.slidesToScroll;
26934
26935
26936
26937        switch (event.data.message) {
26938
26939
26940
26941            case 'previous':
26942
26943                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : _.options.slidesToShow - indexOffset;
26944
26945                if (_.slideCount > _.options.slidesToShow) {
26946
26947                    _.slideHandler(_.currentSlide - slideOffset, false, dontAnimate);
26948
26949                }
26950
26951                break;
26952
26953
26954
26955            case 'next':
26956
26957                slideOffset = indexOffset === 0 ? _.options.slidesToScroll : indexOffset;
26958
26959                if (_.slideCount > _.options.slidesToShow) {
26960
26961                    _.slideHandler(_.currentSlide + slideOffset, false, dontAnimate);
26962
26963                }
26964
26965                break;
26966
26967
26968
26969            case 'index':
26970
26971                var index = event.data.index === 0 ? 0 :
26972
26973                    event.data.index || $target.index() * _.options.slidesToScroll;
26974
26975
26976
26977                _.slideHandler(_.checkNavigable(index), false, dontAnimate);
26978
26979                $target.children().trigger('focus');
26980
26981                break;
26982
26983
26984
26985            default:
26986
26987                return;
26988
26989        }
26990
26991
26992
26993    };
26994
26995
26996
26997    Slick.prototype.checkNavigable = function(index) {
26998
26999
27000
27001        var _ = this,
27002
27003            navigables, prevNavigable;
27004
27005
27006
27007        navigables = _.getNavigableIndexes();
27008
27009        prevNavigable = 0;
27010
27011        if (index > navigables[navigables.length - 1]) {
27012
27013            index = navigables[navigables.length - 1];
27014
27015        } else {
27016
27017            for (var n in navigables) {
27018
27019                if (index < navigables[n]) {
27020
27021                    index = prevNavigable;
27022
27023                    break;
27024
27025                }
27026
27027                prevNavigable = navigables[n];
27028
27029            }
27030
27031        }
27032
27033
27034
27035        return index;
27036
27037    };
27038
27039
27040
27041    Slick.prototype.cleanUpEvents = function() {
27042
27043
27044
27045        var _ = this;
27046
27047
27048
27049        if (_.options.dots && _.$dots !== null) {
27050
27051
27052
27053            $('li', _.$dots)
27054
27055                .off('click.slick', _.changeSlide)
27056
27057                .off('mouseenter.slick', $.proxy(_.interrupt, _, true))
27058
27059                .off('mouseleave.slick', $.proxy(_.interrupt, _, false));
27060
27061
27062
27063            if (_.options.accessibility === true) {
27064
27065                _.$dots.off('keydown.slick', _.keyHandler);
27066
27067            }
27068
27069        }
27070
27071
27072
27073        _.$slider.off('focus.slick blur.slick');
27074
27075
27076
27077        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
27078
27079            _.$prevArrow && _.$prevArrow.off('click.slick', _.changeSlide);
27080
27081            _.$nextArrow && _.$nextArrow.off('click.slick', _.changeSlide);
27082
27083
27084
27085            if (_.options.accessibility === true) {
27086
27087                _.$prevArrow && _.$prevArrow.off('keydown.slick', _.keyHandler);
27088
27089                _.$nextArrow && _.$nextArrow.off('keydown.slick', _.keyHandler);
27090
27091            }
27092
27093        }
27094
27095
27096
27097        _.$list.off('touchstart.slick mousedown.slick', _.swipeHandler);
27098
27099        _.$list.off('touchmove.slick mousemove.slick', _.swipeHandler);
27100
27101        _.$list.off('touchend.slick mouseup.slick', _.swipeHandler);
27102
27103        _.$list.off('touchcancel.slick mouseleave.slick', _.swipeHandler);
27104
27105
27106
27107        _.$list.off('click.slick', _.clickHandler);
27108
27109
27110
27111        $(document).off(_.visibilityChange, _.visibility);
27112
27113
27114
27115        _.cleanUpSlideEvents();
27116
27117
27118
27119        if (_.options.accessibility === true) {
27120
27121            _.$list.off('keydown.slick', _.keyHandler);
27122
27123        }
27124
27125
27126
27127        if (_.options.focusOnSelect === true) {
27128
27129            $(_.$slideTrack).children().off('click.slick', _.selectHandler);
27130
27131        }
27132
27133
27134
27135        $(window).off('orientationchange.slick.slick-' + _.instanceUid, _.orientationChange);
27136
27137
27138
27139        $(window).off('resize.slick.slick-' + _.instanceUid, _.resize);
27140
27141
27142
27143        $('[draggable!=true]', _.$slideTrack).off('dragstart', _.preventDefault);
27144
27145
27146
27147        $(window).off('load.slick.slick-' + _.instanceUid, _.setPosition);
27148
27149
27150
27151    };
27152
27153
27154
27155    Slick.prototype.cleanUpSlideEvents = function() {
27156
27157
27158
27159        var _ = this;
27160
27161
27162
27163        _.$list.off('mouseenter.slick', $.proxy(_.interrupt, _, true));
27164
27165        _.$list.off('mouseleave.slick', $.proxy(_.interrupt, _, false));
27166
27167
27168
27169    };
27170
27171
27172
27173    Slick.prototype.cleanUpRows = function() {
27174
27175
27176
27177        var _ = this, originalSlides;
27178
27179
27180
27181        if(_.options.rows > 0) {
27182
27183            originalSlides = _.$slides.children().children();
27184
27185            originalSlides.removeAttr('style');
27186
27187            _.$slider.empty().append(originalSlides);
27188
27189        }
27190
27191
27192
27193    };
27194
27195
27196
27197    Slick.prototype.clickHandler = function(event) {
27198
27199
27200
27201        var _ = this;
27202
27203
27204
27205        if (_.shouldClick === false) {
27206
27207            event.stopImmediatePropagation();
27208
27209            event.stopPropagation();
27210
27211            event.preventDefault();
27212
27213        }
27214
27215
27216
27217    };
27218
27219
27220
27221    Slick.prototype.destroy = function(refresh) {
27222
27223
27224
27225        var _ = this;
27226
27227
27228
27229        _.autoPlayClear();
27230
27231
27232
27233        _.touchObject = {};
27234
27235
27236
27237        _.cleanUpEvents();
27238
27239
27240
27241        $('.slick-cloned', _.$slider).detach();
27242
27243
27244
27245        if (_.$dots) {
27246
27247            _.$dots.remove();
27248
27249        }
27250
27251
27252
27253        if ( _.$prevArrow && _.$prevArrow.length ) {
27254
27255
27256
27257            _.$prevArrow
27258
27259                .removeClass('slick-disabled slick-arrow slick-hidden')
27260
27261                .removeAttr('aria-hidden aria-disabled tabindex')
27262
27263                .css('display','');
27264
27265
27266
27267            if ( _.htmlExpr.test( _.options.prevArrow )) {
27268
27269                _.$prevArrow.remove();
27270
27271            }
27272
27273        }
27274
27275
27276
27277        if ( _.$nextArrow && _.$nextArrow.length ) {
27278
27279
27280
27281            _.$nextArrow
27282
27283                .removeClass('slick-disabled slick-arrow slick-hidden')
27284
27285                .removeAttr('aria-hidden aria-disabled tabindex')
27286
27287                .css('display','');
27288
27289
27290
27291            if ( _.htmlExpr.test( _.options.nextArrow )) {
27292
27293                _.$nextArrow.remove();
27294
27295            }
27296
27297        }
27298
27299
27300
27301
27302
27303        if (_.$slides) {
27304
27305
27306
27307            _.$slides
27308
27309                .removeClass('slick-slide slick-active slick-center slick-visible slick-current')
27310
27311                .removeAttr('aria-hidden')
27312
27313                .removeAttr('data-slick-index')
27314
27315                .each(function(){
27316
27317                    $(this).attr('style', $(this).data('originalStyling'));
27318
27319                });
27320
27321
27322
27323            _.$slideTrack.children(this.options.slide).detach();
27324
27325
27326
27327            _.$slideTrack.detach();
27328
27329
27330
27331            _.$list.detach();
27332
27333
27334
27335            _.$slider.append(_.$slides);
27336
27337        }
27338
27339
27340
27341        _.cleanUpRows();
27342
27343
27344
27345        _.$slider.removeClass('slick-slider');
27346
27347        _.$slider.removeClass('slick-initialized');
27348
27349        _.$slider.removeClass('slick-dotted');
27350
27351
27352
27353        _.unslicked = true;
27354
27355
27356
27357        if(!refresh) {
27358
27359            _.$slider.trigger('destroy', [_]);
27360
27361        }
27362
27363
27364
27365    };
27366
27367
27368
27369    Slick.prototype.disableTransition = function(slide) {
27370
27371
27372
27373        var _ = this,
27374
27375            transition = {};
27376
27377
27378
27379        transition[_.transitionType] = '';
27380
27381
27382
27383        if (_.options.fade === false) {
27384
27385            _.$slideTrack.css(transition);
27386
27387        } else {
27388
27389            _.$slides.eq(slide).css(transition);
27390
27391        }
27392
27393
27394
27395    };
27396
27397
27398
27399    Slick.prototype.fadeSlide = function(slideIndex, callback) {
27400
27401
27402
27403        var _ = this;
27404
27405
27406
27407        if (_.cssTransitions === false) {
27408
27409
27410
27411            _.$slides.eq(slideIndex).css({
27412
27413                zIndex: _.options.zIndex
27414
27415            });
27416
27417
27418
27419            _.$slides.eq(slideIndex).animate({
27420
27421                opacity: 1
27422
27423            }, _.options.speed, _.options.easing, callback);
27424
27425
27426
27427        } else {
27428
27429
27430
27431            _.applyTransition(slideIndex);
27432
27433
27434
27435            _.$slides.eq(slideIndex).css({
27436
27437                opacity: 1,
27438
27439                zIndex: _.options.zIndex
27440
27441            });
27442
27443
27444
27445            if (callback) {
27446
27447                setTimeout(function() {
27448
27449
27450
27451                    _.disableTransition(slideIndex);
27452
27453
27454
27455                    callback.call();
27456
27457                }, _.options.speed);
27458
27459            }
27460
27461
27462
27463        }
27464
27465
27466
27467    };
27468
27469
27470
27471    Slick.prototype.fadeSlideOut = function(slideIndex) {
27472
27473
27474
27475        var _ = this;
27476
27477
27478
27479        if (_.cssTransitions === false) {
27480
27481
27482
27483            _.$slides.eq(slideIndex).animate({
27484
27485                opacity: 0,
27486
27487                zIndex: _.options.zIndex - 2
27488
27489            }, _.options.speed, _.options.easing);
27490
27491
27492
27493        } else {
27494
27495
27496
27497            _.applyTransition(slideIndex);
27498
27499
27500
27501            _.$slides.eq(slideIndex).css({
27502
27503                opacity: 0,
27504
27505                zIndex: _.options.zIndex - 2
27506
27507            });
27508
27509
27510
27511        }
27512
27513
27514
27515    };
27516
27517
27518
27519    Slick.prototype.filterSlides = Slick.prototype.slickFilter = function(filter) {
27520
27521
27522
27523        var _ = this;
27524
27525
27526
27527        if (filter !== null) {
27528
27529
27530
27531            _.$slidesCache = _.$slides;
27532
27533
27534
27535            _.unload();
27536
27537
27538
27539            _.$slideTrack.children(this.options.slide).detach();
27540
27541
27542
27543            _.$slidesCache.filter(filter).appendTo(_.$slideTrack);
27544
27545
27546
27547            _.reinit();
27548
27549
27550
27551        }
27552
27553
27554
27555    };
27556
27557
27558
27559    Slick.prototype.focusHandler = function() {
27560
27561
27562
27563        var _ = this;
27564
27565
27566
27567        _.$slider
27568
27569            .off('focus.slick blur.slick')
27570
27571            .on('focus.slick blur.slick', '*', function(event) {
27572
27573
27574
27575            event.stopImmediatePropagation();
27576
27577            var $sf = $(this);
27578
27579
27580
27581            setTimeout(function() {
27582
27583
27584
27585                if( _.options.pauseOnFocus ) {
27586
27587                    _.focussed = $sf.is(':focus');
27588
27589                    _.autoPlay();
27590
27591                }
27592
27593
27594
27595            }, 0);
27596
27597
27598
27599        });
27600
27601    };
27602
27603
27604
27605    Slick.prototype.getCurrent = Slick.prototype.slickCurrentSlide = function() {
27606
27607
27608
27609        var _ = this;
27610
27611        return _.currentSlide;
27612
27613
27614
27615    };
27616
27617
27618
27619    Slick.prototype.getDotCount = function() {
27620
27621
27622
27623        var _ = this;
27624
27625
27626
27627        var breakPoint = 0;
27628
27629        var counter = 0;
27630
27631        var pagerQty = 0;
27632
27633
27634
27635        if (_.options.infinite === true) {
27636
27637            if (_.slideCount <= _.options.slidesToShow) {
27638
27639                 ++pagerQty;
27640
27641            } else {
27642
27643                while (breakPoint < _.slideCount) {
27644
27645                    ++pagerQty;
27646
27647                    breakPoint = counter + _.options.slidesToScroll;
27648
27649                    counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
27650
27651                }
27652
27653            }
27654
27655        } else if (_.options.centerMode === true) {
27656
27657            pagerQty = _.slideCount;
27658
27659        } else if(!_.options.asNavFor) {
27660
27661            pagerQty = 1 + Math.ceil((_.slideCount - _.options.slidesToShow) / _.options.slidesToScroll);
27662
27663        }else {
27664
27665            while (breakPoint < _.slideCount) {
27666
27667                ++pagerQty;
27668
27669                breakPoint = counter + _.options.slidesToScroll;
27670
27671                counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
27672
27673            }
27674
27675        }
27676
27677
27678
27679        return pagerQty - 1;
27680
27681
27682
27683    };
27684
27685
27686
27687    Slick.prototype.getLeft = function(slideIndex) {
27688
27689
27690
27691        var _ = this,
27692
27693            targetLeft,
27694
27695            verticalHeight,
27696
27697            verticalOffset = 0,
27698
27699            targetSlide,
27700
27701            coef;
27702
27703
27704
27705        _.slideOffset = 0;
27706
27707        verticalHeight = _.$slides.first().outerHeight(true);
27708
27709
27710
27711        if (_.options.infinite === true) {
27712
27713            if (_.slideCount > _.options.slidesToShow) {
27714
27715                _.slideOffset = (_.slideWidth * _.options.slidesToShow) * -1;
27716
27717                coef = -1
27718
27719
27720
27721                if (_.options.vertical === true && _.options.centerMode === true) {
27722
27723                    if (_.options.slidesToShow === 2) {
27724
27725                        coef = -1.5;
27726
27727                    } else if (_.options.slidesToShow === 1) {
27728
27729                        coef = -2
27730
27731                    }
27732
27733                }
27734
27735                verticalOffset = (verticalHeight * _.options.slidesToShow) * coef;
27736
27737            }
27738
27739            if (_.slideCount % _.options.slidesToScroll !== 0) {
27740
27741                if (slideIndex + _.options.slidesToScroll > _.slideCount && _.slideCount > _.options.slidesToShow) {
27742
27743                    if (slideIndex > _.slideCount) {
27744
27745                        _.slideOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * _.slideWidth) * -1;
27746
27747                        verticalOffset = ((_.options.slidesToShow - (slideIndex - _.slideCount)) * verticalHeight) * -1;
27748
27749                    } else {
27750
27751                        _.slideOffset = ((_.slideCount % _.options.slidesToScroll) * _.slideWidth) * -1;
27752
27753                        verticalOffset = ((_.slideCount % _.options.slidesToScroll) * verticalHeight) * -1;
27754
27755                    }
27756
27757                }
27758
27759            }
27760
27761        } else {
27762
27763            if (slideIndex + _.options.slidesToShow > _.slideCount) {
27764
27765                _.slideOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * _.slideWidth;
27766
27767                verticalOffset = ((slideIndex + _.options.slidesToShow) - _.slideCount) * verticalHeight;
27768
27769            }
27770
27771        }
27772
27773
27774
27775        if (_.slideCount <= _.options.slidesToShow) {
27776
27777            _.slideOffset = 0;
27778
27779            verticalOffset = 0;
27780
27781        }
27782
27783
27784
27785        if (_.options.centerMode === true && _.slideCount <= _.options.slidesToShow) {
27786
27787            _.slideOffset = ((_.slideWidth * Math.floor(_.options.slidesToShow)) / 2) - ((_.slideWidth * _.slideCount) / 2);
27788
27789        } else if (_.options.centerMode === true && _.options.infinite === true) {
27790
27791            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2) - _.slideWidth;
27792
27793        } else if (_.options.centerMode === true) {
27794
27795            _.slideOffset = 0;
27796
27797            _.slideOffset += _.slideWidth * Math.floor(_.options.slidesToShow / 2);
27798
27799        }
27800
27801
27802
27803        if (_.options.vertical === false) {
27804
27805            targetLeft = ((slideIndex * _.slideWidth) * -1) + _.slideOffset;
27806
27807        } else {
27808
27809            targetLeft = ((slideIndex * verticalHeight) * -1) + verticalOffset;
27810
27811        }
27812
27813
27814
27815        if (_.options.variableWidth === true) {
27816
27817
27818
27819            if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
27820
27821                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
27822
27823            } else {
27824
27825                targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow);
27826
27827            }
27828
27829
27830
27831            if (_.options.rtl === true) {
27832
27833                if (targetSlide[0]) {
27834
27835                    targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
27836
27837                } else {
27838
27839                    targetLeft =  0;
27840
27841                }
27842
27843            } else {
27844
27845                targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
27846
27847            }
27848
27849
27850
27851            if (_.options.centerMode === true) {
27852
27853                if (_.slideCount <= _.options.slidesToShow || _.options.infinite === false) {
27854
27855                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex);
27856
27857                } else {
27858
27859                    targetSlide = _.$slideTrack.children('.slick-slide').eq(slideIndex + _.options.slidesToShow + 1);
27860
27861                }
27862
27863
27864
27865                if (_.options.rtl === true) {
27866
27867                    if (targetSlide[0]) {
27868
27869                        targetLeft = (_.$slideTrack.width() - targetSlide[0].offsetLeft - targetSlide.width()) * -1;
27870
27871                    } else {
27872
27873                        targetLeft =  0;
27874
27875                    }
27876
27877                } else {
27878
27879                    targetLeft = targetSlide[0] ? targetSlide[0].offsetLeft * -1 : 0;
27880
27881                }
27882
27883
27884
27885                targetLeft += (_.$list.width() - targetSlide.outerWidth()) / 2;
27886
27887            }
27888
27889        }
27890
27891
27892
27893        return targetLeft;
27894
27895
27896
27897    };
27898
27899
27900
27901    Slick.prototype.getOption = Slick.prototype.slickGetOption = function(option) {
27902
27903
27904
27905        var _ = this;
27906
27907
27908
27909        return _.options[option];
27910
27911
27912
27913    };
27914
27915
27916
27917    Slick.prototype.getNavigableIndexes = function() {
27918
27919
27920
27921        var _ = this,
27922
27923            breakPoint = 0,
27924
27925            counter = 0,
27926
27927            indexes = [],
27928
27929            max;
27930
27931
27932
27933        if (_.options.infinite === false) {
27934
27935            max = _.slideCount;
27936
27937        } else {
27938
27939            breakPoint = _.options.slidesToScroll * -1;
27940
27941            counter = _.options.slidesToScroll * -1;
27942
27943            max = _.slideCount * 2;
27944
27945        }
27946
27947
27948
27949        while (breakPoint < max) {
27950
27951            indexes.push(breakPoint);
27952
27953            breakPoint = counter + _.options.slidesToScroll;
27954
27955            counter += _.options.slidesToScroll <= _.options.slidesToShow ? _.options.slidesToScroll : _.options.slidesToShow;
27956
27957        }
27958
27959
27960
27961        return indexes;
27962
27963
27964
27965    };
27966
27967
27968
27969    Slick.prototype.getSlick = function() {
27970
27971
27972
27973        return this;
27974
27975
27976
27977    };
27978
27979
27980
27981    Slick.prototype.getSlideCount = function() {
27982
27983
27984
27985        var _ = this,
27986
27987            slidesTraversed, swipedSlide, centerOffset;
27988
27989
27990
27991        centerOffset = _.options.centerMode === true ? _.slideWidth * Math.floor(_.options.slidesToShow / 2) : 0;
27992
27993
27994
27995        if (_.options.swipeToSlide === true) {
27996
27997            _.$slideTrack.find('.slick-slide').each(function(index, slide) {
27998
27999                if (slide.offsetLeft - centerOffset + ($(slide).outerWidth() / 2) > (_.swipeLeft * -1)) {
28000
28001                    swipedSlide = slide;
28002
28003                    return false;
28004
28005                }
28006
28007            });
28008
28009
28010
28011            slidesTraversed = Math.abs($(swipedSlide).attr('data-slick-index') - _.currentSlide) || 1;
28012
28013
28014
28015            return slidesTraversed;
28016
28017
28018
28019        } else {
28020
28021            return _.options.slidesToScroll;
28022
28023        }
28024
28025
28026
28027    };
28028
28029
28030
28031    Slick.prototype.goTo = Slick.prototype.slickGoTo = function(slide, dontAnimate) {
28032
28033
28034
28035        var _ = this;
28036
28037
28038
28039        _.changeSlide({
28040
28041            data: {
28042
28043                message: 'index',
28044
28045                index: parseInt(slide)
28046
28047            }
28048
28049        }, dontAnimate);
28050
28051
28052
28053    };
28054
28055
28056
28057    Slick.prototype.init = function(creation) {
28058
28059
28060
28061        var _ = this;
28062
28063
28064
28065        if (!$(_.$slider).hasClass('slick-initialized')) {
28066
28067
28068
28069            $(_.$slider).addClass('slick-initialized');
28070
28071
28072
28073            _.buildRows();
28074
28075            _.buildOut();
28076
28077            _.setProps();
28078
28079            _.startLoad();
28080
28081            _.loadSlider();
28082
28083            _.initializeEvents();
28084
28085            _.updateArrows();
28086
28087            _.updateDots();
28088
28089            _.checkResponsive(true);
28090
28091            _.focusHandler();
28092
28093
28094
28095        }
28096
28097
28098
28099        if (creation) {
28100
28101            _.$slider.trigger('init', [_]);
28102
28103        }
28104
28105
28106
28107        if (_.options.accessibility === true) {
28108
28109            _.initADA();
28110
28111        }
28112
28113
28114
28115        if ( _.options.autoplay ) {
28116
28117
28118
28119            _.paused = false;
28120
28121            _.autoPlay();
28122
28123
28124
28125        }
28126
28127
28128
28129    };
28130
28131
28132
28133    Slick.prototype.initADA = function() {
28134
28135        var _ = this,
28136
28137                numDotGroups = Math.ceil(_.slideCount / _.options.slidesToShow),
28138
28139                tabControlIndexes = _.getNavigableIndexes().filter(function(val) {
28140
28141                    return (val >= 0) && (val < _.slideCount);
28142
28143                });
28144
28145
28146
28147        _.$slides.add(_.$slideTrack.find('.slick-cloned')).attr({
28148
28149            'aria-hidden': 'true',
28150
28151            'tabindex': '-1'
28152
28153        }).find('a, input, button, select').attr({
28154
28155            'tabindex': '-1'
28156
28157        });
28158
28159
28160
28161        if (_.$dots !== null) {
28162
28163            _.$slides.not(_.$slideTrack.find('.slick-cloned')).each(function(i) {
28164
28165                var slideControlIndex = tabControlIndexes.indexOf(i);
28166
28167
28168
28169                $(this).attr({
28170
28171                    'role': 'tabpanel',
28172
28173                    'id': 'slick-slide' + _.instanceUid + i,
28174
28175                    'tabindex': -1
28176
28177                });
28178
28179
28180
28181                if (slideControlIndex !== -1) {
28182
28183                   var ariaButtonControl = 'slick-slide-control' + _.instanceUid + slideControlIndex
28184
28185                   if ($('#' + ariaButtonControl).length) {
28186
28187                     $(this).attr({
28188
28189                         'aria-describedby': ariaButtonControl
28190
28191                     });
28192
28193                   }
28194
28195                }
28196
28197            });
28198
28199
28200
28201            _.$dots.attr('role', 'tablist').find('li').each(function(i) {
28202
28203                var mappedSlideIndex = tabControlIndexes[i];
28204
28205
28206
28207                $(this).attr({
28208
28209                    'role': 'presentation'
28210
28211                });
28212
28213
28214
28215                $(this).find('button').first().attr({
28216
28217                    'role': 'tab',
28218
28219                    'id': 'slick-slide-control' + _.instanceUid + i,
28220
28221                    'aria-controls': 'slick-slide' + _.instanceUid + mappedSlideIndex,
28222
28223                    'aria-label': (i + 1) + ' of ' + numDotGroups,
28224
28225                    'aria-selected': null,
28226
28227                    'tabindex': '-1'
28228
28229                });
28230
28231
28232
28233            }).eq(_.currentSlide).find('button').attr({
28234
28235                'aria-selected': 'true',
28236
28237                'tabindex': '0'
28238
28239            }).end();
28240
28241        }
28242
28243
28244
28245        for (var i=_.currentSlide, max=i+_.options.slidesToShow; i < max; i++) {
28246
28247          if (_.options.focusOnChange) {
28248
28249            _.$slides.eq(i).attr({'tabindex': '0'});
28250
28251          } else {
28252
28253            _.$slides.eq(i).removeAttr('tabindex');
28254
28255          }
28256
28257        }
28258
28259
28260
28261        _.activateADA();
28262
28263
28264
28265    };
28266
28267
28268
28269    Slick.prototype.initArrowEvents = function() {
28270
28271
28272
28273        var _ = this;
28274
28275
28276
28277        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
28278
28279            _.$prevArrow
28280
28281               .off('click.slick')
28282
28283               .on('click.slick', {
28284
28285                    message: 'previous'
28286
28287               }, _.changeSlide);
28288
28289            _.$nextArrow
28290
28291               .off('click.slick')
28292
28293               .on('click.slick', {
28294
28295                    message: 'next'
28296
28297               }, _.changeSlide);
28298
28299
28300
28301            if (_.options.accessibility === true) {
28302
28303                _.$prevArrow.on('keydown.slick', _.keyHandler);
28304
28305                _.$nextArrow.on('keydown.slick', _.keyHandler);
28306
28307            }
28308
28309        }
28310
28311
28312
28313    };
28314
28315
28316
28317    Slick.prototype.initDotEvents = function() {
28318
28319
28320
28321        var _ = this;
28322
28323
28324
28325        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
28326
28327            $('li', _.$dots).on('click.slick', {
28328
28329                message: 'index'
28330
28331            }, _.changeSlide);
28332
28333
28334
28335            if (_.options.accessibility === true) {
28336
28337                _.$dots.on('keydown.slick', _.keyHandler);
28338
28339            }
28340
28341        }
28342
28343
28344
28345        if (_.options.dots === true && _.options.pauseOnDotsHover === true && _.slideCount > _.options.slidesToShow) {
28346
28347
28348
28349            $('li', _.$dots)
28350
28351                .on('mouseenter.slick', $.proxy(_.interrupt, _, true))
28352
28353                .on('mouseleave.slick', $.proxy(_.interrupt, _, false));
28354
28355
28356
28357        }
28358
28359
28360
28361    };
28362
28363
28364
28365    Slick.prototype.initSlideEvents = function() {
28366
28367
28368
28369        var _ = this;
28370
28371
28372
28373        if ( _.options.pauseOnHover ) {
28374
28375
28376
28377            _.$list.on('mouseenter.slick', $.proxy(_.interrupt, _, true));
28378
28379            _.$list.on('mouseleave.slick', $.proxy(_.interrupt, _, false));
28380
28381
28382
28383        }
28384
28385
28386
28387    };
28388
28389
28390
28391    Slick.prototype.initializeEvents = function() {
28392
28393
28394
28395        var _ = this;
28396
28397
28398
28399        _.initArrowEvents();
28400
28401
28402
28403        _.initDotEvents();
28404
28405        _.initSlideEvents();
28406
28407
28408
28409        _.$list.on('touchstart.slick mousedown.slick', {
28410
28411            action: 'start'
28412
28413        }, _.swipeHandler);
28414
28415        _.$list.on('touchmove.slick mousemove.slick', {
28416
28417            action: 'move'
28418
28419        }, _.swipeHandler);
28420
28421        _.$list.on('touchend.slick mouseup.slick', {
28422
28423            action: 'end'
28424
28425        }, _.swipeHandler);
28426
28427        _.$list.on('touchcancel.slick mouseleave.slick', {
28428
28429            action: 'end'
28430
28431        }, _.swipeHandler);
28432
28433
28434
28435        _.$list.on('click.slick', _.clickHandler);
28436
28437
28438
28439        $(document).on(_.visibilityChange, $.proxy(_.visibility, _));
28440
28441
28442
28443        if (_.options.accessibility === true) {
28444
28445            _.$list.on('keydown.slick', _.keyHandler);
28446
28447        }
28448
28449
28450
28451        if (_.options.focusOnSelect === true) {
28452
28453            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
28454
28455        }
28456
28457
28458
28459        $(window).on('orientationchange.slick.slick-' + _.instanceUid, $.proxy(_.orientationChange, _));
28460
28461
28462
28463        $(window).on('resize.slick.slick-' + _.instanceUid, $.proxy(_.resize, _));
28464
28465
28466
28467        $('[draggable!=true]', _.$slideTrack).on('dragstart', _.preventDefault);
28468
28469
28470
28471        $(window).on('load.slick.slick-' + _.instanceUid, _.setPosition);
28472
28473        $(_.setPosition);
28474
28475
28476
28477    };
28478
28479
28480
28481    Slick.prototype.initUI = function() {
28482
28483
28484
28485        var _ = this;
28486
28487
28488
28489        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
28490
28491
28492
28493            _.$prevArrow.show();
28494
28495            _.$nextArrow.show();
28496
28497
28498
28499        }
28500
28501
28502
28503        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
28504
28505
28506
28507            _.$dots.show();
28508
28509
28510
28511        }
28512
28513
28514
28515    };
28516
28517
28518
28519    Slick.prototype.keyHandler = function(event) {
28520
28521
28522
28523        var _ = this;
28524
28525         //Dont slide if the cursor is inside the form fields and arrow keys are pressed
28526
28527        if(!event.target.tagName.match('TEXTAREA|INPUT|SELECT')) {
28528
28529            if (event.keyCode === 37 && _.options.accessibility === true) {
28530
28531                _.changeSlide({
28532
28533                    data: {
28534
28535                        message: _.options.rtl === true ? 'next' :  'previous'
28536
28537                    }
28538
28539                });
28540
28541            } else if (event.keyCode === 39 && _.options.accessibility === true) {
28542
28543                _.changeSlide({
28544
28545                    data: {
28546
28547                        message: _.options.rtl === true ? 'previous' : 'next'
28548
28549                    }
28550
28551                });
28552
28553            }
28554
28555        }
28556
28557
28558
28559    };
28560
28561
28562
28563    Slick.prototype.lazyLoad = function() {
28564
28565
28566
28567        var _ = this,
28568
28569            loadRange, cloneRange, rangeStart, rangeEnd;
28570
28571
28572
28573        function loadImages(imagesScope) {
28574
28575
28576
28577            $('img[data-lazy]', imagesScope).each(function() {
28578
28579
28580
28581                var image = $(this),
28582
28583                    imageSource = $(this).attr('data-lazy'),
28584
28585                    imageSrcSet = $(this).attr('data-srcset'),
28586
28587                    imageSizes  = $(this).attr('data-sizes') || _.$slider.attr('data-sizes'),
28588
28589                    imageToLoad = document.createElement('img');
28590
28591
28592
28593                imageToLoad.onload = function() {
28594
28595
28596
28597                    image
28598
28599                        .animate({ opacity: 0 }, 100, function() {
28600
28601
28602
28603                            if (imageSrcSet) {
28604
28605                                image
28606
28607                                    .attr('srcset', imageSrcSet );
28608
28609
28610
28611                                if (imageSizes) {
28612
28613                                    image
28614
28615                                        .attr('sizes', imageSizes );
28616
28617                                }
28618
28619                            }
28620
28621
28622
28623                            image
28624
28625                                .attr('src', imageSource)
28626
28627                                .animate({ opacity: 1 }, 200, function() {
28628
28629                                    image
28630
28631                                        .removeAttr('data-lazy data-srcset data-sizes')
28632
28633                                        .removeClass('slick-loading');
28634
28635                                });
28636
28637                            _.$slider.trigger('lazyLoaded', [_, image, imageSource]);
28638
28639                        });
28640
28641
28642
28643                };
28644
28645
28646
28647                imageToLoad.onerror = function() {
28648
28649
28650
28651                    image
28652
28653                        .removeAttr( 'data-lazy' )
28654
28655                        .removeClass( 'slick-loading' )
28656
28657                        .addClass( 'slick-lazyload-error' );
28658
28659
28660
28661                    _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]);
28662
28663
28664
28665                };
28666
28667
28668
28669                imageToLoad.src = imageSource;
28670
28671
28672
28673            });
28674
28675
28676
28677        }
28678
28679
28680
28681        if (_.options.centerMode === true) {
28682
28683            if (_.options.infinite === true) {
28684
28685                rangeStart = _.currentSlide + (_.options.slidesToShow / 2 + 1);
28686
28687                rangeEnd = rangeStart + _.options.slidesToShow + 2;
28688
28689            } else {
28690
28691                rangeStart = Math.max(0, _.currentSlide - (_.options.slidesToShow / 2 + 1));
28692
28693                rangeEnd = 2 + (_.options.slidesToShow / 2 + 1) + _.currentSlide;
28694
28695            }
28696
28697        } else {
28698
28699            rangeStart = _.options.infinite ? _.options.slidesToShow + _.currentSlide : _.currentSlide;
28700
28701            rangeEnd = Math.ceil(rangeStart + _.options.slidesToShow);
28702
28703            if (_.options.fade === true) {
28704
28705                if (rangeStart > 0) rangeStart--;
28706
28707                if (rangeEnd <= _.slideCount) rangeEnd++;
28708
28709            }
28710
28711        }
28712
28713
28714
28715        loadRange = _.$slider.find('.slick-slide').slice(rangeStart, rangeEnd);
28716
28717
28718
28719        if (_.options.lazyLoad === 'anticipated') {
28720
28721            var prevSlide = rangeStart - 1,
28722
28723                nextSlide = rangeEnd,
28724
28725                $slides = _.$slider.find('.slick-slide');
28726
28727
28728
28729            for (var i = 0; i < _.options.slidesToScroll; i++) {
28730
28731                if (prevSlide < 0) prevSlide = _.slideCount - 1;
28732
28733                loadRange = loadRange.add($slides.eq(prevSlide));
28734
28735                loadRange = loadRange.add($slides.eq(nextSlide));
28736
28737                prevSlide--;
28738
28739                nextSlide++;
28740
28741            }
28742
28743        }
28744
28745
28746
28747        loadImages(loadRange);
28748
28749
28750
28751        if (_.slideCount <= _.options.slidesToShow) {
28752
28753            cloneRange = _.$slider.find('.slick-slide');
28754
28755            loadImages(cloneRange);
28756
28757        } else
28758
28759        if (_.currentSlide >= _.slideCount - _.options.slidesToShow) {
28760
28761            cloneRange = _.$slider.find('.slick-cloned').slice(0, _.options.slidesToShow);
28762
28763            loadImages(cloneRange);
28764
28765        } else if (_.currentSlide === 0) {
28766
28767            cloneRange = _.$slider.find('.slick-cloned').slice(_.options.slidesToShow * -1);
28768
28769            loadImages(cloneRange);
28770
28771        }
28772
28773
28774
28775    };
28776
28777
28778
28779    Slick.prototype.loadSlider = function() {
28780
28781
28782
28783        var _ = this;
28784
28785
28786
28787        _.setPosition();
28788
28789
28790
28791        _.$slideTrack.css({
28792
28793            opacity: 1
28794
28795        });
28796
28797
28798
28799        _.$slider.removeClass('slick-loading');
28800
28801
28802
28803        _.initUI();
28804
28805
28806
28807        if (_.options.lazyLoad === 'progressive') {
28808
28809            _.progressiveLazyLoad();
28810
28811        }
28812
28813
28814
28815    };
28816
28817
28818
28819    Slick.prototype.next = Slick.prototype.slickNext = function() {
28820
28821
28822
28823        var _ = this;
28824
28825
28826
28827        _.changeSlide({
28828
28829            data: {
28830
28831                message: 'next'
28832
28833            }
28834
28835        });
28836
28837
28838
28839    };
28840
28841
28842
28843    Slick.prototype.orientationChange = function() {
28844
28845
28846
28847        var _ = this;
28848
28849
28850
28851        _.checkResponsive();
28852
28853        _.setPosition();
28854
28855
28856
28857    };
28858
28859
28860
28861    Slick.prototype.pause = Slick.prototype.slickPause = function() {
28862
28863
28864
28865        var _ = this;
28866
28867
28868
28869        _.autoPlayClear();
28870
28871        _.paused = true;
28872
28873
28874
28875    };
28876
28877
28878
28879    Slick.prototype.play = Slick.prototype.slickPlay = function() {
28880
28881
28882
28883        var _ = this;
28884
28885
28886
28887        _.autoPlay();
28888
28889        _.options.autoplay = true;
28890
28891        _.paused = false;
28892
28893        _.focussed = false;
28894
28895        _.interrupted = false;
28896
28897
28898
28899    };
28900
28901
28902
28903    Slick.prototype.postSlide = function(index) {
28904
28905
28906
28907        var _ = this;
28908
28909
28910
28911        if( !_.unslicked ) {
28912
28913
28914
28915            _.$slider.trigger('afterChange', [_, index]);
28916
28917
28918
28919            _.animating = false;
28920
28921
28922
28923            if (_.slideCount > _.options.slidesToShow) {
28924
28925                _.setPosition();
28926
28927            }
28928
28929
28930
28931            _.swipeLeft = null;
28932
28933
28934
28935            if ( _.options.autoplay ) {
28936
28937                _.autoPlay();
28938
28939            }
28940
28941
28942
28943            if (_.options.accessibility === true) {
28944
28945                _.initADA();
28946
28947
28948
28949                if (_.options.focusOnChange) {
28950
28951                    var $currentSlide = $(_.$slides.get(_.currentSlide));
28952
28953                    $currentSlide.attr('tabindex', 0).focus();
28954
28955                }
28956
28957            }
28958
28959
28960
28961        }
28962
28963
28964
28965    };
28966
28967
28968
28969    Slick.prototype.prev = Slick.prototype.slickPrev = function() {
28970
28971
28972
28973        var _ = this;
28974
28975
28976
28977        _.changeSlide({
28978
28979            data: {
28980
28981                message: 'previous'
28982
28983            }
28984
28985        });
28986
28987
28988
28989    };
28990
28991
28992
28993    Slick.prototype.preventDefault = function(event) {
28994
28995
28996
28997        event.preventDefault();
28998
28999
29000
29001    };
29002
29003
29004
29005    Slick.prototype.progressiveLazyLoad = function( tryCount ) {
29006
29007
29008
29009        tryCount = tryCount || 1;
29010
29011
29012
29013        var _ = this,
29014
29015            $imgsToLoad = $( 'img[data-lazy]', _.$slider ),
29016
29017            image,
29018
29019            imageSource,
29020
29021            imageSrcSet,
29022
29023            imageSizes,
29024
29025            imageToLoad;
29026
29027
29028
29029        if ( $imgsToLoad.length ) {
29030
29031
29032
29033            image = $imgsToLoad.first();
29034
29035            imageSource = image.attr('data-lazy');
29036
29037            imageSrcSet = image.attr('data-srcset');
29038
29039            imageSizes  = image.attr('data-sizes') || _.$slider.attr('data-sizes');
29040
29041            imageToLoad = document.createElement('img');
29042
29043
29044
29045            imageToLoad.onload = function() {
29046
29047
29048
29049                if (imageSrcSet) {
29050
29051                    image
29052
29053                        .attr('srcset', imageSrcSet );
29054
29055
29056
29057                    if (imageSizes) {
29058
29059                        image
29060
29061                            .attr('sizes', imageSizes );
29062
29063                    }
29064
29065                }
29066
29067
29068
29069                image
29070
29071                    .attr( 'src', imageSource )
29072
29073                    .removeAttr('data-lazy data-srcset data-sizes')
29074
29075                    .removeClass('slick-loading');
29076
29077
29078
29079                if ( _.options.adaptiveHeight === true ) {
29080
29081                    _.setPosition();
29082
29083                }
29084
29085
29086
29087                _.$slider.trigger('lazyLoaded', [ _, image, imageSource ]);
29088
29089                _.progressiveLazyLoad();
29090
29091
29092
29093            };
29094
29095
29096
29097            imageToLoad.onerror = function() {
29098
29099
29100
29101                if ( tryCount < 3 ) {
29102
29103
29104
29105                    /**
29106
29107                     * try to load the image 3 times,
29108
29109                     * leave a slight delay so we don't get
29110
29111                     * servers blocking the request.
29112
29113                     */
29114
29115                    setTimeout( function() {
29116
29117                        _.progressiveLazyLoad( tryCount + 1 );
29118
29119                    }, 500 );
29120
29121
29122
29123                } else {
29124
29125
29126
29127                    image
29128
29129                        .removeAttr( 'data-lazy' )
29130
29131                        .removeClass( 'slick-loading' )
29132
29133                        .addClass( 'slick-lazyload-error' );
29134
29135
29136
29137                    _.$slider.trigger('lazyLoadError', [ _, image, imageSource ]);
29138
29139
29140
29141                    _.progressiveLazyLoad();
29142
29143
29144
29145                }
29146
29147
29148
29149            };
29150
29151
29152
29153            imageToLoad.src = imageSource;
29154
29155
29156
29157        } else {
29158
29159
29160
29161            _.$slider.trigger('allImagesLoaded', [ _ ]);
29162
29163
29164
29165        }
29166
29167
29168
29169    };
29170
29171
29172
29173    Slick.prototype.refresh = function( initializing ) {
29174
29175
29176
29177        var _ = this, currentSlide, lastVisibleIndex;
29178
29179
29180
29181        lastVisibleIndex = _.slideCount - _.options.slidesToShow;
29182
29183
29184
29185        // in non-infinite sliders, we don't want to go past the
29186
29187        // last visible index.
29188
29189        if( !_.options.infinite && ( _.currentSlide > lastVisibleIndex )) {
29190
29191            _.currentSlide = lastVisibleIndex;
29192
29193        }
29194
29195
29196
29197        // if less slides than to show, go to start.
29198
29199        if ( _.slideCount <= _.options.slidesToShow ) {
29200
29201            _.currentSlide = 0;
29202
29203
29204
29205        }
29206
29207
29208
29209        currentSlide = _.currentSlide;
29210
29211
29212
29213        _.destroy(true);
29214
29215
29216
29217        $.extend(_, _.initials, { currentSlide: currentSlide });
29218
29219
29220
29221        _.init();
29222
29223
29224
29225        if( !initializing ) {
29226
29227
29228
29229            _.changeSlide({
29230
29231                data: {
29232
29233                    message: 'index',
29234
29235                    index: currentSlide
29236
29237                }
29238
29239            }, false);
29240
29241
29242
29243        }
29244
29245
29246
29247    };
29248
29249
29250
29251    Slick.prototype.registerBreakpoints = function() {
29252
29253
29254
29255        var _ = this, breakpoint, currentBreakpoint, l,
29256
29257            responsiveSettings = _.options.responsive || null;
29258
29259
29260
29261        if ( $.type(responsiveSettings) === 'array' && responsiveSettings.length ) {
29262
29263
29264
29265            _.respondTo = _.options.respondTo || 'window';
29266
29267
29268
29269            for ( breakpoint in responsiveSettings ) {
29270
29271
29272
29273                l = _.breakpoints.length-1;
29274
29275
29276
29277                if (responsiveSettings.hasOwnProperty(breakpoint)) {
29278
29279                    currentBreakpoint = responsiveSettings[breakpoint].breakpoint;
29280
29281
29282
29283                    // loop through the breakpoints and cut out any existing
29284
29285                    // ones with the same breakpoint number, we don't want dupes.
29286
29287                    while( l >= 0 ) {
29288
29289                        if( _.breakpoints[l] && _.breakpoints[l] === currentBreakpoint ) {
29290
29291                            _.breakpoints.splice(l,1);
29292
29293                        }
29294
29295                        l--;
29296
29297                    }
29298
29299
29300
29301                    _.breakpoints.push(currentBreakpoint);
29302
29303                    _.breakpointSettings[currentBreakpoint] = responsiveSettings[breakpoint].settings;
29304
29305
29306
29307                }
29308
29309
29310
29311            }
29312
29313
29314
29315            _.breakpoints.sort(function(a, b) {
29316
29317                return ( _.options.mobileFirst ) ? a-b : b-a;
29318
29319            });
29320
29321
29322
29323        }
29324
29325
29326
29327    };
29328
29329
29330
29331    Slick.prototype.reinit = function() {
29332
29333
29334
29335        var _ = this;
29336
29337
29338
29339        _.$slides =
29340
29341            _.$slideTrack
29342
29343                .children(_.options.slide)
29344
29345                .addClass('slick-slide');
29346
29347
29348
29349        _.slideCount = _.$slides.length;
29350
29351
29352
29353        if (_.currentSlide >= _.slideCount && _.currentSlide !== 0) {
29354
29355            _.currentSlide = _.currentSlide - _.options.slidesToScroll;
29356
29357        }
29358
29359
29360
29361        if (_.slideCount <= _.options.slidesToShow) {
29362
29363            _.currentSlide = 0;
29364
29365        }
29366
29367
29368
29369        _.registerBreakpoints();
29370
29371
29372
29373        _.setProps();
29374
29375        _.setupInfinite();
29376
29377        _.buildArrows();
29378
29379        _.updateArrows();
29380
29381        _.initArrowEvents();
29382
29383        _.buildDots();
29384
29385        _.updateDots();
29386
29387        _.initDotEvents();
29388
29389        _.cleanUpSlideEvents();
29390
29391        _.initSlideEvents();
29392
29393
29394
29395        _.checkResponsive(false, true);
29396
29397
29398
29399        if (_.options.focusOnSelect === true) {
29400
29401            $(_.$slideTrack).children().on('click.slick', _.selectHandler);
29402
29403        }
29404
29405
29406
29407        _.setSlideClasses(typeof _.currentSlide === 'number' ? _.currentSlide : 0);
29408
29409
29410
29411        _.setPosition();
29412
29413        _.focusHandler();
29414
29415
29416
29417        _.paused = !_.options.autoplay;
29418
29419        _.autoPlay();
29420
29421
29422
29423        _.$slider.trigger('reInit', [_]);
29424
29425
29426
29427    };
29428
29429
29430
29431    Slick.prototype.resize = function() {
29432
29433
29434
29435        var _ = this;
29436
29437
29438
29439        if ($(window).width() !== _.windowWidth) {
29440
29441            clearTimeout(_.windowDelay);
29442
29443            _.windowDelay = window.setTimeout(function() {
29444
29445                _.windowWidth = $(window).width();
29446
29447                _.checkResponsive();
29448
29449                if( !_.unslicked ) { _.setPosition(); }
29450
29451            }, 50);
29452
29453        }
29454
29455    };
29456
29457
29458
29459    Slick.prototype.removeSlide = Slick.prototype.slickRemove = function(index, removeBefore, removeAll) {
29460
29461
29462
29463        var _ = this;
29464
29465
29466
29467        if (typeof(index) === 'boolean') {
29468
29469            removeBefore = index;
29470
29471            index = removeBefore === true ? 0 : _.slideCount - 1;
29472
29473        } else {
29474
29475            index = removeBefore === true ? --index : index;
29476
29477        }
29478
29479
29480
29481        if (_.slideCount < 1 || index < 0 || index > _.slideCount - 1) {
29482
29483            return false;
29484
29485        }
29486
29487
29488
29489        _.unload();
29490
29491
29492
29493        if (removeAll === true) {
29494
29495            _.$slideTrack.children().remove();
29496
29497        } else {
29498
29499            _.$slideTrack.children(this.options.slide).eq(index).remove();
29500
29501        }
29502
29503
29504
29505        _.$slides = _.$slideTrack.children(this.options.slide);
29506
29507
29508
29509        _.$slideTrack.children(this.options.slide).detach();
29510
29511
29512
29513        _.$slideTrack.append(_.$slides);
29514
29515
29516
29517        _.$slidesCache = _.$slides;
29518
29519
29520
29521        _.reinit();
29522
29523
29524
29525    };
29526
29527
29528
29529    Slick.prototype.setCSS = function(position) {
29530
29531
29532
29533        var _ = this,
29534
29535            positionProps = {},
29536
29537            x, y;
29538
29539
29540
29541        if (_.options.rtl === true) {
29542
29543            position = -position;
29544
29545        }
29546
29547        x = _.positionProp == 'left' ? Math.ceil(position) + 'px' : '0px';
29548
29549        y = _.positionProp == 'top' ? Math.ceil(position) + 'px' : '0px';
29550
29551
29552
29553        positionProps[_.positionProp] = position;
29554
29555
29556
29557        if (_.transformsEnabled === false) {
29558
29559            _.$slideTrack.css(positionProps);
29560
29561        } else {
29562
29563            positionProps = {};
29564
29565            if (_.cssTransitions === false) {
29566
29567                positionProps[_.animType] = 'translate(' + x + ', ' + y + ')';
29568
29569                _.$slideTrack.css(positionProps);
29570
29571            } else {
29572
29573                positionProps[_.animType] = 'translate3d(' + x + ', ' + y + ', 0px)';
29574
29575                _.$slideTrack.css(positionProps);
29576
29577            }
29578
29579        }
29580
29581
29582
29583    };
29584
29585
29586
29587    Slick.prototype.setDimensions = function() {
29588
29589
29590
29591        var _ = this;
29592
29593
29594
29595        if (_.options.vertical === false) {
29596
29597            if (_.options.centerMode === true) {
29598
29599                _.$list.css({
29600
29601                    padding: ('0px ' + _.options.centerPadding)
29602
29603                });
29604
29605            }
29606
29607        } else {
29608
29609            _.$list.height(_.$slides.first().outerHeight(true) * _.options.slidesToShow);
29610
29611            if (_.options.centerMode === true) {
29612
29613                _.$list.css({
29614
29615                    padding: (_.options.centerPadding + ' 0px')
29616
29617                });
29618
29619            }
29620
29621        }
29622
29623
29624
29625        _.listWidth = _.$list.width();
29626
29627        _.listHeight = _.$list.height();
29628
29629
29630
29631
29632
29633        if (_.options.vertical === false && _.options.variableWidth === false) {
29634
29635            _.slideWidth = Math.ceil(_.listWidth / _.options.slidesToShow);
29636
29637            _.$slideTrack.width(Math.ceil((_.slideWidth * _.$slideTrack.children('.slick-slide').length)));
29638
29639
29640
29641        } else if (_.options.variableWidth === true) {
29642
29643            _.$slideTrack.width(5000 * _.slideCount);
29644
29645        } else {
29646
29647            _.slideWidth = Math.ceil(_.listWidth);
29648
29649            _.$slideTrack.height(Math.ceil((_.$slides.first().outerHeight(true) * _.$slideTrack.children('.slick-slide').length)));
29650
29651        }
29652
29653
29654
29655        var offset = _.$slides.first().outerWidth(true) - _.$slides.first().width();
29656
29657        if (_.options.variableWidth === false) _.$slideTrack.children('.slick-slide').width(_.slideWidth - offset);
29658
29659
29660
29661    };
29662
29663
29664
29665    Slick.prototype.setFade = function() {
29666
29667
29668
29669        var _ = this,
29670
29671            targetLeft;
29672
29673
29674
29675        _.$slides.each(function(index, element) {
29676
29677            targetLeft = (_.slideWidth * index) * -1;
29678
29679            if (_.options.rtl === true) {
29680
29681                $(element).css({
29682
29683                    position: 'relative',
29684
29685                    right: targetLeft,
29686
29687                    top: 0,
29688
29689                    zIndex: _.options.zIndex - 2,
29690
29691                    opacity: 0
29692
29693                });
29694
29695            } else {
29696
29697                $(element).css({
29698
29699                    position: 'relative',
29700
29701                    left: targetLeft,
29702
29703                    top: 0,
29704
29705                    zIndex: _.options.zIndex - 2,
29706
29707                    opacity: 0
29708
29709                });
29710
29711            }
29712
29713        });
29714
29715
29716
29717        _.$slides.eq(_.currentSlide).css({
29718
29719            zIndex: _.options.zIndex - 1,
29720
29721            opacity: 1
29722
29723        });
29724
29725
29726
29727    };
29728
29729
29730
29731    Slick.prototype.setHeight = function() {
29732
29733
29734
29735        var _ = this;
29736
29737
29738
29739        if (_.options.slidesToShow === 1 && _.options.adaptiveHeight === true && _.options.vertical === false) {
29740
29741            var targetHeight = _.$slides.eq(_.currentSlide).outerHeight(true);
29742
29743            _.$list.css('height', targetHeight);
29744
29745        }
29746
29747
29748
29749    };
29750
29751
29752
29753    Slick.prototype.setOption =
29754
29755    Slick.prototype.slickSetOption = function() {
29756
29757
29758
29759        /**
29760
29761         * accepts arguments in format of:
29762
29763         *
29764
29765         *  - for changing a single option's value:
29766
29767         *     .slick("setOption", option, value, refresh )
29768
29769         *
29770
29771         *  - for changing a set of responsive options:
29772
29773         *     .slick("setOption", 'responsive', [{}, ...], refresh )
29774
29775         *
29776
29777         *  - for updating multiple values at once (not responsive)
29778
29779         *     .slick("setOption", { 'option': value, ... }, refresh )
29780
29781         */
29782
29783
29784
29785        var _ = this, l, item, option, value, refresh = false, type;
29786
29787
29788
29789        if( $.type( arguments[0] ) === 'object' ) {
29790
29791
29792
29793            option =  arguments[0];
29794
29795            refresh = arguments[1];
29796
29797            type = 'multiple';
29798
29799
29800
29801        } else if ( $.type( arguments[0] ) === 'string' ) {
29802
29803
29804
29805            option =  arguments[0];
29806
29807            value = arguments[1];
29808
29809            refresh = arguments[2];
29810
29811
29812
29813            if ( arguments[0] === 'responsive' && $.type( arguments[1] ) === 'array' ) {
29814
29815
29816
29817                type = 'responsive';
29818
29819
29820
29821            } else if ( typeof arguments[1] !== 'undefined' ) {
29822
29823
29824
29825                type = 'single';
29826
29827
29828
29829            }
29830
29831
29832
29833        }
29834
29835
29836
29837        if ( type === 'single' ) {
29838
29839
29840
29841            _.options[option] = value;
29842
29843
29844
29845
29846
29847        } else if ( type === 'multiple' ) {
29848
29849
29850
29851            $.each( option , function( opt, val ) {
29852
29853
29854
29855                _.options[opt] = val;
29856
29857
29858
29859            });
29860
29861
29862
29863
29864
29865        } else if ( type === 'responsive' ) {
29866
29867
29868
29869            for ( item in value ) {
29870
29871
29872
29873                if( $.type( _.options.responsive ) !== 'array' ) {
29874
29875
29876
29877                    _.options.responsive = [ value[item] ];
29878
29879
29880
29881                } else {
29882
29883
29884
29885                    l = _.options.responsive.length-1;
29886
29887
29888
29889                    // loop through the responsive object and splice out duplicates.
29890
29891                    while( l >= 0 ) {
29892
29893
29894
29895                        if( _.options.responsive[l].breakpoint === value[item].breakpoint ) {
29896
29897
29898
29899                            _.options.responsive.splice(l,1);
29900
29901
29902
29903                        }
29904
29905
29906
29907                        l--;
29908
29909
29910
29911                    }
29912
29913
29914
29915                    _.options.responsive.push( value[item] );
29916
29917
29918
29919                }
29920
29921
29922
29923            }
29924
29925
29926
29927        }
29928
29929
29930
29931        if ( refresh ) {
29932
29933
29934
29935            _.unload();
29936
29937            _.reinit();
29938
29939
29940
29941        }
29942
29943
29944
29945    };
29946
29947
29948
29949    Slick.prototype.setPosition = function() {
29950
29951
29952
29953        var _ = this;
29954
29955
29956
29957        _.setDimensions();
29958
29959
29960
29961        _.setHeight();
29962
29963
29964
29965        if (_.options.fade === false) {
29966
29967            _.setCSS(_.getLeft(_.currentSlide));
29968
29969        } else {
29970
29971            _.setFade();
29972
29973        }
29974
29975
29976
29977        _.$slider.trigger('setPosition', [_]);
29978
29979
29980
29981    };
29982
29983
29984
29985    Slick.prototype.setProps = function() {
29986
29987
29988
29989        var _ = this,
29990
29991            bodyStyle = document.body.style;
29992
29993
29994
29995        _.positionProp = _.options.vertical === true ? 'top' : 'left';
29996
29997
29998
29999        if (_.positionProp === 'top') {
30000
30001            _.$slider.addClass('slick-vertical');
30002
30003        } else {
30004
30005            _.$slider.removeClass('slick-vertical');
30006
30007        }
30008
30009
30010
30011        if (bodyStyle.WebkitTransition !== undefined ||
30012
30013            bodyStyle.MozTransition !== undefined ||
30014
30015            bodyStyle.msTransition !== undefined) {
30016
30017            if (_.options.useCSS === true) {
30018
30019                _.cssTransitions = true;
30020
30021            }
30022
30023        }
30024
30025
30026
30027        if ( _.options.fade ) {
30028
30029            if ( typeof _.options.zIndex === 'number' ) {
30030
30031                if( _.options.zIndex < 3 ) {
30032
30033                    _.options.zIndex = 3;
30034
30035                }
30036
30037            } else {
30038
30039                _.options.zIndex = _.defaults.zIndex;
30040
30041            }
30042
30043        }
30044
30045
30046
30047        if (bodyStyle.OTransform !== undefined) {
30048
30049            _.animType = 'OTransform';
30050
30051            _.transformType = '-o-transform';
30052
30053            _.transitionType = 'OTransition';
30054
30055            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
30056
30057        }
30058
30059        if (bodyStyle.MozTransform !== undefined) {
30060
30061            _.animType = 'MozTransform';
30062
30063            _.transformType = '-moz-transform';
30064
30065            _.transitionType = 'MozTransition';
30066
30067            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.MozPerspective === undefined) _.animType = false;
30068
30069        }
30070
30071        if (bodyStyle.webkitTransform !== undefined) {
30072
30073            _.animType = 'webkitTransform';
30074
30075            _.transformType = '-webkit-transform';
30076
30077            _.transitionType = 'webkitTransition';
30078
30079            if (bodyStyle.perspectiveProperty === undefined && bodyStyle.webkitPerspective === undefined) _.animType = false;
30080
30081        }
30082
30083        if (bodyStyle.msTransform !== undefined) {
30084
30085            _.animType = 'msTransform';
30086
30087            _.transformType = '-ms-transform';
30088
30089            _.transitionType = 'msTransition';
30090
30091            if (bodyStyle.msTransform === undefined) _.animType = false;
30092
30093        }
30094
30095        if (bodyStyle.transform !== undefined && _.animType !== false) {
30096
30097            _.animType = 'transform';
30098
30099            _.transformType = 'transform';
30100
30101            _.transitionType = 'transition';
30102
30103        }
30104
30105        _.transformsEnabled = _.options.useTransform && (_.animType !== null && _.animType !== false);
30106
30107    };
30108
30109
30110
30111
30112
30113    Slick.prototype.setSlideClasses = function(index) {
30114
30115
30116
30117        var _ = this,
30118
30119            centerOffset, allSlides, indexOffset, remainder;
30120
30121
30122
30123        allSlides = _.$slider
30124
30125            .find('.slick-slide')
30126
30127            .removeClass('slick-active slick-center slick-current')
30128
30129            .attr('aria-hidden', 'true');
30130
30131
30132
30133        _.$slides
30134
30135            .eq(index)
30136
30137            .addClass('slick-current');
30138
30139
30140
30141        if (_.options.centerMode === true) {
30142
30143
30144
30145            var evenCoef = _.options.slidesToShow % 2 === 0 ? 1 : 0;
30146
30147
30148
30149            centerOffset = Math.floor(_.options.slidesToShow / 2);
30150
30151
30152
30153            if (_.options.infinite === true) {
30154
30155
30156
30157                if (index >= centerOffset && index <= (_.slideCount - 1) - centerOffset) {
30158
30159                    _.$slides
30160
30161                        .slice(index - centerOffset + evenCoef, index + centerOffset + 1)
30162
30163                        .addClass('slick-active')
30164
30165                        .attr('aria-hidden', 'false');
30166
30167
30168
30169                } else {
30170
30171
30172
30173                    indexOffset = _.options.slidesToShow + index;
30174
30175                    allSlides
30176
30177                        .slice(indexOffset - centerOffset + 1 + evenCoef, indexOffset + centerOffset + 2)
30178
30179                        .addClass('slick-active')
30180
30181                        .attr('aria-hidden', 'false');
30182
30183
30184
30185                }
30186
30187
30188
30189                if (index === 0) {
30190
30191
30192
30193                    allSlides
30194
30195                        .eq(allSlides.length - 1 - _.options.slidesToShow)
30196
30197                        .addClass('slick-center');
30198
30199
30200
30201                } else if (index === _.slideCount - 1) {
30202
30203
30204
30205                    allSlides
30206
30207                        .eq(_.options.slidesToShow)
30208
30209                        .addClass('slick-center');
30210
30211
30212
30213                }
30214
30215
30216
30217            }
30218
30219
30220
30221            _.$slides
30222
30223                .eq(index)
30224
30225                .addClass('slick-center');
30226
30227
30228
30229        } else {
30230
30231
30232
30233            if (index >= 0 && index <= (_.slideCount - _.options.slidesToShow)) {
30234
30235
30236
30237                _.$slides
30238
30239                    .slice(index, index + _.options.slidesToShow)
30240
30241                    .addClass('slick-active')
30242
30243                    .attr('aria-hidden', 'false');
30244
30245
30246
30247            } else if (allSlides.length <= _.options.slidesToShow) {
30248
30249
30250
30251                allSlides
30252
30253                    .addClass('slick-active')
30254
30255                    .attr('aria-hidden', 'false');
30256
30257
30258
30259            } else {
30260
30261
30262
30263                remainder = _.slideCount % _.options.slidesToShow;
30264
30265                indexOffset = _.options.infinite === true ? _.options.slidesToShow + index : index;
30266
30267
30268
30269                if (_.options.slidesToShow == _.options.slidesToScroll && (_.slideCount - index) < _.options.slidesToShow) {
30270
30271
30272
30273                    allSlides
30274
30275                        .slice(indexOffset - (_.options.slidesToShow - remainder), indexOffset + remainder)
30276
30277                        .addClass('slick-active')
30278
30279                        .attr('aria-hidden', 'false');
30280
30281
30282
30283                } else {
30284
30285
30286
30287                    allSlides
30288
30289                        .slice(indexOffset, indexOffset + _.options.slidesToShow)
30290
30291                        .addClass('slick-active')
30292
30293                        .attr('aria-hidden', 'false');
30294
30295
30296
30297                }
30298
30299
30300
30301            }
30302
30303
30304
30305        }
30306
30307
30308
30309        if (_.options.lazyLoad === 'ondemand' || _.options.lazyLoad === 'anticipated') {
30310
30311            _.lazyLoad();
30312
30313        }
30314
30315    };
30316
30317
30318
30319    Slick.prototype.setupInfinite = function() {
30320
30321
30322
30323        var _ = this,
30324
30325            i, slideIndex, infiniteCount;
30326
30327
30328
30329        if (_.options.fade === true) {
30330
30331            _.options.centerMode = false;
30332
30333        }
30334
30335
30336
30337        if (_.options.infinite === true && _.options.fade === false) {
30338
30339
30340
30341            slideIndex = null;
30342
30343
30344
30345            if (_.slideCount > _.options.slidesToShow) {
30346
30347
30348
30349                if (_.options.centerMode === true) {
30350
30351                    infiniteCount = _.options.slidesToShow + 1;
30352
30353                } else {
30354
30355                    infiniteCount = _.options.slidesToShow;
30356
30357                }
30358
30359
30360
30361                for (i = _.slideCount; i > (_.slideCount -
30362
30363                        infiniteCount); i -= 1) {
30364
30365                    slideIndex = i - 1;
30366
30367                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
30368
30369                        .attr('data-slick-index', slideIndex - _.slideCount)
30370
30371                        .prependTo(_.$slideTrack).addClass('slick-cloned');
30372
30373                }
30374
30375                for (i = 0; i < infiniteCount  + _.slideCount; i += 1) {
30376
30377                    slideIndex = i;
30378
30379                    $(_.$slides[slideIndex]).clone(true).attr('id', '')
30380
30381                        .attr('data-slick-index', slideIndex + _.slideCount)
30382
30383                        .appendTo(_.$slideTrack).addClass('slick-cloned');
30384
30385                }
30386
30387                _.$slideTrack.find('.slick-cloned').find('[id]').each(function() {
30388
30389                    $(this).attr('id', '');
30390
30391                });
30392
30393
30394
30395            }
30396
30397
30398
30399        }
30400
30401
30402
30403    };
30404
30405
30406
30407    Slick.prototype.interrupt = function( toggle ) {
30408
30409
30410
30411        var _ = this;
30412
30413
30414
30415        if( !toggle ) {
30416
30417            _.autoPlay();
30418
30419        }
30420
30421        _.interrupted = toggle;
30422
30423
30424
30425    };
30426
30427
30428
30429    Slick.prototype.selectHandler = function(event) {
30430
30431
30432
30433        var _ = this;
30434
30435
30436
30437        var targetElement =
30438
30439            $(event.target).is('.slick-slide') ?
30440
30441                $(event.target) :
30442
30443                $(event.target).parents('.slick-slide');
30444
30445
30446
30447        var index = parseInt(targetElement.attr('data-slick-index'));
30448
30449
30450
30451        if (!index) index = 0;
30452
30453
30454
30455        if (_.slideCount <= _.options.slidesToShow) {
30456
30457
30458
30459            _.slideHandler(index, false, true);
30460
30461            return;
30462
30463
30464
30465        }
30466
30467
30468
30469        _.slideHandler(index);
30470
30471
30472
30473    };
30474
30475
30476
30477    Slick.prototype.slideHandler = function(index, sync, dontAnimate) {
30478
30479
30480
30481        var targetSlide, animSlide, oldSlide, slideLeft, targetLeft = null,
30482
30483            _ = this, navTarget;
30484
30485
30486
30487        sync = sync || false;
30488
30489
30490
30491        if (_.animating === true && _.options.waitForAnimate === true) {
30492
30493            return;
30494
30495        }
30496
30497
30498
30499        if (_.options.fade === true && _.currentSlide === index) {
30500
30501            return;
30502
30503        }
30504
30505
30506
30507        if (sync === false) {
30508
30509            _.asNavFor(index);
30510
30511        }
30512
30513
30514
30515        targetSlide = index;
30516
30517        targetLeft = _.getLeft(targetSlide);
30518
30519        slideLeft = _.getLeft(_.currentSlide);
30520
30521
30522
30523        _.currentLeft = _.swipeLeft === null ? slideLeft : _.swipeLeft;
30524
30525
30526
30527        if (_.options.infinite === false && _.options.centerMode === false && (index < 0 || index > _.getDotCount() * _.options.slidesToScroll)) {
30528
30529            if (_.options.fade === false) {
30530
30531                targetSlide = _.currentSlide;
30532
30533                if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
30534
30535                    _.animateSlide(slideLeft, function() {
30536
30537                        _.postSlide(targetSlide);
30538
30539                    });
30540
30541                } else {
30542
30543                    _.postSlide(targetSlide);
30544
30545                }
30546
30547            }
30548
30549            return;
30550
30551        } else if (_.options.infinite === false && _.options.centerMode === true && (index < 0 || index > (_.slideCount - _.options.slidesToScroll))) {
30552
30553            if (_.options.fade === false) {
30554
30555                targetSlide = _.currentSlide;
30556
30557                if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
30558
30559                    _.animateSlide(slideLeft, function() {
30560
30561                        _.postSlide(targetSlide);
30562
30563                    });
30564
30565                } else {
30566
30567                    _.postSlide(targetSlide);
30568
30569                }
30570
30571            }
30572
30573            return;
30574
30575        }
30576
30577
30578
30579        if ( _.options.autoplay ) {
30580
30581            clearInterval(_.autoPlayTimer);
30582
30583        }
30584
30585
30586
30587        if (targetSlide < 0) {
30588
30589            if (_.slideCount % _.options.slidesToScroll !== 0) {
30590
30591                animSlide = _.slideCount - (_.slideCount % _.options.slidesToScroll);
30592
30593            } else {
30594
30595                animSlide = _.slideCount + targetSlide;
30596
30597            }
30598
30599        } else if (targetSlide >= _.slideCount) {
30600
30601            if (_.slideCount % _.options.slidesToScroll !== 0) {
30602
30603                animSlide = 0;
30604
30605            } else {
30606
30607                animSlide = targetSlide - _.slideCount;
30608
30609            }
30610
30611        } else {
30612
30613            animSlide = targetSlide;
30614
30615        }
30616
30617
30618
30619        _.animating = true;
30620
30621
30622
30623        _.$slider.trigger('beforeChange', [_, _.currentSlide, animSlide]);
30624
30625
30626
30627        oldSlide = _.currentSlide;
30628
30629        _.currentSlide = animSlide;
30630
30631
30632
30633        _.setSlideClasses(_.currentSlide);
30634
30635
30636
30637        if ( _.options.asNavFor ) {
30638
30639
30640
30641            navTarget = _.getNavTarget();
30642
30643            navTarget = navTarget.slick('getSlick');
30644
30645
30646
30647            if ( navTarget.slideCount <= navTarget.options.slidesToShow ) {
30648
30649                navTarget.setSlideClasses(_.currentSlide);
30650
30651            }
30652
30653
30654
30655        }
30656
30657
30658
30659        _.updateDots();
30660
30661        _.updateArrows();
30662
30663
30664
30665        if (_.options.fade === true) {
30666
30667            if (dontAnimate !== true) {
30668
30669
30670
30671                _.fadeSlideOut(oldSlide);
30672
30673
30674
30675                _.fadeSlide(animSlide, function() {
30676
30677                    _.postSlide(animSlide);
30678
30679                });
30680
30681
30682
30683            } else {
30684
30685                _.postSlide(animSlide);
30686
30687            }
30688
30689            _.animateHeight();
30690
30691            return;
30692
30693        }
30694
30695
30696
30697        if (dontAnimate !== true && _.slideCount > _.options.slidesToShow) {
30698
30699            _.animateSlide(targetLeft, function() {
30700
30701                _.postSlide(animSlide);
30702
30703            });
30704
30705        } else {
30706
30707            _.postSlide(animSlide);
30708
30709        }
30710
30711
30712
30713    };
30714
30715
30716
30717    Slick.prototype.startLoad = function() {
30718
30719
30720
30721        var _ = this;
30722
30723
30724
30725        if (_.options.arrows === true && _.slideCount > _.options.slidesToShow) {
30726
30727
30728
30729            _.$prevArrow.hide();
30730
30731            _.$nextArrow.hide();
30732
30733
30734
30735        }
30736
30737
30738
30739        if (_.options.dots === true && _.slideCount > _.options.slidesToShow) {
30740
30741
30742
30743            _.$dots.hide();
30744
30745
30746
30747        }
30748
30749
30750
30751        _.$slider.addClass('slick-loading');
30752
30753
30754
30755    };
30756
30757
30758
30759    Slick.prototype.swipeDirection = function() {
30760
30761
30762
30763        var xDist, yDist, r, swipeAngle, _ = this;
30764
30765
30766
30767        xDist = _.touchObject.startX - _.touchObject.curX;
30768
30769        yDist = _.touchObject.startY - _.touchObject.curY;
30770
30771        r = Math.atan2(yDist, xDist);
30772
30773
30774
30775        swipeAngle = Math.round(r * 180 / Math.PI);
30776
30777        if (swipeAngle < 0) {
30778
30779            swipeAngle = 360 - Math.abs(swipeAngle);
30780
30781        }
30782
30783
30784
30785        if ((swipeAngle <= 45) && (swipeAngle >= 0)) {
30786
30787            return (_.options.rtl === false ? 'left' : 'right');
30788
30789        }
30790
30791        if ((swipeAngle <= 360) && (swipeAngle >= 315)) {
30792
30793            return (_.options.rtl === false ? 'left' : 'right');
30794
30795        }
30796
30797        if ((swipeAngle >= 135) && (swipeAngle <= 225)) {
30798
30799            return (_.options.rtl === false ? 'right' : 'left');
30800
30801        }
30802
30803        if (_.options.verticalSwiping === true) {
30804
30805            if ((swipeAngle >= 35) && (swipeAngle <= 135)) {
30806
30807                return 'down';
30808
30809            } else {
30810
30811                return 'up';
30812
30813            }
30814
30815        }
30816
30817
30818
30819        return 'vertical';
30820
30821
30822
30823    };
30824
30825
30826
30827    Slick.prototype.swipeEnd = function(event) {
30828
30829
30830
30831        var _ = this,
30832
30833            slideCount,
30834
30835            direction;
30836
30837
30838
30839        _.dragging = false;
30840
30841        _.swiping = false;
30842
30843
30844
30845        if (_.scrolling) {
30846
30847            _.scrolling = false;
30848
30849            return false;
30850
30851        }
30852
30853
30854
30855        _.interrupted = false;
30856
30857        _.shouldClick = ( _.touchObject.swipeLength > 10 ) ? false : true;
30858
30859
30860
30861        if ( _.touchObject.curX === undefined ) {
30862
30863            return false;
30864
30865        }
30866
30867
30868
30869        if ( _.touchObject.edgeHit === true ) {
30870
30871            _.$slider.trigger('edge', [_, _.swipeDirection() ]);
30872
30873        }
30874
30875
30876
30877        if ( _.touchObject.swipeLength >= _.touchObject.minSwipe ) {
30878
30879
30880
30881            direction = _.swipeDirection();
30882
30883
30884
30885            switch ( direction ) {
30886
30887
30888
30889                case 'left':
30890
30891                case 'down':
30892
30893
30894
30895                    slideCount =
30896
30897                        _.options.swipeToSlide ?
30898
30899                            _.checkNavigable( _.currentSlide + _.getSlideCount() ) :
30900
30901                            _.currentSlide + _.getSlideCount();
30902
30903
30904
30905                    _.currentDirection = 0;
30906
30907
30908
30909                    break;
30910
30911
30912
30913                case 'right':
30914
30915                case 'up':
30916
30917
30918
30919                    slideCount =
30920
30921                        _.options.swipeToSlide ?
30922
30923                            _.checkNavigable( _.currentSlide - _.getSlideCount() ) :
30924
30925                            _.currentSlide - _.getSlideCount();
30926
30927
30928
30929                    _.currentDirection = 1;
30930
30931
30932
30933                    break;
30934
30935
30936
30937                default:
30938
30939
30940
30941
30942
30943            }
30944
30945
30946
30947            if( direction != 'vertical' ) {
30948
30949
30950
30951                _.slideHandler( slideCount );
30952
30953                _.touchObject = {};
30954
30955                _.$slider.trigger('swipe', [_, direction ]);
30956
30957
30958
30959            }
30960
30961
30962
30963        } else {
30964
30965
30966
30967            if ( _.touchObject.startX !== _.touchObject.curX ) {
30968
30969
30970
30971                _.slideHandler( _.currentSlide );
30972
30973                _.touchObject = {};
30974
30975
30976
30977            }
30978
30979
30980
30981        }
30982
30983
30984
30985    };
30986
30987
30988
30989    Slick.prototype.swipeHandler = function(event) {
30990
30991
30992
30993        var _ = this;
30994
30995
30996
30997        if ((_.options.swipe === false) || ('ontouchend' in document && _.options.swipe === false)) {
30998
30999            return;
31000
31001        } else if (_.options.draggable === false && event.type.indexOf('mouse') !== -1) {
31002
31003            return;
31004
31005        }
31006
31007
31008
31009        _.touchObject.fingerCount = event.originalEvent && event.originalEvent.touches !== undefined ?
31010
31011            event.originalEvent.touches.length : 1;
31012
31013
31014
31015        _.touchObject.minSwipe = _.listWidth / _.options
31016
31017            .touchThreshold;
31018
31019
31020
31021        if (_.options.verticalSwiping === true) {
31022
31023            _.touchObject.minSwipe = _.listHeight / _.options
31024
31025                .touchThreshold;
31026
31027        }
31028
31029
31030
31031        switch (event.data.action) {
31032
31033
31034
31035            case 'start':
31036
31037                _.swipeStart(event);
31038
31039                break;
31040
31041
31042
31043            case 'move':
31044
31045                _.swipeMove(event);
31046
31047                break;
31048
31049
31050
31051            case 'end':
31052
31053                _.swipeEnd(event);
31054
31055                break;
31056
31057
31058
31059        }
31060
31061
31062
31063    };
31064
31065
31066
31067    Slick.prototype.swipeMove = function(event) {
31068
31069
31070
31071        var _ = this,
31072
31073            edgeWasHit = false,
31074
31075            curLeft, swipeDirection, swipeLength, positionOffset, touches, verticalSwipeLength;
31076
31077
31078
31079        touches = event.originalEvent !== undefined ? event.originalEvent.touches : null;
31080
31081
31082
31083        if (!_.dragging || _.scrolling || touches && touches.length !== 1) {
31084
31085            return false;
31086
31087        }
31088
31089
31090
31091        curLeft = _.getLeft(_.currentSlide);
31092
31093
31094
31095        _.touchObject.curX = touches !== undefined ? touches[0].pageX : event.clientX;
31096
31097        _.touchObject.curY = touches !== undefined ? touches[0].pageY : event.clientY;
31098
31099
31100
31101        _.touchObject.swipeLength = Math.round(Math.sqrt(
31102
31103            Math.pow(_.touchObject.curX - _.touchObject.startX, 2)));
31104
31105
31106
31107        verticalSwipeLength = Math.round(Math.sqrt(
31108
31109            Math.pow(_.touchObject.curY - _.touchObject.startY, 2)));
31110
31111
31112
31113        if (!_.options.verticalSwiping && !_.swiping && verticalSwipeLength > 4) {
31114
31115            _.scrolling = true;
31116
31117            return false;
31118
31119        }
31120
31121
31122
31123        if (_.options.verticalSwiping === true) {
31124
31125            _.touchObject.swipeLength = verticalSwipeLength;
31126
31127        }
31128
31129
31130
31131        swipeDirection = _.swipeDirection();
31132
31133
31134
31135        if (event.originalEvent !== undefined && _.touchObject.swipeLength > 4) {
31136
31137            _.swiping = true;
31138
31139            event.preventDefault();
31140
31141        }
31142
31143
31144
31145        positionOffset = (_.options.rtl === false ? 1 : -1) * (_.touchObject.curX > _.touchObject.startX ? 1 : -1);
31146
31147        if (_.options.verticalSwiping === true) {
31148
31149            positionOffset = _.touchObject.curY > _.touchObject.startY ? 1 : -1;
31150
31151        }
31152
31153
31154
31155
31156
31157        swipeLength = _.touchObject.swipeLength;
31158
31159
31160
31161        _.touchObject.edgeHit = false;
31162
31163
31164
31165        if (_.options.infinite === false) {
31166
31167            if ((_.currentSlide === 0 && swipeDirection === 'right') || (_.currentSlide >= _.getDotCount() && swipeDirection === 'left')) {
31168
31169                swipeLength = _.touchObject.swipeLength * _.options.edgeFriction;
31170
31171                _.touchObject.edgeHit = true;
31172
31173            }
31174
31175        }
31176
31177
31178
31179        if (_.options.vertical === false) {
31180
31181            _.swipeLeft = curLeft + swipeLength * positionOffset;
31182
31183        } else {
31184
31185            _.swipeLeft = curLeft + (swipeLength * (_.$list.height() / _.listWidth)) * positionOffset;
31186
31187        }
31188
31189        if (_.options.verticalSwiping === true) {
31190
31191            _.swipeLeft = curLeft + swipeLength * positionOffset;
31192
31193        }
31194
31195
31196
31197        if (_.options.fade === true || _.options.touchMove === false) {
31198
31199            return false;
31200
31201        }
31202
31203
31204
31205        if (_.animating === true) {
31206
31207            _.swipeLeft = null;
31208
31209            return false;
31210
31211        }
31212
31213
31214
31215        _.setCSS(_.swipeLeft);
31216
31217
31218
31219    };
31220
31221
31222
31223    Slick.prototype.swipeStart = function(event) {
31224
31225
31226
31227        var _ = this,
31228
31229            touches;
31230
31231
31232
31233        _.interrupted = true;
31234
31235
31236
31237        if (_.touchObject.fingerCount !== 1 || _.slideCount <= _.options.slidesToShow) {
31238
31239            _.touchObject = {};
31240
31241            return false;
31242
31243        }
31244
31245
31246
31247        if (event.originalEvent !== undefined && event.originalEvent.touches !== undefined) {
31248
31249            touches = event.originalEvent.touches[0];
31250
31251        }
31252
31253
31254
31255        _.touchObject.startX = _.touchObject.curX = touches !== undefined ? touches.pageX : event.clientX;
31256
31257        _.touchObject.startY = _.touchObject.curY = touches !== undefined ? touches.pageY : event.clientY;
31258
31259
31260
31261        _.dragging = true;
31262
31263
31264
31265    };
31266
31267
31268
31269    Slick.prototype.unfilterSlides = Slick.prototype.slickUnfilter = function() {
31270
31271
31272
31273        var _ = this;
31274
31275
31276
31277        if (_.$slidesCache !== null) {
31278
31279
31280
31281            _.unload();
31282
31283
31284
31285            _.$slideTrack.children(this.options.slide).detach();
31286
31287
31288
31289            _.$slidesCache.appendTo(_.$slideTrack);
31290
31291
31292
31293            _.reinit();
31294
31295
31296
31297        }
31298
31299
31300
31301    };
31302
31303
31304
31305    Slick.prototype.unload = function() {
31306
31307
31308
31309        var _ = this;
31310
31311
31312
31313        $('.slick-cloned', _.$slider).remove();
31314
31315
31316
31317        if (_.$dots) {
31318
31319            _.$dots.remove();
31320
31321        }
31322
31323
31324
31325        if (_.$prevArrow && _.htmlExpr.test(_.options.prevArrow)) {
31326
31327            _.$prevArrow.remove();
31328
31329        }
31330
31331
31332
31333        if (_.$nextArrow && _.htmlExpr.test(_.options.nextArrow)) {
31334
31335            _.$nextArrow.remove();
31336
31337        }
31338
31339
31340
31341        _.$slides
31342
31343            .removeClass('slick-slide slick-active slick-visible slick-current')
31344
31345            .attr('aria-hidden', 'true')
31346
31347            .css('width', '');
31348
31349
31350
31351    };
31352
31353
31354
31355    Slick.prototype.unslick = function(fromBreakpoint) {
31356
31357
31358
31359        var _ = this;
31360
31361        _.$slider.trigger('unslick', [_, fromBreakpoint]);
31362
31363        _.destroy();
31364
31365
31366
31367    };
31368
31369
31370
31371    Slick.prototype.updateArrows = function() {
31372
31373
31374
31375        var _ = this,
31376
31377            centerOffset;
31378
31379
31380
31381        centerOffset = Math.floor(_.options.slidesToShow / 2);
31382
31383
31384
31385        if ( _.options.arrows === true &&
31386
31387            _.slideCount > _.options.slidesToShow &&
31388
31389            !_.options.infinite ) {
31390
31391
31392
31393            _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
31394
31395            _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
31396
31397
31398
31399            if (_.currentSlide === 0) {
31400
31401
31402
31403                _.$prevArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
31404
31405                _.$nextArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
31406
31407
31408
31409            } else if (_.currentSlide >= _.slideCount - _.options.slidesToShow && _.options.centerMode === false) {
31410
31411
31412
31413                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
31414
31415                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
31416
31417
31418
31419            } else if (_.currentSlide >= _.slideCount - 1 && _.options.centerMode === true) {
31420
31421
31422
31423                _.$nextArrow.addClass('slick-disabled').attr('aria-disabled', 'true');
31424
31425                _.$prevArrow.removeClass('slick-disabled').attr('aria-disabled', 'false');
31426
31427
31428
31429            }
31430
31431
31432
31433        }
31434
31435
31436
31437    };
31438
31439
31440
31441    Slick.prototype.updateDots = function() {
31442
31443
31444
31445        var _ = this;
31446
31447
31448
31449        if (_.$dots !== null) {
31450
31451
31452
31453            _.$dots
31454
31455                .find('li')
31456
31457                    .removeClass('slick-active')
31458
31459                    .end();
31460
31461
31462
31463            _.$dots
31464
31465                .find('li')
31466
31467                .eq(Math.floor(_.currentSlide / _.options.slidesToScroll))
31468
31469                .addClass('slick-active');
31470
31471
31472
31473        }
31474
31475
31476
31477    };
31478
31479
31480
31481    Slick.prototype.visibility = function() {
31482
31483
31484
31485        var _ = this;
31486
31487
31488
31489        if ( _.options.autoplay ) {
31490
31491
31492
31493            if ( document[_.hidden] ) {
31494
31495
31496
31497                _.interrupted = true;
31498
31499
31500
31501            } else {
31502
31503
31504
31505                _.interrupted = false;
31506
31507
31508
31509            }
31510
31511
31512
31513        }
31514
31515
31516
31517    };
31518
31519
31520
31521    $.fn.slick = function() {
31522
31523        var _ = this,
31524
31525            opt = arguments[0],
31526
31527            args = Array.prototype.slice.call(arguments, 1),
31528
31529            l = _.length,
31530
31531            i,
31532
31533            ret;
31534
31535        for (i = 0; i < l; i++) {
31536
31537            if (typeof opt == 'object' || typeof opt == 'undefined')
31538
31539                _[i].slick = new Slick(_[i], opt);
31540
31541            else
31542
31543                ret = _[i].slick[opt].apply(_[i].slick, args);
31544
31545            if (typeof ret != 'undefined') return ret;
31546
31547        }
31548
31549        return _;
31550
31551    };
31552
31553
31554
31555}));
31556
31557
31558var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
31559
31560
31561
31562(function($) {
31563
31564	//responsive
31565
31566    var window_height = 0;
31567
31568    var window_width = 0;
31569
31570    var responsive_timeout = null;
31571
31572    var get_screen_size = function() {
31573
31574        var t = $("body").css("top");
31575
31576        if (t == "-2px") 
31577
31578            return "small";
31579
31580        else if (t == "-1px") 
31581
31582            return "medium";
31583
31584        else 
31585
31586            return "large";
31587
31588    };
31589
31590    
31591
31592    YHA.INIT_FUNC = YHA.INIT_FUNC || {};
31593
31594	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
31595
31596	YHA.RESPON_NO_DELAY_FUNC = YHA.RESPON_NO_DELAY_FUNC || {};
31597
31598    YHA.INIT_FUNC['default'] = {};
31599
31600	YHA.RESPON_FUNC['default'] = {};
31601
31602	YHA.RESPON_NO_DELAY_FUNC['default'] = {};
31603
31604    YHA.SCREEN_SIZE = get_screen_size();
31605
31606     
31607
31608	//INIT
31609
31610	YHA.INIT_FUNC['default']['search'] = function(){
31611
31612		var $top_menu = $("#top-menubar");
31613
31614		var $searchbar = $("#top-search");
31615
31616		if($searchbar.length){
31617
31618			$("#btn-searchbar").bind("click",function(){
31619
31620				var $btn = $(this);
31621
31622				if($btn.hasClass('active')){
31623
31624					$btn.removeClass('active');
31625
31626					$searchbar.removeClass("respon-show");
31627
31628				}else{
31629
31630					$("#top-control-bar .btn").removeClass('active');
31631
31632					$btn.addClass('active');
31633
31634					$searchbar.addClass("respon-show");
31635
31636					$top_menu.removeClass("respon-show");
31637
31638				}
31639
31640			});
31641
31642		} 
31643
31644	};    
31645
31646    
31647
31648	YHA.RESPON_NO_DELAY_FUNC['default']['topmenu'] = function() {        
31649
31650        var current_screen_size = YHA.SCREEN_SIZE;
31651
31652        YHA.SCREEN_SIZE = get_screen_size();
31653
31654        
31655
31656        if (current_screen_size !== YHA.SCREEN_SIZE) { 
31657
31658            // Screen size changed
31659
31660            if (YHA.SCREEN_SIZE === "large")
31661
31662                $("#menu-top .hover").removeClass("hover");
31663
31664            
31665
31666            if (YHA.SCREEN_SIZE === "medium" && current_screen_size === "large") {
31667
31668                $("#btn-menu").removeClass("active");
31669
31670                $("#top-menubar").removeClass("respon-show");
31671
31672            }
31673
31674        }
31675
31676    };
31677
31678    
31679
31680	YHA.INIT_FUNC['default']['topmenu'] = function() {
31681
31682		var $top_menu = $("#top-menubar");
31683
31684		var $searchbar = $("#top-search");
31685
31686		if($top_menu.length){
31687
31688			$("#btn-menu").bind("click",function(){
31689
31690				var $btn = $(this);
31691
31692				if($btn.hasClass('active')){
31693
31694					$btn.removeClass('active');
31695
31696					$top_menu.removeClass("respon-show");
31697
31698				}else{
31699
31700					$("#top-control-bar .btn").removeClass('active');
31701
31702					$btn.addClass('active');
31703
31704					$top_menu.addClass("respon-show");
31705
31706					$searchbar.removeClass("respon-show");
31707
31708				}
31709
31710			});
31711
31712			$("#menu-top >nav > ul >li").each(function(){
31713
31714				var $menu = $(this),
31715
31716                    $menus = $("#menu-top >nav >ul >li"),
31717
31718                    $btn = $('> a',$menu);
31719
31720				$btn.bind('click',function(e){
31721
31722					if (Modernizr.mq('(max-width: 980px)')) {
31723
31724						e.stopPropagation();
31725
31726						e.preventDefault();
31727
31728					}
31729
31730					if($menu.find(".submenu").length){
31731
31732						if($menu.hasClass('hover')){
31733
31734							$menus.removeClass('hover');
31735
31736						}else{
31737
31738							$menus.removeClass('hover');
31739
31740                            if (YHA.SCREEN_SIZE !== "large")
31741
31742                                $menu.addClass('hover');
31743
31744						}
31745
31746					}
31747
31748				});
31749
31750//				$btn.bind('mouseout',function(){
31751
31752//					$menu.removeClass('hover');
31753
31754//				});
31755
31756			});
31757
31758		}
31759
31760	};
31761
31762        
31763
31764	YHA.INIT_FUNC['default']['banner'] = function(){
31765
31766		var $banners = $('.banner');
31767
31768		var $slidershow = $('#home-slidershow');
31769
31770		if($banners.length){
31771
31772			var success = 0;
31773
31774    		var images = [];
31775
31776    		var length = $banners.length;
31777
31778 
31779
31780    		$banners.each(function(index){
31781
31782    			var $banner = $(this);
31783
31784    			var image = document.createElement('img');
31785
31786    			image.src = $banner.attr("yha-bg");
31787
31788    			$(image).load(function(){
31789
31790    				success++;
31791
31792    				images[index] = {
31793
31794    					width: this.naturalWidth,
31795
31796    					height: this.naturalHeight
31797
31798    				};
31799
31800    				$banner.css('backgroundImage','url('+this.src+')');
31801
31802    				if(success == length){
31803
31804    					// YHA.RESPON_FUNC['default'].slider = function(callback){
31805
31806    					// 	if($banners.length && $(window).width() > 1024){
31807
31808        	// 					var window_width = $(window).outerWidth(true);
31809
31810        	// 					var max_height = 0;
31811
31812        	// 					for(var i = 0; i < length; ++i){
31813
31814        	// 						var slide_height = images[i].height * window_width/images[i].width;
31815
31816        	// 						max_height = max_height < slide_height ? slide_height : max_height;
31817
31818        	// 					}
31819
31820        	// 					$('.banner').css({'height':max_height});
31821
31822    					// 	}else{
31823
31824    					// 		$('.banner').css({'height':'auto'});
31825
31826    					// 	}
31827
31828    					// };
31829
31830    					
31831
31832						if($slidershow.length){
31833
31834							if($slidershow.slick){      
31835
31836                                $slidershow.on('init', function(slick){
31837
31838                                    $slidershow.delay(500).fadeIn(1, function() {
31839
31840                                        $slidershow.addClass("slider_loaded");                                       
31841
31842                                    });
31843
31844                                });                          
31845
31846								var slider = $slidershow.slick({
31847
31848					    			dots: true,
31849
31850					    			infinite: true,
31851
31852					    			autoplay: true,
31853
31854					    			arrows: false,
31855
31856									pauseOnHover : false,
31857
31858									autoplaySpeed: 5000,
31859
31860									customPaging: function(slider, i) {
31861
31862					                    return '<a class="btn font-rs" data-role="none" role="button" tabindex="0">0' + (i + 1) + '</a>';
31863
31864					                },
31865
31866					                responsive: [
31867
31868					                	{
31869
31870					                		breakpoint: 540,
31871
31872										    settings: {
31873
31874										        dots: false,
31875
31876										    }
31877
31878					                	}
31879
31880					                ]
31881
31882					    		});
31883
31884								$('#slidershow-wrapper .btn-play-pause').click(function() {
31885
31886									console.log($(this).attr('data-status'));
31887
31888									if($(this).attr('data-status') == 'playing') {
31889
31890										console.log('pausing');
31891
31892										$slidershow.slick('slickPause');
31893
31894										$(this).attr('data-status', 'paused');
31895
31896									} else {
31897
31898										console.log('playing');
31899
31900										$slidershow.slick('slickPlay');
31901
31902										$(this).attr('data-status', 'playing');
31903
31904									}
31905
31906								});
31907
31908                                /*
31909
31910                                console.log($slidershow);
31911
31912					    		$slidershow.on('init',function(slick){                       
31913
31914                                    alert("init2");
31915
31916                                    $slidershow.css({opacity: 1});
31917
31918	        		 				//YHA.RESPON_FUNC['default'].slider();
31919
31920	        		 			});
31921
31922                                */
31923
31924				        	}
31925
31926						}else{
31927
31928    						// YHA.RESPON_FUNC['default'].slider();
31929
31930    					}
31931
31932    				}
31933
31934    			});
31935
31936    		});
31937
31938		}
31939
31940	};
31941
31942	
31943
31944	
31945
31946	YHA.INIT_FUNC['default']['langs_switcher'] = function(){
31947
31948		var $switcher = $('#font-size-switcher');
31949
31950		if($switcher.length){
31951
31952			YHA.common.fontSize = Cookies.get('font-size')?Cookies.get('font-size'):'font-m';
31953
31954			fontSizeSwitch(YHA.common.fontSize);
31955
31956			$('.btn',$switcher).bind('click',function(){
31957
31958				var $btn = $(this);
31959
31960				var key = $btn.parent().attr('id');
31961
31962				if(!$btn.hasClass('active')){
31963
31964					$('.btn',$switcher).removeClass('active');
31965
31966					fontSizeSwitch(key);
31967
31968				}
31969
31970				return false;
31971
31972			});
31973
31974		}
31975
31976		function fontSizeSwitch(key){
31977
31978			var class_name = 'page-'+key;
31979
31980			Cookies.set('font-size', key, { expires: 365 });
31981
31982			$('body').attr('class',function(){
31983
31984				var className = $(this).attr("class");
31985
31986                if(/page-font-[a-zA-Z0-9_-]*/.test(className)) {
31987
31988                    className = className.replace(/page-font-[a-zA-Z0-9_-]*/, class_name);
31989
31990                }else{
31991
31992                    className += " "+class_name;
31993
31994                }
31995
31996                return className;
31997
31998			});
31999
32000			$('#'+key+' .btn').addClass('active');
32001
32002			YHA.common.fontSize = key;
32003
32004		}
32005
32006	};
32007
32008	
32009
32010	YHA.INIT_FUNC['default']['back-to-top'] = function(){
32011
32012		var $btn = $('#btn-scrolltop');
32013
32014		if($btn.length){
32015
32016			$btn.bind('click',function(){
32017
32018				$("html, body").animate({scrollTop: 0}, 1000);
32019
32020			});
32021
32022		}
32023
32024	};
32025
32026	
32027
32028	YHA.INIT_FUNC['default']['slidershow'] = function(){
32029
32030		var $sliershows = $('.slidershow');
32031
32032		if($sliershows.length){
32033
32034			$sliershows.slick({
32035
32036				autoplay: true,
32037
32038				autoplaySpeed: 5000,
32039
32040    			dots: true,
32041
32042    			infinite: true,
32043
32044    			arrows: false,
32045
32046    		});
32047
32048		}
32049
32050	};
32051
32052
32053
32054	
32055
32056	YHA.INIT_FUNC['default']['map'] = function(){
32057
32058		var $maps = $('.acf-map');
32059
32060		var maps = [];
32061
32062		if($maps.length){
32063
32064	   
32065
32066	       /*
32067
32068			*  new_map
32069
32070			*
32071
32072			*  This function will render a Google Map onto the selected jQuery element
32073
32074			*
32075
32076			*  @type	function
32077
32078			*  @date	8/11/2013
32079
32080			*  @since	4.3.0
32081
32082			*
32083
32084			*  @param	$el (jQuery element)
32085
32086			*  @return	n/a
32087
32088			*/
32089
32090			function new_map( $el ) {
32091
32092				// var
32093
32094				var $markers = $el.find('.marker');
32095
32096				// vars
32097
32098				var args = {
32099
32100					zoom		: 16,
32101
32102					center		: new google.maps.LatLng(0, 0),
32103
32104					mapTypeId	: google.maps.MapTypeId.ROADMAP
32105
32106				};
32107
32108				// create map	        	
32109
32110				var map = new google.maps.Map( $el[0], args);
32111
32112				// add a markers reference
32113
32114				map.markers = [];
32115
32116	
32117
32118				// add markers
32119
32120				$markers.each(function(){
32121
32122					
32123
32124			    	add_marker( $(this), map );
32125
32126					
32127
32128				});
32129
32130				// center map
32131
32132				center_map( map );
32133
32134				// return
32135
32136				return map;
32137
32138				
32139
32140			}
32141
32142			
32143
32144			/*
32145
32146			*  add_marker
32147
32148			*
32149
32150			*  This function will add a marker to the selected Google Map
32151
32152			*
32153
32154			*  @type	function
32155
32156			*  @date	8/11/2013
32157
32158			*  @since	4.3.0
32159
32160			*
32161
32162			*  @param	$marker (jQuery element)
32163
32164			*  @param	map (Google Map object)
32165
32166			*  @return	n/a
32167
32168			*/
32169
32170			
32171
32172			function add_marker( $marker, map ) {
32173
32174			
32175
32176				// var
32177
32178				var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );
32179
32180			
32181
32182				// create marker
32183
32184				var marker = new google.maps.Marker({
32185
32186					position	: latlng,
32187
32188					map			: map
32189
32190				});
32191
32192			
32193
32194				// add to array
32195
32196				map.markers.push( marker );
32197
32198			
32199
32200				// if marker contains HTML, add it to an infoWindow
32201
32202				if( $marker.html() )
32203
32204				{
32205
32206					// create info window
32207
32208					var infowindow = new google.maps.InfoWindow({
32209
32210						content		: $marker.html()
32211
32212					});
32213
32214			
32215
32216					// show info window when marker is clicked
32217
32218					google.maps.event.addListener(marker, 'click', function() {
32219
32220			
32221
32222						infowindow.open( map, marker );
32223
32224			
32225
32226					});
32227
32228				}
32229
32230			}
32231
32232			
32233
32234			/*
32235
32236			*  center_map
32237
32238			*
32239
32240			*  This function will center the map, showing all markers attached to this map
32241
32242			*
32243
32244			*  @type	function
32245
32246			*  @date	8/11/2013
32247
32248			*  @since	4.3.0
32249
32250			*
32251
32252			*  @param	map (Google Map object)
32253
32254			*  @return	n/a
32255
32256			*/
32257
32258			
32259
32260			function center_map( map ) {
32261
32262				// vars
32263
32264				var bounds = new google.maps.LatLngBounds();
32265
32266			
32267
32268				// loop through all markers and create bounds
32269
32270				$.each( map.markers, function( i, marker ){
32271
32272					var latlng = new google.maps.LatLng( marker.position.lat(), marker.position.lng() );
32273
32274					bounds.extend( latlng );
32275
32276				});
32277
32278			
32279
32280				// only 1 marker?
32281
32282				if( map.markers.length == 1 )
32283
32284				{
32285
32286					// set center of map
32287
32288				    map.setCenter( bounds.getCenter() );
32289
32290				    map.setZoom( 16 );
32291
32292				}
32293
32294				else
32295
32296				{
32297
32298					// fit to bounds
32299
32300					map.fitBounds( bounds );
32301
32302				}
32303
32304			}
32305
32306			
32307
32308			$('.acf-map').each(function(index){
32309
32310				var $map = $(this);
32311
32312				var toggled = false;
32313
32314				var $tab = $map.parents('[role=tabpanel]').eq(0);
32315
32316				if($tab.length && !$tab.hasClass('active')){
32317
32318					var id = $tab.attr('id');
32319
32320					$("#"+id).on('toggled', function (event, tab) {
32321
32322						if(!toggled){
32323
32324							initMap();
32325
32326							toggled = true;
32327
32328						}
32329
32330					});
32331
32332				}else{
32333
32334					initMap();
32335
32336					toggled = true;
32337
32338				}
32339
32340				function initMap(){
32341
32342					maps[index] = new_map($map);
32343
32344				};
32345
32346			});
32347
32348			YHA.RESPON_FUNC['default']['map'] = function(){
32349
32350				var length = maps.length;
32351
32352				for(var i=0; i < length; ++i){
32353
32354					if(maps[i]){
32355
32356						google.maps.event.trigger(maps[i], 'resize');
32357
32358					}
32359
32360				}
32361
32362			};
32363
32364		}
32365
32366	};
32367
32368		
32369
32370	YHA.INIT_FUNC['default']['fieldset'] = function(){
32371
32372		var $fieldsets = $('fieldset');
32373
32374		if($fieldsets.length){
32375
32376			$fieldsets.each(function(){
32377
32378				var $fieldset = $(this);
32379
32380				var $tab = $fieldset.parents('[role=tabpanel]').eq(0);
32381
32382				var toggled = false;
32383
32384				$('legend',$fieldset).bind("click",function(){
32385
32386                    if ($fieldset.hasClass("opened")) 
32387
32388                        $fieldset.removeClass("opened").find(".fieldset-content").stop(true,false).slideUp(300);
32389
32390                    else 
32391
32392                        $fieldset.addClass("opened").find(".fieldset-content").stop(true,fal
32392se).slideDown(300);                    
32393
32394				});
32395
32396			});
32397
32398			
32399
32400		}
32401
32402	};
32403
32404	
32405
32406	YHA.INIT_FUNC['default']['fieldset-list'] = function(){
32407
32408		var $fieldset_lists = $('.fieldset-list');
32409
32410		if($fieldset_lists.length){
32411
32412			$fieldset_lists.each(function(){
32413
32414				var $fieldset_list = $(this);
32415
32416				$('fieldset',$fieldset_list).each(function(index){
32417
32418					var $legend = $("legend",this);
32419
32420					var text = $legend.text();
32421
32422                    
32423
32424                    if ($fieldset_list.hasClass("wo-num")) 
32425
32426                        $legend.html(text+'<i class="fa"></i>');
32427
32428                    else
32429
32430                        $legend.html('<span>'+(index+1)+'</span>'+text+'<i class="fa"></i>');
32431
32432				});
32433
32434			});
32435
32436			
32437
32438		}
32439
32440	};
32441
32442	
32443
32444	YHA.INIT_FUNC['default']['tab-selecter'] = function(){
32445
32446		var $tab_selecters = $('.tabs-selecter');
32447
32448		if($tab_selecters.length){
32449
32450			$tab_selecters.each(function(){
32451
32452				var $tabs = $('.tabs',this);
32453
32454				var $selecter = $('select',this);
32455
32456				if($("[role=tabpanel].active",$tab_selecters).length){
32457
32458					var id = $("[role=tabpanel].active",$tab_selecters).attr('id');
32459
32460					if($selecter.val() != id){
32461
32462						$selecter.val(id);
32463
32464					}
32465
32466				}
32467
32468				$("[role=tabpanel]",$tab_selecters).on('toggled', function (event, tab) {
32469
32470					var id = $(this).attr('id');
32471
32472					if($selecter.val() != id){
32473
32474						$selecter.val(id);
32475
32476					}
32477
32478				});
32479
32480				
32481
32482				$selecter.bind('change',function(){
32483
32484					var value = $(this).val();
32485
32486					var $tab = $('[role=tab][href=#'+value+']');
32487
32488					$tab.click();
32489
32490				});
32491
32492			});
32493
32494		}
32495
32496	};
32497
32498	
32499
32500	YHA.INIT_FUNC['default']['slidebar-icon-link'] = function(){
32501
32502		var $slidebar_icons = $(".slidebar-icon[href]");
32503
32504		if($slidebar_icons.length){
32505
32506			$slidebar_icons.each(function(){
32507
32508				var $btn = $(this);
32509
32510				var id = $btn.attr('href');
32511
32512				$btn.bind("click",function(){
32513
32514					$('[role=tab][href='+id+']').click();
32515
32516					return false;
32517
32518				});
32519
32520			});
32521
32522		}
32523
32524	};
32525
32526	    
32527
32528	YHA.INIT_FUNC['default']['highlighted-articles'] = function(){
32529
32530		$('.masonryAreaWrapper').masonry({
32531
32532		  itemSelector: '.article',
32533
32534		  percentPosition: true
32535
32536		});
32537
32538	};
32539
32540    
32541
32542	$( document ).ready(function() {
32543
32544		NProgress.configure({ parent: 'header' });
32545
32546		NProgress.start();
32547
32548		$(document).foundation();
32549
32550		$(document).waitForImages(function() {
32551
32552			for (var selector in YHA.INIT_FUNC) {
32553
32554				if(YHA.INIT_FUNC[selector] && (selector == 'default' || $(selector).length)){
32555
32556					for(var fun_key in YHA.INIT_FUNC[selector]){
32557
32558						if ( typeof YHA.INIT_FUNC[selector][fun_key] === 'function') {
32559
32560							YHA.INIT_FUNC[selector][fun_key].call(this);
32561
32562						}
32563
32564					}
32565
32566				}
32567
32568			}
32569
32570		    setTimeout(function(){
32571
32572		    	NProgress.done();
32573
32574				// $('#nprogress').removeAttr();
32575
32576		    	$('header').append('<div id="nprogress"><div class="bar"></div></div>');
32577
32578				// console.log('test4');
32579
32580		    },500);
32581
32582		});
32583
32584        
32585
32586        var fbShare = function(url, winWidth, winHeight) {
32587
32588            var winTop = (screen.height / 2) - (winHeight / 2);
32589
32590            var winLeft = (screen.width / 2) - (winWidth / 2);
32591
32592            //window.open('http://www.facebook.com/sharer.php?s=100&p[title]=' + title + '&p[summary]=' + descr + '&p[url]=' + url + '&p[images][0]=' + image, 'sharer', 'top=' + winTop + ',left=' + winLeft + ',toolbar=0,status=0,width=' + winWidth + ',height=' + winHeight);
32593
32594            window.open("https://www.facebook.com/dialog/share?app_id=1661737634114011&display=popup&href=" + url, '_blank', 'top=' + winTop + ',left=' + winLeft + ',toolbar=0,status=0,width=' + winWidth + ',height=' + winHeight);
32595
32596        };
32597
32598        
32599
32600        $("#sharefb").on("click", function(e) {
32601
32602            e.preventDefault();
32603
32604            //window.open("http://www.facebook.com/sharer/sharer.php?u=" + window.url + "", "_blank");
32605
32606            
32607
32608            fbShare(window.url, 520,350);
32609
32610            
32611
32612            /*
32613
32614            FB.ui({
32615
32616                method: 'share',
32617
32618                href: window.url,
32619
32620              }, function(response){
32621
32622                  console.log(response);
32623
32624                  
32625
32626              });
32627
32628              */
32629
32630        });        
32631
32632	});
32633
32634	YHA.INIT_FUNC['default']['announcement'] = function(){
32635
32636		$('#announcements .announcement .close').click(function() {
32637
32638			Cookies.set('announcement_' + $(this).parents('.announcement').attr('data-id') + '_closed', true);
32639
32640		});
32641
32642	};
32643
32644	$(window).resize(function() {
32645
32646        if (responsive_timeout) {
32647
32648            clearTimeout(responsive_timeout);
32649
32650            responsive_timeout = null;
32651
32652        }
32653
32654        responsive_timeout = setTimeout(function() {
32655
32656            if (window_width !== $(window).width() || window_height !== $(window).height()) {
32657
32658                window_width = $(window).width();
32659
32660                window_height = $(window).height();
32661
32662                for (var selector in YHA.RESPON_FUNC) {
32663
32664					if(YHA.RESPON_FUNC[selector] && (selector == 'default' || $(selector).length)){
32665
32666						for(var fun_key in YHA.RESPON_FUNC[selector]){
32667
32668							if ( typeof YHA.RESPON_FUNC[selector][fun_key] === 'function') {
32669
32670								YHA.RESPON_FUNC[selector][fun_key].call(this);
32671
32672							}
32673
32674						}
32675
32676					}
32677
32678				}
32679
32680            }
32681
32682        }, 1000);
32683
32684        
32685
32686        for (var selector in YHA.RESPON_NO_DELAY_FUNC) {
32687
32688            if(YHA.RESPON_NO_DELAY_FUNC[selector] && (selector == 'default' || $(selector).length)){
32689
32690                for(var fun_key in YHA.RESPON_NO_DELAY_FUNC[selector]){
32691
32692                    if ( typeof YHA.RESPON_NO_DELAY_FUNC[selector][fun_key] === 'function') {
32693
32694                        YHA.RESPON_NO_DELAY_FUNC[selector][fun_key].call(this);
32695
32696                    }
32697
32698                }
32699
32700            }
32701
32702        }
32703
32704    });
32705
32706})(jQuery);
32707var YHA = YHA || {};
32708
32709
32710
32711(function($) {
32712
32713	var body_selector = ".page-gallery-detail",
32714
32715		$body_selector = $(body_selector),
32716
32717		$masonry = $body_selector.find(".masonryAreaWrapper"),
32718
32719		$loadMore = $body_selector.find(".loadWrapper .btn");
32720
32721
32722
32723	var page = 1, count = 4;
32724
32725	//INIT
32726
32727	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
32728
32729	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
32730
32731	YHA.INIT_FUNC[body_selector] = {};
32732
32733	YHA.RESPON_FUNC[body_selector] = {};
32734
32735
32736
32737	function initPopup() {
32738
32739		$masonry.magnificPopup({
32740
32741			delegate: 'div > a',
32742
32743			type: 'inline',
32744
32745			mainClass: 'mfp-img-mobile',
32746
32747			showCloseBtn: false,
32748
32749			gallery: {
32750
32751				enabled: true, // set to true to enable gallery
32752
32753				navigateByImgClick: true,
32754
32755				arrowMarkup: '', // markup of an arrow button
32756
32757			},
32758
32759			image: {
32760
32761				tError: '<a href="%url%">The image #%curr%</a> could not be loaded.',
32762
32763				titleSrc: function(item) {
32764
32765					return item.el.attr('title') + '<small>by Marsel Van Oosten</small>';
32766
32767				}
32768
32769			}
32770
32771		})
32772
32773	}
32774
32775
32776
32777	function refreshPopup() {
32778
32779		$masonry.off('click.magnificpopup');
32780
32781		$masonry.removeData('magnificPopup');
32782
32783		initPopup();
32784
32785	}
32786
32787	//INIT
32788
32789	YHA.INIT_FUNC[body_selector]['init'] = function(){
32790
32791		initPopup();
32792
32793		$loadMore.on("click", function(e)	{
32794
32795			e.preventDefault();
32796
32797			var $hiddenArticles = $masonry.find('.hidden-article').slice(0, count);
32798
32799			if($hiddenArticles.length > 0) {
32800
32801				$hiddenArticles.each(function(index, item){
32802
32803					var newBlock = $(item);
32804
32805					newBlock.removeClass('hidden-article').addClass('article');
32806
32807					//$masonry.find('.article').last().after(newBlock);
32808
32809					$masonry.masonry("appended", newBlock);
32810
32811					newBlock.find('img').load(function() {
32812
32813						$masonry.masonry('layout');
32814
32815					});
32816
32817					//$(item).remove();
32818
32819				});
32820
32821				$masonry.masonry('layout');
32822
32823				//refreshPopup();
32824
32825			}
32826
32827
32828
32829			if($hiddenArticles.length == 0 || $hiddenArticles.length < count) {
32830
32831				$(this).hide();
32832
32833			}
32834
32835		});
32836
32837		$body_selector.find('.arrow-left').click(function(){
32838
32839			$.magnificPopup.instance.prev();
32840
32841		});
32842
32843		$body_selector.find('.arrow-right').click(function(){
32844
32845			$.magnificPopup.instance.next();
32846
32847		});
32848
32849	};
32850
32851
32852
32853
32854
32855})(jQuery);
32856var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
32857
32858
32859
32860(function($) {
32861
32862    var body_selector = ".page-hostel-booking-enquiry";
32863
32864    var loading = false,
32865
32866        $submitBtn = $("#btn-enter"),
32867
32868        txt1 = $submitBtn.html(),
32869
32870        txt2 = $submitBtn.attr("data-txt");
32871
32872    function updateBookingSummary(booking_data) {
32873
32874		console.log('updateBookingSummary 11111')
32875
32876        var $bookin_summary = $('#booking-summary');
32877
32878        $bookin_summary.find('.summary-hostel-name').text(booking_data['hostel_name']);
32879
32880        $bookin_summary.find('.summary-room-title').text(booking_data['room_type']);
32881
32882        $bookin_summary.find('.summary-rate-title').text(booking_data['rate_plan_name']);
32883
32884        $bookin_summary.find('.summary-checkin').text(moment(booking_data['checkin']).format('dddd, MMM DD, YYYY'));
32885
32886        $bookin_summary.find('.summary-checkout').text(moment(booking_data['checkout']).format('dddd, MMM DD, YYYY'));
32887
32888        $bookin_summary.find('.summary-rooms').text(booking_data['rooms']);
32889
32890        $bookin_summary.find('.summary-guests').text(booking_data['guests']);
32891
32892        $bookin_summary.find('.summary-nights').text(booking_data['nights']);
32893
32894        $bookin_summary.find('.summary-ref-id').text(booking_data['ref_id']);
32895
32896        $bookin_summary.find('.summary-total-price').text(booking_data['amount']);
32897
32898        $bookin_summary.find('.summary-guest').text(booking_data['guest_name']);
32899
32900        console.log(booking_data['hostel_rules_and_regulations']);
32901
32902        $('#hostel-rules').attr('src', booking_data['hostel_rules_and_regulations']);
32903
32904        $(document).foundation();
32905
32906    }
32907
32908    //INIT
32909
32910    YHA.INIT_FUNC = YHA.INIT_FUNC || {};
32911
32912    YHA.INIT_FUNC[body_selector] = {};
32913
32914
32915
32916    YHA.INIT_FUNC[body_selector]['init'] = function(){
32917
32918        if(window.booking_summary && window.booking_enquiry_ref_id) {
32919
32920            $('#summary-section').show();
32921
32922            updateBookingSummary(window.booking_summary);
32923
32924        } else {
32925
32926            $('#form-section').show();
32927
32928        }
32929
32930        $submitBtn.click(function() {
32931
32932            if(!loading) {
32933
32934                loading = true;
32935
32936                $submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
32937
32938                var $enquiryForm = $('#enquiry-form');
32939
32940                $enquiryForm.ajaxSubmit({
32941
32942                    url : YHA.common.base_url + "/api/hostel/enquiry_form_login",
32943
32944                    success: function(response) {
32945
32946                        loading = false;
32947
32948                        $submitBtn.html(txt1);
32949
32950                        if(response.status) {
32951
32952                            $('#form-section').hide();
32953
32954                            $('#summary-section').show();
32955
32956                            updateBookingSummary(response['booking']);
32957
32958                            // redirectToPaymentGateway(response);
32959
32960                        } else {
32961
32962                            var errorData = response.errors;
32963
32964                            var allError = "";
32965
32966                            for(var i in errorData) {
32967
32968                                allError = errorData[0]['msg']+'<br>';
32969
32970                                break;
32971
32972                            }
32973
32974                            YHA.common.popupError(allError);
32975
32976                        }
32977
32978                    },
32979
32980                    error: function() {
32981
32982                        loading = false;
32983
32984                        $submitBtn.html(txt1);
32985
32986                        YHA.common.popupError('Network error');
32987
32988                    }
32989
32990                });
32991
32992            }
32993
32994        });
32995
32996        var $requestSubmitBtn = $('#btn-request-submit');
32997
32998        var originalText = $requestSubmitBtn.html();
32999
33000        $requestSubmitBtn.click(function()
33001
33002        {
33003
33004            if(!loading) {
33005
33006                var content = $("#request-content").val();
33007
33008                var enquiry = $( "#request-type option:selected" ).text();
33009
33010                loading = true;
33011
33012                $requestSubmitBtn.html(txt2);
33013
33014                $.post(YHA.common.base_url + "/api/hostel/enquiry_form",
33015
33016                    {
33017
33018                        'content' : content,
33019
33020                        'enquiry' : enquiry,
33021
33022                        'ref_id' : window.booking_enquiry_ref_id?window.booking_enquiry_ref_id:$('#order-confirmation-number').val()
33023
33024                    },(function(response)
33025
33026                    {
33027
33028                        $requestSubmitBtn.html(originalText);
33029
33030                        loading = false;
33031
33032                        if(response.status)
33033
33034                        {
33035
33036                            YHA.common.popupError(response.msg);
33037
33038                        }else
33039
33040                        {
33041
33042                            var allError ="";
33043
33044                            var errorData = response.errors;
33045
33046                            for(var i in errorData){
33047
33048                                allError = errorData[0]['msg']+'<br>';
33049
33050                                break;
33051
33052                            }
33053
33054                            YHA.common.popupError(allError);
33055
33056                        }
33057
33058
33059
33060                    }), 'json');
33061
33062            }
33063
33064        });
33065
33066        $('#btn-reset').click(function() {
33067
33068            $('#enquiry-form')[0].reset();
33069
33070        });
33071
33072        $('.btn-download').click(function() {
33073
33074            if($('#download-form').val()) {
33075
33076                window.open($('#download-form').val());
33077
33078            }
33079
33080        });
33081
33082        $('.btn-send').click(function() {
33083
33084            // var $this = $(this);
33085
33086            $.post(YHA.common.base_url + "/api/hostel/resendConfirmationEmail", { 'email' : $('#email-address').val(), 'ref_id' : window.booking_enquiry_ref_id?window.booking_enquiry_ref_id:$('#order-confirmation-number').val() }, function(response) {
33087
33088                if(response.status) {
33089
33090                    YHA.common.popupError(response.message);
33091
33092                } else {
33093
33094                    var errorData = response.errors;
33095
33096                    var allError = "";
33097
33098                    for (var i in errorData) {
33099
33100                        allError = errorData[0]['msg'] + '<br>';
33101
33102                        break;
33103
33104                    }
33105
33106                    YHA.common.popupError(allError);
33107
33108                }
33109
33110            });
33111
33112        });
33113
33114    };
33115
33116})(jQuery);
33117var YHA = YHA || {INIT_FUNC: {}, RESPON_FUNC: {}};
33118
33119
33120
33121(function ($) {
33122
33123    var body_selector = ".page-hostel-booking-detail";
33124
33125    var loading = false,
33126
33127        $submitBtn = $("#btn-continuous"),
33128
33129        txt1 = $submitBtn.html(),
33130
33131        txt2 = $submitBtn.attr("data-txt");
33132
33133
33134
33135    var guest_number_index = 0;
33136
33137    var roomData = [];
33138
33139    var searchingData = {
33140
33141        'hostel_id': $('#hostel-id').val()
33142
33143    };
33144
33145
33146
33147    var lang = 'en';
33148
33149    var booking_lang = 'eng';
33150
33151    var booking_date_error_msg = '';
33152
33153    var booking_guest_error_msg = '';
33154
33155    var booking_rooms_error_msg = '';
33156
33157    switch (YHA.common.lang) {
33158
33159        case 'zh':
33160
33161            lang = 'zh-TW';
33162
33163            break;
33164
33165        case 'sc':
33166
33167            lang = 'zh-CN';
33168
33169            break;
33170
33171        default:
33172
33173            lang = 'en';
33174
33175    }
33176
33177    moment.locale(lang);
33178
33179
33180
33181    function redirectToPaymentGateway(response) {
33182
33183        window.onbeforeunload = null;
33184
33185        var hiddenForm = response.html;
33186
33187        $('#form-section').hide();
33188
33189        $('#payment-processing').show();
33190
33191        window.scrollTo(0, 0);
33192
33193        $(body_selector + ' .hidden-section').html(hiddenForm);
33194
33195    }
33196
33197
33198
33199    function numberWithCommas(price) {
33200
33201        return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
33202
33203    }
33204
33205
33206
33207    function setSearchingData(key, value) {
33208
33209        searchingData[key] = value;
33210
33211    }
33212
33213
33214
33215    function showDetailPopup() {
33216
33217        $('.see-details').magnificPopup({
33218
33219            type: 'ajax',
33220
33221            alignTop: true,
33222
33223            overflowY: 'scroll' // as we know that popup content is tall we set scroll overflow by default to avoid jump
33224
33225        });
33226
33227    }
33228
33229
33230
33231    function insertGuestInfoTemplate(guest_number) {
33232
33233        var $html_template = $('#html-template');
33234
33235        var $guestinfo_template = $html_template.find('#template-guest-info').html();
33236
33237        $guestinfo_template = $guestinfo_template.replace(/{{guest_number}}/g, guest_number);
33238
33239        $('#guest-list').append('<li class="guest-info">' + $guestinfo_template + '</li>');
33240
33241    }
33242
33243
33244
33245    function getAvaiableRooms() {
33246
33247        // var hostel_id = $('#hostel-id').val();
33248
33249        // console.log(searchingData);
33250
33251        $('#room-type-list').empty();
33252
33253        $('.loading-layer').css({'display': 'table'});
33254
33255        $.get(YHA.common.base_url + '/api/hostel/searchRooms/', searchingData, function (response) {
33256
33257            $('.loading-layer').hide();
33258
33259            if (response.data && response.data.length > 0) {
33260
33261                updateSearchResult(response.data);
33262
33263            } else {
33264
33265                $('#room-type-list').html('<span class="error">' + response.message + '</span>');
33266
33267            }
33268
33269        });
33270
33271    }
33272
33273
33274
33275    function showSection(page) {
33276
33277        if (page === '') {
33278
33279            return;
33280
33281        }
33282
33283        $('.contentWrapper').fadeOut();
33284
33285        switch (page) {
33286
33287            case 'room-search' :
33288
33289                $('#room-search-section').show();
33290
33291                break;
33292
33293            case 'form' :
33294
33295                $('#form-section').show();
33296
33297                break;
33298
33299        }
33300
33301        $('html, body').animate({'scrollTop': $('#breadcrumb-section').offset().top}, 0);
33302
33303    }
33304
33305
33306
33307    function sortSearchResult(data) {
33308
33309        var sorting_key = $('select[name="sort-by"]').val();
33310
33311        var result = data;
33312
33313        switch (sorting_key) {
33314
33315            case "room-rate-per-night":
33316
33317                result = data.sort(function (a, b) {
33318
33319                    return a.lowest_price_non_formatted - b.lowest_price_non_formatted;
33320
33321                });
33322
33323                break;
33324
33325            case "room-left":
33326
33327                result = data.sort(function (a, b) {
33328
33329                    return b.rooms - a.rooms;
33330
33331                });
33332
33333                break;
33334
33335            default:
33336
33337                result = data.sort(function (a, b) {
33338
33339                    return a.lowest_price_non_formatted - b.lowest_price_non_formatted;
33340
33341                });
33342
33343        }
33344
33345
33346
33347        var sold_out_list = [];
33348
33349        for (var i = 0; i < result.length; i++) {
33350
33351            if (result[i]['rooms'] == 0) {
33352
33353                sold_out_list.push(result[i]);
33354
33355                result.splice(i, 1);
33356
33357            }
33358
33359        }
33360
33361        console.log('Sorting');
33362
33363        // console.log(sold_out_list);
33364
33365        return result.concat(sold_out_list);
33366
33367    }
33368
33369
33370
33371    function updateSearchResult(data) {
33372
33373        roomData = data;
33374
33375        sortSearchResult(data);
33376
33377        var $room_type_template = $('#template-room-type .room-type').clone();
33378
33379        var $room_type_list = $('#room-type-list');
33380
33381        $room_type_list.empty();
33382
33383        // console.log(data.length);
33384
33385        for (var i = 0; i < data.length; i++) {
33386
33387            var newRoom = $room_type_template.clone();
33388
33389            newRoom.find('.title').html(data[i]['title']);
33390
33391            newRoom.find('.description').html(data[i]['description']);
33392
33393            newRoom.find('.rooms-left').html(data[i]['room_left']);
33394
33395            newRoom.find('.price-wrap .lowest-price-by-room-type').html(data[i]['lowest_price']);
33396
33397            newRoom.find('.feature-image').html('<img src="' + data[i]['featured_image'] + '" />');
33398
33399            newRoom.find('.see-details').attr('data-gallery', JSON.stringify(data[i]['gallery']));
33400
33401            newRoom.find('.see-details').attr('data-facilities', JSON.stringify(data[i]['facilities']));
33402
33403            newRoom.find('.type-text').text(data[i]['type_text']);
33404
33405            var $room_select = newRoom.find('select.rooms-select');
33406
33407            $room_select.append('<option>' + data[i]['type_text'] + '</option>');
33408
33409            for (var j = 1; j <= Math.min(data[i]['rooms'], 8); j++) {
33410
33411                if (j < data[i]['booking_quantity']) {
33412
33413                    $room_select.append('<option data-status="disabled" value="' + j + '">' + j + '</option>');
33414
33415                } else {
33416
33417                    $room_select.append('<option value="' + j + '">' + j + '</option>');
33418
33419                }
33420
33421            }
33422
33423            newRoom.attr('data-is-room', data[i]['is_room']);
33424
33425            newRoom.attr('data-booking-quantity', data[i]['booking_quantity']);
33426
33427            if (data[i]['rooms'] == 0) {
33428
33429                newRoom.find('.price-wrap').remove();
33430
33431                newRoom.find('.btn-reserve').remove();
33432
33433            }
33434
33435            var $room_rate_template = newRoom.find('.room-rate:first-child').clone();
33436
33437            newRoom.find('.room-rates').empty();
33438
33439            for (var rate_plan_id in data[i]['rate_plans']) {
33440
33441                var room_rate = data[i]['rate_plans'][rate_plan_id];
33442
33443                var newRate = $room_rate_template.clone();
33444
33445                newRate.find('.price').html(room_rate['average_price']);
33446
33447                newRate.find('.price').attr('data-total', room_rate['total_price']);
33448
33449                newRate.find('.type-text').text(data[i]['type_text']);
33450
33451                newRate.attr('data-hash', room_rate['hash']);
33452
33453                newRate.attr('data-type', room_rate['type']);
33454
33455
33456
33457                var type_of_room_rate = newRate.attr('data-type');
33458
33459                var select_type = $('input[name="room-rate"]:checked').val();
33460
33461                if (select_type !== undefined && type_of_room_rate != select_type) {
33462
33463                    console.log('Adding Hide');
33464
33465                    newRate.addClass('hide');
33466
33467                }
33468
33469
33470
33471                newRate.find('.room-rate-title').html(room_rate['title']);
33472
33473                if (room_rate['features']) {
33474
33475                    newRate.find('.room-features').empty();
33476
33477                    for (var j = 0; j < room_rate['features'].length; j++) {
33478
33479                        var $html = '<li class="room-feature" style=" background: url(' + room_rate['features'][j]['icon'] + ') no-repeat center left; background-size:20px 20px; ">' + room_rate['features'][j]['description'] + '</li>';
33480
33481                        newRate.find('.room-features').append($html);
33482
33483                    }
33484
33485                }
33486
33487                // newRate.find('.room-feature-wifi').html(room_rate['wifi']);
33488
33489                // newRate.find('.room-feature-breakfast').html(room_rate['breakfast']);
33490
33491                // newRate.find('.room-feature-beverage').html(room_rate['beverage']);
33492
33493                newRoom.find('.room-rates').append(newRate);
33494
33495            }
33496
33497            $room_type_list.append(newRoom);
33498
33499        }
33500
33501    }
33502
33503
33504
33505    function showPoup(msg) {
33506
33507        $.magnificPopup.open({
33508
33509            items: {
33510
33511                src: '<div class="error-popup popup-content">' +
33512
33513                '<div class="table error-content">' +
33514
33515                '<div class="table-cell">' +
33516
33517                msg +
33518
33519                '</div>' +
33520
33521                '</div>' +
33522
33523                '<div class="btn btn-cricle btn-close" onclick="$.magnificPopup.close();">' +
33524
33525                '<div class="table">' +
33526
33527                '<div class="table-cell">' +
33528
33529                'OK' +
33530
33531                '</div>' +
33532
33533                '</div>' +
33534
33535                '</div>' +
33536
33537                '</div>',
33538
33539                type: 'inline'
33540
33541            },
33542
33543            fixedContentPos: true,
33544
33545            callbacks: {
33546
33547                close: function () {
33548
33549                    // window.location.replace(YHA.common.base_url);
33550
33551                }
33552
33553            }
33554
33555        });
33556
33557    }
33558
33559
33560
33561    function updateBookingSummary($room_type, $room_rate) {
33562
33563		console.log('updateBookingSummary 22222')
33564
33565        var $bookin_summary = $('#booking-summary');
33566
33567        $bookin_summary.find('.summary-room-title').text($room_type.find('.title').text());
33568
33569        $bookin_summary.find('.summary-rate-title').text($room_rate.find('.room-rate-title').text());
33570
33571        $bookin_summary.find('.summary-checkin').text(moment(searchingData['checkin']).format('dddd, MMM DD, YYYY'));
33572
33573        $bookin_summary.find('.summary-checkout').text(moment(searchingData['checkout']).format('dddd, MMM DD, YYYY'));
33574
33575        $bookin_summary.find('.summary-rooms').text(searchingData['rooms']);
33576
33577        $bookin_summary.find('.summary-guests').text(searchingData['guests']);
33578
33579        $bookin_summary.find('.summary-nights').text(moment(searchingData['checkout']).diff(moment(searchingData['checkin']), 'days'));
33580
33581        var price = $room_rate.find('.price').attr('data-total') * searchingData['rooms'];
33582
33583		var formatted_price = numberWithCommas(price);
33584
33585        $bookin_summary.find('#total-price .price').text(formatted_price);
33586
33587        $bookin_summary.find('#total-price .price').attr('data-price', price);
33588
33589        var total_guest = searchingData['guests'];
33590
33591		guest_number_index = total_guest;
33592		
33593        if ($('#guest-list').is(':empty')) {
33594
33595            insertGuestInfoTemplate(1);
33596
33597            // for(var i = 0; i < total_guest; i++) {
33598
33599            //     insertGuestInfoTemplate(i+1);
33600
33601            // }
33602
33603		}
33604		
33605		//Check Member Title
33606
33607		// Fix the check logic 20250526 //
33608
33609		//if ($room_rate.find('.room-rate-title').text() == 'Member Rate' || $room_rate.find('.room-rate-title').text() == '會員價格' || $room_rate.find('.room-rate-title').text() == '会员价格')
33610		//{
33611
33612		const rateTitle = $room_rate.find('.room-rate-title').text().toLowerCase(); 
33613 
33614		if (rateTitle.includes('non member rate') || 
33615		    rateTitle.includes('非會員價') || 
33616		    rateTitle.includes('非会员价')) 
33617		{
33618			$('#yha-member-1-of-guest-1').attr('disabled', 'disabled');
33619			$('#yha-member-2-of-guest-1').attr('checked', 'checked');
33620		}
33621		else if (rateTitle.includes('member rate') || 
33622		    rateTitle.includes('會員價') || 
33623		    rateTitle.includes('会员价'))
33624		{
33625			$('#yha-member-1-of-guest-1').attr('checked', 'checked');
33626			$('#yha-member-2-of-guest-1').attr('disabled', 'disabled');
33627		}
33628
33629		// End -Fix the check logic 20250526 //
33630
33631        // $bookin_summary.find('').moment(searchingData['checkout']).diff(moment(searchingData['checkin']), 'days')
33632
33633    }
33634
33635
33636
33637    function initSeeDetailPopup() {
33638
33639        var toggled = false;
33640
33641        var $sliershow_for = $('#slidershow-for');
33642
33643        var $sliershow_nav = $('#slidershow-nav');
33644
33645        var slider_for = null;
33646
33647        var slider_nav = null;
33648
33649        if ($sliershow_for.length
33650
33651            && $sliershow_nav.length) {
33652
33653            slider_for = $sliershow_for.slick({
33654
33655                slidesToShow: 1,
33656
33657                slidesToScroll: 1,
33658
33659                fade: true,
33660
33661                asNavFor: '#slidershow-nav',
33662
33663                // adaptiveHeight: true,
33664
33665                responsive: [
33666
33667                    {
33668
33669                        breakpoint: 768,
33670
33671                        settings: {
33672
33673                            arrows: true,
33674
33675                            fade: false,
33676
33677                        }
33678
33679                    }
33680
33681                ]
33682
33683            });
33684
33685            slider_nav = $sliershow_nav.slick({
33686
33687                arrows: false,
33688
33689                slidesToShow: 4,
33690
33691                slidesToScroll: 1,
33692
33693                asNavFor: '#slidershow-for',
33694
33695                focusOnSelect: true
33696
33697            });
33698
33699            slider_nav.on('afterChange', function (event, slick, currentSlide, nextSlide) {
33700
33701                $('#slide-count .current-number').html(currentSlide + 1);
33702
33703            });
33704
33705            $("#general").unbind('toggled').on('toggled', function (event, tab) {
33706
33707                if (!toggled) {
33708
33709                    slider_for.slick('setPosition');
33710
33711                    slider_nav.slick('setPosition');
33712
33713                    toggled = true;
33714
33715                }
33716
33717            });
33718
33719        }
33720
33721    }
33722
33723
33724
33725    function destroySeeDetailPopup() {
33726
33727        $('#slidershow-for').slick('unslick');
33728
33729        $('#slidershow-nav').slick('unslick');
33730
33731    }
33732
33733
33734
33735    function updatePriceByCoupon(coupon) {
33736
33737        if (coupon.type === 'amount') {
33738
33739            $('#total-price .price').text(numberWithCommas(Math.max(0, parseInt($('#total-price .price').attr('data-price')) - coupon.discount)));
33740
33741            $('.promotion-name').text(coupon.name);
33742
33743        } else if (coupon.type === 'percentage') {
33744
33745            $('#total-price .price').text(numberWithCommas(parseFloat(($('#total-price .price').attr('data-price')) * (1 - coupon.discount / 100)).toFixed(2)));
33746
33747            $('.promotion-name').text(coupon.name);
33748
33749        } else {
33750
33751            $('#total-price .price').text(numberWithCommas($('#total-price .price').attr('data-price')));
33752
33753            $('.promotion-name').text('');
33754
33755        }
33756
33757    }
33758
33759
33760
33761    function applyPromotionCode(promotion_code) {
33762
33763        $('.loading-layer').css({'display': 'table'});
33764
33765        $.get(YHA.common.base_url + '/api/hostel/checkCoupon/', {
33766
33767            'code': promotion_code,
33768
33769						'hash': searchingData['hash'],
33770						
33771						'checkin': $('input[name=checkin]').val(),
33772
33773            'checkout': $('input[name=checkout]').val(),
33774
33775        }, function (response) {
33776
33777            $('.loading-layer').hide();
33778
33779            if (response.status) {
33780
33781                updatePriceByCoupon(response.coupon);
33782
33783            } else {
33784
33785                showPoup(response.error);
33786
33787            }
33788
33789        });
33790
33791    }
33792
33793
33794
33795    function initPage() {
33796
33797        showSection('room-search');
33798
33799        // showSection('form');
33800
33801        setSearchingData('checkin', $('input[name="checkin"]').val());
33802
33803        setSearchingData('checkout', $('input[name="checkout"]').val());
33804
33805        setSearchingData('rooms', 0);
33806
33807        setSearchingData('guests', 1);
33808
33809        getAvaiableRooms();
33810
33811        // $('.search-bar .btn-search').click();
33812
33813    }
33814
33815
33816
33817    function switchRatePlan($room_type, $room_rate) {
33818
33819        updateBookingSummary($room_type, $room_rate);
33820
33821        setSearchingData('hash', $room_rate.attr('data-hash'));
33822
33823    }
33824
33825
33826
33827    function switchRatePlanByType(type) {
33828
33829        console.log("switchRatePlanByType");
33830
33831        var $room_type = $('.room-rate[data-status="selected"]').parents('.room
33831-type');
33832
33833        var $room_rate = $room_type.find('.room-rate[data-type="' + type + '"]');
33834
33835
33836
33837        console.log($($room_rate[$room_rate.length-1]));
33838
33839
33840
33841        if ($room_rate[0]) {
33842
33843            console.log("yes yes");
33844
33845			console.log($room_type)
33846			console.log($room_rate)
33847
33848            //switchRatePlan($room_type, $room_rate);
33849
33850            // switchRatePlan($room_type, $($room_rate[$room_rate.length-1]));//2018-07-12 Samson-find the last one since client will add more than one type of member price.
33851            switchRatePlan($room_type, $($room_rate[0]));//上面果個係咪傻架?
33852
33853            if ($('#promotion-code').val() !== '') {
33854
33855                applyPromotionCode($('#promotion-code').val());
33856
33857            }
33858
33859        }
33860
33861    }
33862
33863
33864
33865    //INIT
33866
33867    YHA.INIT_FUNC = YHA.INIT_FUNC || {};
33868
33869    YHA.INIT_FUNC[body_selector] = {};
33870
33871
33872
33873    YHA.INIT_FUNC[body_selector]['init'] = function () {
33874
33875        switch (YHA.common.lang) {
33876
33877            case 'zh':
33878
33879                lang = 'zh-TW';
33880
33881                booking_lang = 'cht';
33882
33883                booking_date_error_msg = '最多可選' + maxConsecutiveNights ? maxConsecutiveNights : 14 + '晚';
33884
33885                booking_guest_error_msg = '請選擇旅客人數';
33886
33887                booking_rooms_error_msg = '請選擇數目';
33888
33889                booking_rooms_error_msg_2 = '你所選擇之旅客人數已超過房間/床位/露營的可入住數量';
33890
33891                break;
33892
33893            case 'sc':
33894
33895                lang = 'zh-CN';
33896
33897                booking_lang = 'chs';
33898
33899                booking_date_error_msg = '最多可选' + maxConsecutiveNights ? maxConsecutiveNights : 14 + '晚';
33900
33901                booking_guest_error_msg = '请选择旅客人数';
33902
33903                booking_rooms_error_msg = '请选择数目';
33904
33905                booking_rooms_error_msg_2 = '你所选择之旅客人数已超过房间/床位/露营的可入住数量';
33906
33907                break;
33908
33909            default:
33910
33911                lang = 'en';
33912
33913                booking_lang = 'eng';
33914
33915                booking_date_error_msg = 'Maximum reservation period is ' + maxConsecutiveNights ? maxConsecutiveNights : 14 + ' nights';
33916
33917                booking_guest_error_msg = 'Please select no. of guests';
33918
33919                booking_rooms_error_msg = 'Please select no. of Rooms/Dorms/Tents';
33920
33921                booking_rooms_error_msg_2 = 'The number of guests exceeding the maximum accommodation quantity of the Room/Dorm Bed/Tent.';
33922
33923        }
33924
33925        $(document).on('click', '.see-details', function () {
33926
33927            var $room_type = $(this).parents('.room-type');
33928
33929            var room_title = $room_type.find('.title').html();
33930
33931            var room_description = $room_type.find('.description').html();
33932
33933            var gallery = JSON.parse($(this).attr('data-gallery'));
33934
33935            var facilities = JSON.parse($(this).attr('data-facilities'));
33936
33937            $.magnificPopup.open({
33938
33939                items: {
33940
33941                    src: '#popup-see-details',
33942
33943                    type: 'inline'
33944
33945                },
33946
33947                fixedContentPos: true,
33948
33949                modal: false,
33950
33951                callbacks: {
33952
33953                    beforeOpen: function () {
33954
33955                        var $popup = this;
33956
33957                        // $.get(window.base_url + '/api/hostel/test', function(response) {
33958
33959                        var $popupContent = $popup.contentContainer;
33960
33961                        $('#popup-see-details').find('.room-detail .room-title').html(room_title);
33962
33963                        $('#popup-see-details').find('.room-detail .room-description').html(room_description);
33964
33965                        $('#slidershow-for').empty();
33966
33967                        $('#slidershow-nav').empty();
33968
33969                        for (var i = 0; i < gallery.length; i++) {
33970
33971                            var html = '<li>' +
33972
33973                                '<div class="item-img">' +
33974
33975                                '<img src="' + gallery[i]['url'] + '" title="' + gallery[i]['title'] + '" alt="' + gallery[i]['alt'] + '"/>' +
33976
33977                                '</div>' +
33978
33979                                '</li>';
33980
33981                            $('#slidershow-for').append(html);
33982
33983                            $('#slidershow-nav').append(html);
33984
33985                        }
33986
33987                        $('#popup-see-details .facilities').empty();
33988
33989                        for (var i = 0; i < facilities.length; i++) {
33990
33991                            var html = '<li class="facility">' +
33992
33993                                '<i class="fa fa-check">' + facilities[i] + '</i></li>';
33994
33995                            $('#popup-see-details .facilities').append(html);
33996
33997                        }
33998
33999                        $('#popup-see-details').find('.total-number').html(gallery.length);
34000
34001                        // });
34002
34003                    },
34004
34005                    open: function () {
34006
34007                        initSeeDetailPopup();
34008
34009                        $(window).trigger('resize');
34010
34011                    },
34012
34013                    close: function () {
34014
34015                        destroySeeDetailPopup();
34016
34017                    }
34018
34019                }
34020
34021            });
34022
34023        });
34024
34025
34026
34027        // implementation of disabled form fields
34028
34029        var $homeBookingBar = $('.search-bar');
34030
34031        // var nowTemp = new Date();
34032
34033        // var now = new Date(nowTemp.getFullYear(), nowTemp.getMonth(), nowTemp.getDate(), 0, 0, 0, 0);
34034
34035        // var initialCheckIn = moment().format('YYYY-MM-DD');
34036
34037
34038
34039        var checkin = $homeBookingBar.find('input[name=checkin]').fdatepicker({
34040
34041            format: 'yyyy-mm-dd',
34042
34043            language: lang,
34044
34045            onRender: function (date) {
34046
34047                return date.valueOf() < moment().startOf('day').valueOf() ? 'disabled' : '';
34048
34049            }
34050
34051        }).on('changeDate', function (ev) {
34052
34053            if (ev.date.valueOf() >= checkout.date.valueOf()) {
34054
34055                var newDate = new Date(ev.date);
34056
34057                newDate.setDate(newDate.getDate() + 1);
34058
34059                checkout.update(newDate);
34060
34061            }
34062
34063            checkin.hide();
34064
34065            // setSearchingData('checkin', moment(ev.date).format('YYYY-MM-DD'));
34066
34067            $homeBookingBar.find('input[name=checkout]')[0].focus();
34068
34069        }).data('datepicker');
34070
34071        // var today = new Date();
34072
34073        // console.log(today);
34074
34075        // console.log(today.setDate(today.getDate() + 1));
34076
34077        // var initialCheckOut = moment(new Date()).add(1,'days').format('YYYY-MM-DD');
34078
34079        //
34080
34081        var checkout = $homeBookingBar.find('input[name=checkout]').fdatepicker({
34082
34083            // initialDate: initialCheckOut,
34084
34085            format: 'yyyy-mm-dd',
34086
34087            language: lang,
34088
34089            onRender: function (date) {
34090
34091                return (date.valueOf() <= checkin.date.valueOf() || date.valueOf() - checkin.date.valueOf() > +maxConsecutiveNights * 24 * 60 * 60 * 1000) ? 'disabled' : '';
34092
34093            }
34094
34095        }).on('changeDate', function (ev) {
34096
34097            checkout.hide();
34098
34099            // setSearchingData('checkout', moment(ev.date).format('YYYY-MM-DD'));
34100
34101        }).data('datepicker');
34102
34103        $homeBookingBar.find('.icon-calendar').click(function () {
34104
34105            if ($(this).attr('data-input-target') == 'checkin') {
34106
34107                checkin.show();
34108
34109                checkout.hide();
34110
34111            } else {
34112
34113                checkin.hide();
34114
34115                checkout.show();
34116
34117            }
34118
34119        });
34120
34121        if (inputCheckIn && inputCheckOut) {
34122
34123            var initialCheckIn = moment(inputCheckIn).format('YYYY-MM-DD');
34124
34125            var initialCheckOut = moment(inputCheckOut).format('YYYY-MM-DD');
34126
34127        } else {
34128
34129            var initialCheckIn = moment().format('YYYY-MM-DD');
34130
34131            var initialCheckOut = moment(new Date()).add(1, 'days').format('YYYY-MM-DD');
34132
34133        }
34134
34135        // console.log(initialCheckOut);
34136
34137        checkin.update(initialCheckIn);
34138
34139        checkout.update(initialCheckOut);
34140
34141        setSearchingData('checkin', initialCheckIn);
34142
34143        setSearchingData('checkout', initialCheckOut);
34144
34145        $('.search-bar .btn-search').click(function () {
34146
34147            setSearchingData('checkin', $('input[name="checkin"]').val());
34148
34149            setSearchingData('checkout', $('input[name="checkout"]').val());
34150
34151            setSearchingData('rooms', Math.max($('select[name="rooms"] option:selected').val(), 0));
34152
34153            var no_of_guests = $('select[name="guests"] option:selected').val();
34154
34155            if (no_of_guests >= 1) {
34156
34157                setSearchingData('guests', no_of_guests);
34158
34159                getAvaiableRooms()
34160
34161            } else {
34162
34163                YHA.common.popupError(booking_guest_error_msg);
34164
34165            }
34166
34167        });
34168
34169        $(document).on('click', '.btn-book', function () {
34170
34171            var rooms = $(this).siblings('select[name="rooms"]').val();
34172
34173            var room_select_status = $(this).siblings('select[name="rooms"]').find('option:selected').attr('data-status');
34174
34175            if (room_select_status !== 'disabled') {
34176
34177                if (rooms > 0) {
34178
34179                    var $room_type = $(this).parents('.room-type');
34180
34181                    var $room_rate = $(this).parents('.room-rate');
34182
34183                    $room_rate.attr('data-status', 'selected');
34184
34185                    setSearchingData('rooms', rooms);
34186
34187                    switchRatePlan($room_type, $room_rate);
34188
34189                    if (!$('#form-section').is(':visible')) {
34190
34191                        showSection('form');
34192
34193                    }
34194
34195                } else {
34196
34197                    YHA.common.popupError(booking_rooms_error_msg);
34198
34199                }
34200
34201            } else {
34202
34203                YHA.common.popupError(booking_rooms_error_msg_2);
34204
34205            }
34206
34207        });
34208
34209        $('.field-filter').change(function () {
34210
34211            var $box = $(this);
34212
34213            if ($box.is(":checked")) {
34214
34215                // the name of the box is retrieved using the .attr() method
34216
34217                // as it is assumed and expected to be immutable
34218
34219                var group = "input:checkbox[name='" + $box.attr("name") + "']";
34220
34221                // the checked state of the group/box on the other hand will change
34222
34223                // and the current value is retrieved using .prop() method
34224
34225                $(group).prop("checked", false);
34226
34227                $box.prop("checked", true);
34228
34229            } else {
34230
34231                $box.prop("checked", false);
34232
34233            }
34234
34235            if ($box.prop('checked')) {
34236
34237                setSearchingData($(this).attr('name'), $(this).val());
34238
34239            } else {
34240
34241                setSearchingData($(this).attr('name'), '');
34242
34243            }
34244
34245            if ($(this).attr('name') === 'room-rate') {
34246
34247                if ($box.prop('checked')) {
34248
34249                    $('#room-type-list .room-rate').each(function () {
34250
34251                        if ($(this).attr('data-type') != $('input[name="room-rate"]:checked').val()) {
34252
34253                            $(this).addClass('hide');
34254
34255                        } else {
34256
34257                            $(this).removeClass('hide');
34258
34259                        }
34260
34261                    });
34262
34263                } else {
34264
34265                    $('.room-rate').each(function () {
34266
34267                        $(this).removeClass('hide');
34268
34269                    });
34270
34271                }
34272
34273
34274
34275            } else {
34276
34277                getAvaiableRooms();
34278
34279            }
34280
34281        });
34282
34283        $(document).on('change', '.rooms-select', function () {
34284
34285            var room_select_status = $(this).find('option:selected').attr('data-status');
34286
34287            console.log(room_select_status);
34288
34289            if (room_select_status === 'disabled') {
34290
34291                YHA.common.popupError(booking_rooms_error_msg_2);
34292
34293            }
34294
34295        });
34296
34297        $(document).on('change', '.field-member', function () {
34298
34299
34300
34301            /*2018-07-06 Samson- if賽馬會摩星嶺青年旅舍 808,白普理賽馬會青年旅舍 816,昂坪戴維斯青年旅舍 831, disable switchRatePlanByType function  */
34302
34303            if (($('#hostel-id').val() != '808') && ($('#hostel-id').val() != '816') && ($('#hostel-id').val() != '831')) {
34304
34305                console.log('clicking');
34306
34307                var is_member = false;
34308
34309                $('#guest-list .guest-info').each(function (index) {
34310
34311                    if ($('#yha-member-1-of-guest-' + (index + 1)).is(':checked') || $('#apply-on-site-of-guest-' + (index + 1)).is(':checked')) {
34312
34313                        is_member = true;
34314
34315                        return false;
34316
34317                    }
34318
34319                });
34320
34321                if (is_member) {
34322
34323					console.log('is member');
34324                    switchRatePlanByType('member');
34325
34326                } else {
34327					console.log('non member');
34328                    switchRatePlanByType('non_member');
34329
34330                }
34331
34332                if ($(this).attr('type') === 'radio') {
34333
34334                    if ($(this).val() == '1') {
34335
34336                        $(this).parents('.guest-info').find('.field-apply-on-site').attr('disabled', true).prop('checked', false);
34337
34338                    } else {
34339
34340                        $(this).parents('.guest-info').find('.field-apply-on-site').attr('disabled', false);
34341
34342                        // $(this).parents('.guest-info').find('.field-apply-on-site').attr('checked', false);
34343
34344                    }
34345
34346                }
34347
34348            }
34349
34350        });
34351
34352        $('select[name="sort-by"]').change(function () {
34353
34354            sortSearchResult(roomData);
34355
34356        });
34357
34358        $(document).on('click', '.btn-reserve', function () {
34359
34360            var $roomType = $(this).parents('.room-type');
34361
34362            if ($roomType.find('.room-rates').is(":hidden")) {
34363
34364                $roomType.find('.room-rates').slideDown();
34365
34366            } else {
34367
34368                $roomType.find('.room-rates').slideUp();
34369
34370            }
34371
34372        });
34373
34374        $('.mobile-sidebar-menu li').click(function (e) {
34375
34376            $('.mobile-sidebar-menu li').removeClass('active');
34377
34378            $(this).addClass('active');
34379
34380            var index = $(this).index();
34381
34382            $('.slidebar-boxes').removeClass('active');
34383
34384            $('.slidebar-boxes').eq(index).addClass('active');
34385
34386        });
34387
34388        initPage();
34389
34390    };
34391
34392    YHA.INIT_FUNC[body_selector]['form'] = function () {
34393
34394        $('input[data-target-input]').change(function () {
34395
34396            var targetInput = $(this).attr('data-target-input');
34397
34398            if ($(this).is(':checked')) {
34399
34400                $(targetInput).attr('disabled', false).focus();
34401
34402            } else {
34403
34404                $(targetInput).attr('disabled', true);
34405
34406            }
34407
34408        });
34409
34410        $('#btn-back').click(function () {
34411
34412            showSection('room-search');
34413
34414        });
34415
34416        $(document).on('change', '.age-selector', function () {
34417
34418            console.log($(this).val());
34419
34420            if ($(this).val() == 'child') {
34421
34422                YHA.common.popupError($(this).attr('data-notice'));
34423
34424            }
34425
34426        });
34427
34428        $submitBtn.click(function () {
34429
34430            if (!loading) {
34431
34432                loading = true;
34433
34434                $submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
34435
34436                var $bookingForm = $('#booking-form');
34437
34438                var postData = searchingData;
34439
34440                postData['promotion_code'] = $('#promotion-code').val();
34441
34442                $bookingForm.ajaxSubmit({
34443
34444                    url: YHA.common.base_url + "/api/hostel/submit_form",
34445
34446                    data: postData,
34447
34448                    success: function (response) {
34449
34450                        loading = false;
34451
34452                        $submitBtn.html(txt1);
34453
34454                        if (response.status) {
34455
34456                            redirectToPaymentGateway(response);
34457
34458                        } else {
34459
34460                            var errorData = response.errors;
34461
34462                            var allError = "";
34463
34464                            for (var i in errorData) {
34465
34466                                allError = errorData[0]['msg'] + '<br>';
34467
34468                                break;
34469
34470                            }
34471
34472                            YHA.common.popupError(allError);
34473
34474                        }
34475
34476                    },
34477
34478                    error: function () {
34479
34480                        loading = false;
34481
34482                        $submitBtn.html(txt1);
34483
34484                        YHA.common.popupError('Network error');
34485
34486                    }
34487
34488                });
34489
34490            }
34491
34492        });
34493
34494        $('.btn-add-guest').click(function (e) {
34495
34496            var $room_type = $('.room-rate[data-status="selected"]').parents('.room-type');
34497
34498            var $room_rate = $room_type.find('.room-rate[data-type="member"]');
34499
34500            switchRatePlan($room_type, $room_rate);
34501
34502            e.preventDefault();
34503
34504            e.stopPropagation();
34505
34506            // var total_guest = searchingData['guests'];
34507
34508            // if(guest_number_index >= total_guest) {
34509
34510            //     return;
34511
34512            // }
34513
34514            // insertGuestInfoTemplate(guest_number_index++);
34515
34516        });
34517
34518        $('#promotion-code').blur(function () {
34519
34520            if ($(this).val() === '') {
34521
34522                $('#total-price .price').text($('#total-price .price').attr('data-price'));
34523
34524                $('.promotion-name').text('');
34525
34526            } else {
34527
34528                applyPromotionCode($(this).val());
34529
34530            }
34531
34532        });
34533
34534        window.onbeforeunload = function () {
34535
34536            return "Are you sure you want to navigate away?";
34537
34538        }
34539
34540    };
34541
34542})(jQuery);
34543var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
34544
34545
34546
34547(function($) {
34548
34549	var body_selector = ".page-hostel-rating-detail";
34550
34551	var loading = false;
34552
34553
34554
34555	function showPoup(msg) {
34556
34557		$.magnificPopup.open({
34558
34559			items: {
34560
34561				src: '<div class="error-popup popup-content">' +
34562
34563						'<div class="table error-content">' +
34564
34565							'<div class="table-cell">' +
34566
34567								msg +
34568
34569							'</div>' +
34570
34571						'</div>' +
34572
34573						'<div class="btn btn-cricle btn-close" onclick="$.magnificPopup.close();">' +
34574
34575							'<div class="table">' +
34576
34577								'<div class="table-cell">' +
34578
34579									'OK' +
34580
34581								'</div>' +
34582
34583							'</div>' +
34584
34585						'</div>' +
34586
34587					'</div>',
34588
34589				type: 'inline'
34590
34591			},
34592
34593			fixedContentPos: true,
34594
34595			callbacks: {
34596
34597				close: function() {
34598
34599					window.location.replace(YHA.common.base_url);
34600
34601				}
34602
34603			}
34604
34605		});
34606
34607	}
34608
34609	//INIT
34610
34611	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
34612
34613	YHA.INIT_FUNC[body_selector] = {};
34614
34615
34616
34617	YHA.INIT_FUNC[body_selector]['init'] = function(){
34618
34619		var $ratingForm = $('#review-form');
34620
34621		$ratingForm.find('.btn-reset').click(function() {
34622
34623			$ratingForm.find('.rating-option ul li a').each(function(){
34624
34625				$(this).removeClass('active');
34626
34627				$(this).parents('.rating-option').find('input[type=hidden]').val('');
34628
34629			});
34630
34631		});
34632
34633		$ratingForm.find('.rating-option ul li a').click(function() {
34634
34635			$(this).parent().siblings().find('a').removeClass('active');
34636
34637			$(this).addClass('active');
34638
34639			$(this).parents('.rating-option').find('input[type=hidden]').val($(this).attr('data-value'));
34640
34641		});
34642
34643		$ratingForm.find('.btn-submit').click(function() {
34644
34645			if(!loading) {
34646
34647				var $submitBtn = $(this);
34648
34649				var original_text = $submitBtn.val();
34650
34651				$submitBtn.val($submitBtn.attr('data-loading-text'));
34652
34653				loading = true;
34654
34655				$ratingForm.ajaxSubmit({
34656
34657					url : YHA.common.base_url + "/api/review/submit_form",
34658
34659					success: function(response) {
34660
34661						loading = false;
34662
34663						$submitBtn.val(original_text);
34664
34665						if(response.status) {
34666
34667							showPoup(response.msg);
34668
34669						} else {
34670
34671							var errorData = response.errors;
34672
34673							var allError = "";
34674
34675							for(var i in errorData)
34676
34677							{
34678
34679								allError = errorData[0]['msg']+'<br>';
34680
34681								break;
34682
34683							}
34684
34685							YHA.common.popupError(allError);
34686
34687						}
34688
34689					}
34690
34691				});
34692
34693			}
34694
34695		});
34696
34697	};
34698
34699	
34700
34701})(jQuery);
34702var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
34703
34704
34705
34706(function($) {
34707
34708	var body_selector = ".page-hostel-detail",
34709
34710		$body_selector = $(body_selector),
34711
34712        $no_record = $body_selector.find(".no_record"),
34713
34714        $loadMore = $body_selector.find(".loadWrapper .btn"),
34715
34716        txt1 = $loadMore.text(),
34717
34718        txt2 = $loadMore.attr("data-txt"),
34719
34720        loading = false,
34721
34722        xhr;        
34723
34724        
34725
34726	var page = 1, count = 5;    
34727
34728        
34729
34730	//INIT
34731
34732	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
34733
34734	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
34735
34736	YHA.INIT_FUNC[body_selector] = {};
34737
34738	YHA.RESPON_FUNC[body_selector] = {};
34739
34740
34741
34742
34743
34744	function getComments(hostel_id) {
34745
34746        loading = true;
34747
34748
34749
34750        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
34751
34752        
34753
34754		xhr = $.ajax({
34755
34756			url: YHA.common.base_url + "/api/review/get_reviews_by_hostel_id/",
34757
34758			method: "GET",
34759
34760			dataType: "json",
34761
34762			data: {
34763
34764				'hostel_id' : hostel_id,
34765
34766				'page' : page?page:1,
34767
34768				'count' : count?count:10
34769
34770			},
34771
34772			success:function(response){
34773
34774                $loadMore.text(txt1);
34775
34776                loading = false;
34777
34778                xhr = (function() {return;})();    
34779
34780                
34781
34782				if(response.status == true)	{
34783
34784					if(response.comments.length <= 0 || response.comments < count)	
34785
34786                        $loadMore.hide();                    
34787
34788                    else {
34789
34790						var $commentContainer = $('#hostel-comments');
34791
34792						var commentHtml = '';
34793
34794
34795
34796						$.each(response.comments, function()	{
34797
34798							commentHtml = $commentContainer.find('ul > li:first-child').clone();
34799
34800							commentHtml.find('.comment .rating').html('<span>' + this.rating + '%</span>').addClass(this.rating>50?'rate-smile':'rate-sad');
34801
34802							commentHtml.find('.comment .author').text(this.name);
34803
34804							commentHtml.find('.comment .date').text(this.comment_date);
34805
34806							commentHtml.find('.comment .content').html(this.content);
34807
34808							if(this.reply) {
34809
34810                                commentHtml.find('.reply .content').html(this.reply);
34811
34812							} else {
34813
34814                                commentHtml.find('.reply').remove();
34815
34816							}
34817
34818                            $commentContainer.find('ul').append(commentHtml);
34819
34820						})
34821
34822					}                       
34823
34824				}
34825
34826			}
34827
34828		});
34829
34830	}
34831
34832
34833
34834	function loadMore(hostel_id) {
34835
34836		page++;
34837
34838		getComments(hostel_id);
34839
34840	}
34841
34842
34843
34844	YHA.INIT_FUNC[body_selector]['tab-generate'] = function(){
34845
34846		var toggled = false;
34847
34848		var $sliershow_for = $('#slidershow-for');
34849
34850		var $sliershow_nav = $('#slidershow-nav');
34851
34852		var slider_for = null;
34853
34854		var slider_nav = null;
34855
34856		if($sliershow_for.length
34857
34858		&& $sliershow_nav.length){
34859
34860			slider_for = $sliershow_for.slick({
34861
34862			  slidesToShow: 1,
34863
34864			  slidesToScroll: 1,
34865
34866			  arrows: false,
34867
34868			  fade: true,
34869
34870			  asNavFor: '#slidershow-nav',
34871
34872			  responsive : [
34873
34874			  	{
34875
34876			  		breakpoint: 768,
34877
34878			  		settings: {
34879
34880			  			arrows: true,
34881
34882			  			fade: false,
34883
34884			  		}
34885
34886			  	}
34887
34888			  ]
34889
34890		 	});
34891
34892		 	slider_nav = $sliershow_nav.slick({
34893
34894			  slidesToShow: 4,
34895
34896			  slidesToScroll: 1,
34897
34898			  asNavFor: '#slidershow-for',
34899
34900			  focusOnSelect: true
34901
34902			});
34903
34904			$("#general").on('toggled', function (event, tab) {
34905
34906				if(!toggled){
34907
34908					slider_for.slick('setPosition');
34909
34910					slider_nav.slick('setPosition');
34911
34912					toggled = true;
34913
34914				}
34915
34916			});
34917
34918		}
34919
34920	};
34921
34922
34923
34924	YHA.INIT_FUNC[body_selector]['review-section'] = function(){
34925
34926		$loadMore.on("click", function(e)	{
34927
34928			e.preventDefault();
34929
34930			if(!loading) {
34931
34932				loadMore($(this).attr('data-hostel-id'));	
34933
34934			}
34935
34936		});
34937
34938	};
34939
34940	
34941
34942})(jQuery);
34943var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
34944
34945
34946
34947(function($) {
34948
34949	var body_selector = ".page-donation";
34950
34951	var $submitBtn = $("#btn-continuous"),
34952
34953		txt1 = $submitBtn.html(),
34954
34955		txt2 = $submitBtn.attr("data-txt"),
34956
34957		loading = false;
34958
34959	//INIT
34960
34961	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
34962
34963	YHA.INIT_FUNC[body_selector] = {};
34964
34965
34966
34967	var windowScroll = function(str)
34968
34969	{
34970
34971		$('html, body').stop().animate({
34972
34973			scrollTop: $(str).offset().top
34974
34975		}, 500);
34976
34977
34978
34979	};
34980
34981	YHA.INIT_FUNC[body_selector]['init'] = function(){
34982
34983
34984
34985		$( "#other_amount" ).focus(function() 
34986
34987		{
34988
34989			$("input[name=amount][value='other']","#amount_choice").prop("checked",true);
34990
34991		});
34992
34993
34994
34995		$('#donation-list ul li:first-child a').click(function(e){
34996
34997			e.preventDefault();
34998
34999			e.stopPropagation();
35000
35001			windowScroll('#form-content');
35002
35003		});
35004
35005		$("#btn-continuous").click(function()
35006
35007		{
35008
35009			if(!loading) {
35010
35011				var sur_name_chi = $("#sur_name_chi_input").val();
35012
35013				var given_name_chi = $("#given_name_chi_input").val();
35014
35015				var sur_name_eng = $("#sur_name_eng_input").val();
35016
35017				var given_name_eng = $("#given_name_eng_input").val();
35018
35019				var group_name = $("#group_name_input").val();
35020
35021
35022
35023
35024
35025				var address_1 = $("#address-1").val();
35026
35027				var address_2 = $("#address-2").val();
35028
35029				var address_3 = $("#address-3").val();
35030
35031				var contact = $("#contact_input").val();
35032
35033				var email = $("#email_input").val();
35034
35035				var fax = $("#fax_input").val();
35036
35037
35038
35039
35040
35041
35042
35043				var amount = $('input[name=amount]:checked', '#amount_choice').val();
35044
35045				var receipt = $('input[name=receipt]:checked', '#receipt_choice').val();
35046
35047				var appel = $('input[name=appel]:checked', '#appel_choice').val();
35048
35049				// var district = $('input[name=district]:checked', '#district_choice').val();
35050
35051				var receive = $('input[name=receive]:checked', '#receive_choice').val();
35052
35053
35054
35055
35056
35057				if(amount=="other")
35058
35059				{
35060
35061					amount = $("#other_amount").val();
35062
35063				}
35064
35065
35066
35067				if(receive==undefined ||receive=="undefined")
35068
35069				{
35070
35071					receive = "";
35072
35073				}
35074
35075
35076
35077				if(amount==undefined ||amount=="undefined")
35078
35079				{
35080
35081					amount = "";
35082
35083				}
35084
35085
35086
35087				if(receipt==undefined ||receipt=="undefined")
35088
35089				{
35090
35091					receipt = "";
35092
35093				}
35094
35095
35096
35097				if(appel==undefined ||appel=="undefined")
35098
35099				{
35100
35101					appel = "";
35102
35103				}
35104
35105
35106
35107				//console.log("-------------------------------");
35108
35109				// console.log('data:'+sur_name_chi+"|"+given_name_chi+"|"+sur_name_eng+"|"+given_name_eng+"|"+group_name+"|"+flat+"|"+floor+"|"+block+"|"+building+"|"+street+"|"+contact+"|"+email+"|"+fax+"|"+amount+"|"+receipt+"|"+appel+"|"+district+"|"+receive+"////////////");
35110
35111
35112
35113				loading = true;
35114
35115				$submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
35116
35117				$.post(YHA.common.base_url + "/api/donation/submit_form",
35118
35119					{
35120
35121						sur_name_chi:sur_name_chi,
35122
35123						given_name_chi:given_name_chi,
35124
35125						sur_name_eng:sur_name_eng,
35126
35127						given_name_eng:given_name_eng,
35128
35129						group_name:group_name,
35130
35131						address_1:address_1,
35132
35133						address_2:address_2,
35134
35135						address_3:address_3,
35136
35137						contact:contact,
35138
35139						email:email,
35140
35141						fax:fax,
35142
35143						amount:amount,
35144
35145						receipt:receipt,
35146
35147						appel:appel,
35148
35149						receive:receive,
35150
35151
35152
35153					},(function(response)
35154
35155					{
35156
35157						$submitBtn.html(txt1);
35158
35159						loading = false;
35160
35161						if(response.status)
35162
35163						{
35164
35165							var hiddenForm = response.html;
35166
35167							$('#donation-page-content').hide();
35168
35169							$('#payment-processing').show();
35170
35171							window.scrollTo(0,0);
35172
35173							$(body_selector + ' .hidden-section').html(hiddenForm);
35174
35175						}else
35176
35177						{
35178
35179
35180
35181							var allError ="";
35182
35183
35184
35185							var errorData = response.errors;
35186
35187
35188
35189							for(var i in errorData){
35190
35191								allError+= errorData[i]['msg']+'\n';
35192
35193								break;
35194
35195							}
35196
35197							YHA.common.popupError(allError);
35198
35199
35200
35201						}
35202
35203
35204
35205					}), 'json');
35206
35207			}
35208
35209		});
35210
35211	};
35212
35213	
35214
35215})(jQuery);
35216var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
35217
35218
35219
35220(function($) {
35221
35222	var body_selector = ".page-home";
35223
35224	var loading = false;
35225
35226	// function toDate(date) {
35227
35228	// 	var from = date.split("-");
35229
35230	// 	return new Date(from[2], from[1] - 1, from[0]);
35231
35232	// }
35233
35234
35235
35236	//INIT
35237
35238	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
35239
35240	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
35241
35242	YHA.INIT_FUNC[body_selector] = {};
35243
35244	YHA.RESPON_FUNC[body_selector] = {};
35245
35246	
35247
35248	YHA.INIT_FUNC[body_selector]['home-booking-bar'] = function(){
35249
35250		var $homeBookingBar = $('#home-booking-bar');
35251
35252		$(".tab-title").bind("click",function(){
35253
35254			var $tab = $(this);
35255
35256			var id = $tab.find('a').eq(0).attr('aria-controls');
35257
35258			var $content = $("#"+id);
35259
35260			if(!$content.hasClass('open')){
35261
35262				$(".open").removeClass('open');
35263
35264				$(".tabs-content").addClass('open');
35265
35266				$content.addClass('open');
35267
35268			}else{
35269
35270				$(".open").removeClass('open');
35271
35272			}
35273
35274		});
35275
35276		$homeBookingBar.find('select[name="hostel_name"]').change(function(){
35277
35278			var booking_method = $('option:selected', this).attr('data-booking-method');
35279
35280			if(booking_method == 'email') {
35281
35282				$('#book-by-email').show();
35283
35284				$('#book-by-link').hide();
35285
35286			} else {
35287
35288				$('#book-by-link').show();
35289
35290				$('#book-by-email').hide();
35291
35292			}
35293
35294		});
35295
35296
35297
35298
35299
35300
35301
35302		var lang = 'en';
35303
35304		var booking_lang = 'eng';
35305
35306		var booking_date_error_msg = '';
35307
35308		switch(YHA.common.lang) {
35309
35310			case 'zh':
35311
35312				lang = 'zh-TW';
35313
35314				booking_lang = 'cht';
35315
35316				booking_date_error_msg = '最多可選14晚';
35317
35318				break;
35319
35320			case 'sc':
35321
35322				lang = 'zh-CN';
35323
35324				booking_lang = 'chs';
35325
35326				booking_date_error_msg = '最多可选14晚';
35327
35328				break;
35329
35330			default:
35331
35332				lang = 'en';
35333
35334				booking_lang = 'eng';
35335
35336				booking_date_error_msg = 'Maximum reservation period is 14 nights';
35337
35338		}
35339
35340
35341
35342		$homeBookingBar.find('#hkHostels .btn-submit-booking').click(function(e){
35343
35344			var value = $homeBookingBar.find('select[name="hostel_name"]').val();
35345
35346            var booking_method = $homeBookingBar.find('select[name="hostel_name"] o
35346ption:selected').attr('data-booking-method');
35347
35348            var booking_variable = $homeBookingBar.find('select[name="hostel_name"] option:selected').attr('data-booking-variable');
35349
35350			console.log(value);
35351
35352			if(value != '') {
35353
35354                if(booking_method == 'email') {
35355
35356                    e.preventDefault();
35357
35358                    window.location =  booking_variable;
35359
35360                } else {
35361
35362                    e.preventDefault();
35363
35364                    // var hostel_name = $homeBookingBar.find('select[name=hostel_name]').val();
35365
35366                    var checkin_value = $homeBookingBar.find('input[name=checkin]').val();
35367
35368                    var checkout_value = $homeBookingBar.find('input[name=checkout]').val();
35369
35370                    // var adult = $homeBookingBar.find('select[name=adult]').val();
35371
35372                    // var children = $homeBookingBar.find('select[name=children]').val();
35373
35374                    // var room = $homeBookingBar.find('select[name=room]').val();
35375
35376                    var booking_url = $(this).attr('data-booking-link');
35377
35378                    // var booking_lang = 'eng';
35379
35380                    // console.log(checkin_value);
35381
35382                    // console.log(checkout_value);
35383
35384                    if(checkin_value && checkout_value) {
35385
35386                        var checkin_date = moment(checkin_value);
35387
35388                        var checkout_date = moment(checkout_value);
35389
35390                        // var timeDiff = checkout_date.getTime() - checkin_date.getTime();
35391
35392                        // console.log(checkin_date);
35393
35394                        // console.log(checkout_date);
35395
35396                        var diffDays = checkout_date.diff(checkin_date, 'days');
35397
35398                        console.log(diffDays);
35399
35400                        if(diffDays <= 14 && diffDays > 0) {
35401
35402                            var params = {
35403
35404                                checkin : checkin_value,
35405
35406                                checkout : checkout_value,
35407
35408                                id : value
35409
35410                            };
35411
35412                            var url = booking_url + '?' + $.param(params);
35413
35414                            // console.log(url);
35415
35416                            top.location.href = url;
35417
35418                        } else {
35419
35420                            alert(booking_date_error_msg);
35421
35422                        }
35423
35424                    }
35425
35426				}
35427
35428			}
35429
35430		});
35431
35432        $homeBookingBar.find('#myBooking .btn-submit-booking').click(function(e){
35433
35434        	if(!loading) {
35435
35436        		console.log('Loading');
35437
35438                var $enquiryForm = $('#enquiry-form');
35439
35440                $enquiryForm.ajaxSubmit({
35441
35442                    url : YHA.common.base_url + "/api/hostel/enquiry_form_login",
35443
35444                    success: function(response) {
35445
35446                        loading = false;
35447
35448                        if(response.status) {
35449
35450                            top.location.href = YHA.common.base_url + '/hostels/my-booking';
35451
35452                        } else {
35453
35454                            var errorData = response.errors;
35455
35456                            var allError = "";
35457
35458                            for(var i in errorData) {
35459
35460                                allError = errorData[0]['msg']+'<br>';
35461
35462                                break;
35463
35464                            }
35465
35466                            YHA.common.popupError(allError);
35467
35468                        }
35469
35470                    },
35471
35472                    error: function() {
35473
35474                        loading = false;
35475
35476                        YHA.common.popupError('Network error');
35477
35478                    }
35479
35480                });
35481
35482			}
35483
35484        });
35485
35486		// implementation of disabled form fields
35487
35488
35489
35490		var nowTemp = new Date();
35491
35492		var now = new Date(nowTemp.getFullYear(), nowTemp.getMonth(), nowTemp.getDate(), 0, 0, 0, 0);
35493
35494		var checkin = $homeBookingBar.find('input[name=checkin]').fdatepicker({
35495
35496			format : 'yyyy-mm-dd',
35497
35498			language: lang,
35499
35500			onRender: function (date) {
35501
35502				return date.valueOf() < now.valueOf() ? 'disabled' : '';
35503
35504			}
35505
35506		}).on('changeDate', function (ev) {
35507
35508			if (ev.date.valueOf() >= checkout.date.valueOf()) {
35509
35510				var newDate = new Date(ev.date);
35511
35512				newDate.setDate(newDate.getDate() + 1);
35513
35514				checkout.update(newDate);
35515
35516			}
35517
35518			checkin.hide();
35519
35520			$homeBookingBar.find('input[name=checkout]')[0].focus();
35521
35522		}).data('datepicker');
35523
35524		var checkout = $homeBookingBar.find('input[name=checkout]').fdatepicker({
35525
35526			format : 'yyyy-mm-dd',
35527
35528			language: lang,
35529
35530			onRender: function (date) {
35531
35532				return (date.valueOf() <= checkin.date.valueOf() || date.valueOf() - checkin.date.valueOf() > 14*24*60*60*1000) ? 'disabled' : '';
35533
35534			}
35535
35536		}).on('changeDate', function (ev) {
35537
35538			checkout.hide();
35539
35540		}).data('datepicker');
35541
35542		$homeBookingBar.find('.icon-calendar').click(function(){
35543
35544			if($(this).attr('data-input-target') == 'checkin') {
35545
35546				checkin.show();
35547
35548				checkout.hide();
35549
35550			} else {
35551
35552				checkin.hide();
35553
35554				checkout.show();
35555
35556			}
35557
35558		});
35559
35560	};
35561
35562
35563
35564	YHA.INIT_FUNC[body_selector]['home-find-out'] = function(){
35565
35566		var $wrapper = $("#home-find-out");
35567
35568		var $slider = $(".slidershow",$wrapper);
35569
35570		if($wrapper.length && $slider.length){
35571
35572			$slider.on('setPosition', function(slick){
35573
35574				// console.log('set position');
35575
35576				var height = $(".slick-current .item-img",$wrapper).height();
35577
35578				$(".slick-dots",$wrapper).css('top',parseInt(height)-22);
35579
35580			});
35581
35582		}
35583
35584	};
35585
35586
35587
35588}
35588)(jQuery);
35589var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
35590
35591
35592
35593(function($) {
35594
35595	var body_selector = ".page-association";
35596
35597
35598
35599	var currentwidth = 0;
35600
35601	var stickyActive = false;
35602
35603	//INIT
35604
35605	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
35606
35607	YHA.INIT_FUNC[body_selector] = {};
35608
35609
35610
35611	YHA.INIT_FUNC[body_selector]['init'] = function()
35612
35613	{
35614
35615
35616
35617		var checkWinWidth = function()
35618
35619		{
35620
35621			if(currentwidth != $(window).width())
35622
35623			{
35624
35625				currentwidth = $(window).width();
35626
35627				
35628
35629				if($("#side-menu").css('padding-left')=="0px")
35630
35631				{
35632
35633					$("#side-menu .content").unstick();
35634
35635					stickyActive = false;
35636
35637				}else{
35638
35639					if(!stickyActive) {
35640
35641						$("#side-menu .content").sticky({
35642
35643							topSpacing: 40
35644
35645						});
35646
35647						$("#side-menu .content").on('sticky-start', function(){
35648
35649							var $sideMenu = $("#side-menu");
35650
35651							var left = $sideMenu.offset().left + parseInt($sideMenu.css('padding-left'));
35652
35653							$(this).css({
35654
35655								'left' : left
35656
35657							});
35658
35659						});
35660
35661						stickyActive = true;
35662
35663					}
35664
35665					
35666
35667				}
35668
35669			}
35670
35671		}
35672
35673
35674
35675		checkWinWidth();
35676
35677
35678
35679		
35680
35681
35682
35683		$( window ).resize(function() 
35684
35685		{
35686
35687			checkWinWidth();
35688
35689
35690
35691		});
35692
35693
35694
35695		var windowScroll = function(str)
35696
35697		{
35698
35699			$('html, body').stop().animate({
35700
35701				scrollTop: $(str).offset().top
35702
35703			}, 500);
35704
35705
35706
35707		};
35708
35709
35710
35711
35712
35713		$("#side-menu").find("li").each(function(index)
35714
35715		{
35716
35717			$(this).click(function()
35718
35719			{
35720
35721				if(index==0)
35722
35723				{
35724
35725					windowScroll(".mission");
35726
35727				}
35728
35729
35730
35731				if(index==1)
35732
35733				{
35734
35735					windowScroll(".milestone");
35736
35737				}
35738
35739
35740
35741				if(index==2)
35742
35743				{
35744
35745					windowScroll(".organisation");
35746
35747				}
35748
35749
35750
35751				if(index==3)
35752
35753				{
35754
35755					windowScroll(".awards");
35756
35757				}
35758
35759
35760
35761			});
35762
35763
35764
35765
35766
35767		});
35768
35769
35770
35771
35772
35773		
35774
35775
35776
35777		
35778
35779
35780
35781	};
35782
35783	
35784
35785})(jQuery);
35786var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
35787
35788
35789
35790(function($) {
35791
35792	var body_selector = ".page-become-member",
35793
35794        $submitBtn = $("#btn-continuous"),
35795
35796        txt1 = $submitBtn.html(),
35797
35798        txt2 = $submitBtn.attr("data-txt"),
35799
35800        submitting = false;
35801
35802	//INIT
35803
35804	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
35805
35806	YHA.INIT_FUNC[body_selector] = {};
35807
35808
35809
35810	YHA.INIT_FUNC[body_selector]['init'] = function(){
35811
35812
35813
35814        $( "#act_7_txt_input" ).focus(function()
35815
35816        {
35817
35818            $("input[name=act][value='other']","#activities_choice").prop("checked",true);
35819
35820        });
35821
35822		$("#btn-continuous").click(function()
35823
35824		{
35825
35826            if (!submitting) {
35827
35828                submitting = true;
35829
35830                $submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
35831
35832                var captcha = grecaptcha.getResponse();
35833
35834
35835
35836                //console.log("response:"+captcha);
35837
35838
35839
35840                var name_cht = $("#name_cht_input").val();
35841
35842                var name_eng = $("#name_eng_input").val();
35843
35844                var birthplace = $("#hometown_input").val();
35845
35846                var professional = $("#occupation_input").val();
35847
35848                var address = $("#address_input").val();
35849
35850                var tel = $("#home_phone_input").val();
35851
35852                var phone = $("#mobile_input").val();
35853
35854                var email = $("#email_input").val();
35855
35856                var fax = $("#fax_input").val();
35857
35858                var old_address = $("#former_address_input").val();
35859
35860                var year = $("#por_input").val();
35861
35862
35863
35864                // var work_other = $('input[name=act]:checked', '#activities_choice').val();
35865
35866
35867
35868                // if(work_other == undefined || work_other == "undefined")
35869
35870                // {
35871
35872                //     work_other = "";
35873
35874                // }
35875
35876
35877
35878                // if(work_other=="other")
35879
35880                // {
35881
35882                //     work_other = $("#act_7_txt_input").val();
35883
35884                // }
35885
35886
35887
35888
35889
35890
35891
35892                var guided_tour = false,
35893
35894                    research = false,
35895
35896                    museum_administration = false,
35897
35898                    artifacts_handling = false,
35899
35900                    oral_history = false,
35901
35902                    story_sharing = false,
35903
35904                    work_other = false,
35905
35906                    receive_promotion = 0;
35907
35908
35909
35910
35911
35912                if($("#act_1").is(':checked')) 
35913
35914                {
35915
35916                    guided_tour = 1;
35917
35918                };
35919
35920                if($('#act_2').is(':checked')) 
35921
35922                {
35923
35924                    research = 1;
35925
35926                };
35927
35928                if($('#act_3').is(':checked')) 
35929
35930                {
35931
35932                    museum_administration = 1;
35933
35934                };
35935
35936                if($('#act_4').is(':checked')) 
35937
35938                {
35939
35940                    artifacts_handling = 1;
35941
35942                };
35943
35944                if($('#act_5').is(':checked')) 
35945
35946                {
35947
35948                    oral_history = 1;
35949
35950                };
35951
35952                if($('#act_6').is(':checked')) 
35953
35954                {
35955
35956                    story_sharing = 1;
35957
35958                };
35959
35960                if($('#act_7').is(':checked')) 
35961
35962                {
35963
35964                    work_other = $("#act_7_txt_input").val();
35965
35966                };
35967
35968
35969
35970                if($('input[name="receive_promotion"]').is(':checked'))
35971
35972                {
35973
35974                    receive_promotion = 1;
35975
35976                }
35977
35978
35979
35980                var gender = $('input[name=gender]:checked', '#gender_choice').val();
35981
35982
35983
35984
35985
35986                if(gender == undefined || gender == "undefined")
35987
35988                {
35989
35990                    gender = "";
35991
35992                }
35993
35994
35995
35996                var age = $('input[name=age]:checked', '#age_choice').val();
35997
35998
35999
36000
36001
36002                if(age == undefined || age == "undefined")
36003
36004                {
36005
36006                    age = "";
36007
36008                }
36009
36010
36011
36012                //console.log("-------------------------------");
36013
36014                //console.log('guided_tour:'+guided_tour+"|"+research+"|"+museum_administration+"|"+artifacts_handling+"|"+oral_history+"|"+story_sharing+"|"+work_other);
36015
36016
36017
36018                $.post(YHA.common.base_url + "/api/alumni_network/submit_form",
36019
36020                {
36021
36022                    name_cht:name_cht,
36023
36024                    name_eng:name_eng,
36025
36026                    gender:gender,
36027
36028                    birthplace:birthplace,
36029
36030                    professional: professional,
36031
36032                    age:age,
36033
36034                    address:address,
36035
36036                    tel:tel,
36037
36038                    phone:phone,
36039
36040                    email:email,
36041
36042                    fax:fax,
36043
36044                    old_address:old_address,
36045
36046                    year:year,
36047
36048                    work_other:work_other,
36049
36050                    guided_tour:guided_tour,
36051
36052                    museum_administration:museum_administration,
36053
36054                    oral_history:oral_history,
36055
36056                    research:research,
36057
36058                    artifacts_handling:artifacts_handling,
36059
36060                    story_sharing:story_sharing,
36061
36062                    receive_promotion:receive_promotion,
36063
36064                    captcha:captcha
36065
36066
36067
36068                },(function(response) 
36069
36070                {
36071
36072                    submitting = false;
36073
36074                    $submitBtn.html(txt1);
36075
36076                    if(response.status) {
36077
36078                        YHA.common.popupError(response.msg);
36079
36080                    } else {
36081
36082                        grecaptcha.reset();
36083
36084                        var allError ="";
36085
36086                        var errorData = response.errors;
36087
36088                        for(var i in errorData){
36089
36090                            allError = errorData[0]['msg']+'<br>';
36091
36092                            break;
36093
36094                        }
36095
36096                        YHA.common.popupError(allError);
36097
36098                    }
36099
36100
36101
36102                }), 'json');
36103
36104            }
36105
36106		});
36107
36108
36109
36110	};
36111
36112	
36113
36114})(jQuery);
36115var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
36116
36117
36118
36119(function($) {
36120
36121	var body_selector = ".page-contactus";
36122
36123	var $submitBtn = $("#btn-continuous"),
36124
36125		txt1 = $submitBtn.html(),
36126
36127		txt2 = $submitBtn.attr("data-txt"),
36128
36129		loading = false;
36130
36131
36132
36133	function resetForm() {
36134
36135		$("#surname_input").val('');
36136
36137		$("#given_name_input").val('');
36138
36139		$("#email_input").val('');
36140
36141		$("#contact_num_input").val('');
36142
36143		$("#address_input").val('');
36144
36145		$("#fax_input").val('');
36146
36147		$("#content_input").val('');
36148
36149	}
36150
36151	//INIT
36152
36153	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
36154
36155	YHA.INIT_FUNC[body_selector] = {};
36156
36157
36158
36159	YHA.INIT_FUNC[body_selector]['init'] = function(){
36160
36161
36162
36163		$("#btn-continuous").click(function()
36164
36165		{
36166
36167			if(!loading) {
36168
36169				var surname = $("#surname_input").val();
36170
36171				var given_name = $("#given_name_input").val();
36172
36173				var email = $("#email_input").val();
36174
36175				var contact = $("#contact_num_input").val();
36176
36177				var address = $("#address_input").val();
36178
36179				var fax = $("#fax_input").val();
36180
36181				var content = $("#content_input").val();
36182
36183				var enquiry = $( "#enquiry option:selected" ).text();
36184
36185				var hostel_id = $( "#hostel_id option:selected" ).val();
36186
36187				var appel = $('input[name=appel]:checked', '#appel_choice').val();
36188
36189				var recaptcha = $('#g-recaptcha-response').val();
36190
36191
36192
36193				if(appel == undefined || appel == "undefined")
36194
36195				{
36196
36197					appel = "";
36198
36199				}
36200
36201
36202
36203				//console.log("-------------------------------");
36204
36205				//console.log('data:'+surname+"|"+given_name+"|"+email+"|"+contact+"|"+address+"|"+fax+"|"+content+"|"+enquiry);
36206
36207
36208
36209				loading = true;
36210
36211				$submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
36212
36213
36214
36215				$.post(YHA.common.base_url + "/api/contactus/submit_form",
36216
36217					{
36218
36219						surname:surname,
36220
36221						given_name:given_name,
36222
36223						email:email,
36224
36225						contact: contact,
36226
36227						appellation:appel,
36228
36229						address:address,
36230
36231						fax:fax,
36232
36233						content:content,
36234
36235						enquiry:enquiry,
36236
36237						hostel_id: hostel_id,
36238
36239						'g-recaptcha-response' :recaptcha
36240
36241					},(function(response)
36242
36243					{
36244
36245						$submitBtn.html(txt1);
36246
36247						loading = false;
36248
36249						if(response.status)
36250
36251						{
36252
36253							resetForm();
36254
36255							YHA.common.popupError(response.msg);
36256
36257						}else
36258
36259						{
36260
36261							var allError ="";
36262
36263							var errorData = response.errors;
36264
36265							for(var i in errorData){
36266
36267								allError = errorData[0]['msg']+'<br>';
36268
36269								break;
36270
36271							}
36272
36273							YHA.common.popupError(allError);
36274
36275						}
36276
36277
36278
36279					}), 'json');
36280
36281			}
36282
36283		});
36284
36285
36286
36287	};
36288
36289	
36290
36291})(jQuery);
36292var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
36293
36294
36295
36296(function($) {
36297
36298	var body_selector = ".page-edm",
36299
36300        $body_selector = $(".page-edm"),
36301
36302        $edm_content = $body_selector.find('.edmContent'),
36303
36304        $yearchooser = $body_selector.find(".yearchooser"),
36305
36306        $year = $yearchooser.find("span"),
36307
36308        minYear = $year.attr("data-min"),
36309
36310        maxYear = $year.attr("data-max"),
36311
36312        $no_record = $body_selector.find(".no_record"),
36313
36314        $loadMore = $body_selector.find(".loadWrapper .btn"),
36315
36316        txt1 = $loadMore.text(),
36317
36318        txt2 = $loadMore.attr("data-txt"),
36319
36320        loading = false,
36321
36322        xhr;        
36323
36324
36325
36326    var year=$year.attr("data-year"), page = 1, count = 10, currentOrderBy = 'newsletter_date', currentOrder = 'desc', searchTag = '';
36327
36328
36329
36330	//INIT
36331
36332	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
36333
36334	YHA.INIT_FUNC[body_selector] = {};
36335
36336
36337
36338	function getEdms() {
36339
36340        loading = true;
36341
36342
36343
36344        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
36345
36346        
36347
36348		var query = {
36349
36350			'orderby' : currentOrderBy,
36351
36352			'order' : currentOrder,
36353
36354			'page' : page,
36355
36356			'count' : count,
36357
36358            'year' : year
36359
36360		};
36361
36362        loading = true; 
36363
36364        $year.html(year).attr("data-year", year);  
36365
36366		xhr = $.get(YHA.common.base_url + "/api/news/get_edms/", query, function(response) {      
36367
36368            if(response.status)	{                
36369
36370                if(response.data.length < 1 || response.data.length < count) 
36371
36372                    $loadMore.hide();
36373
36374                createBlocks(response.data);
36375
36376            }
36377
36378            $loadMore.text(txt1);
36379
36380            loading = false;
36381
36382            
36383
36384            if (!$edm_content.find("> div").length) {
36385
36386                $loadMore.hide();
36387
36388                $no_record.show();
36389
36390            }
36391
36392                                
36393
36394            xhr = (function() {return;})();                        
36395
36396		}, 'json');
36397
36398	}
36399
36400
36401
36402	function createBlocks(posts) {
36403
36404		$.each(posts, function()	{
36405
36406			var $html = $('<div class="columns small-12 medium-10 medium-centered">' +
36407
36408                    '<a href="' + this.url + '" target="_blank" class="edmItem">' +
36409
36410                        '<div class="date">' + this.newsletter_date + '</div>' +
36411
36412                        '<div class="title fontf-rs">' + this.title + '</div>' +
36413
36414                        '<i></i>' +
36415
36416                    '</a>' +
36417
36418                '</div>');
36419
36420            $edm_content.append($html);
36421
36422		});
36423
36424	}
36425
36426    
36427
36428	//INIT
36429
36430	YHA.INIT_FUNC[body_selector]['init'] = function(){
36431
36432        var $prev = $yearchooser.find(".prev"),
36433
36434            $next = $yearchooser.find(".next");
36435
36436    
36437
36438		$body_selector.find('.featured-event-box').slick({
36439
36440		    arrows: false,
36441
36442		    dots: true
36443
36444		});
36445
36446
36447
36448        $prev.on("click", function(e) {
36449
36450            e.preventDefault();            
36451
36452            if (!loading && parseInt(year) >= (parseInt(minYear) + 1)) {
36453
36454                if (typeof(xhr) !== "undefined") 
36455
36456                    xhr.abort();
36457
36458                loading = false;    
36459
36460                $no_record.hide();
36461
36462                $loadMore.show();
36463
36464
36465
36466                year--;
36467
36468                page = 1;
36469
36470                $edm_content.empty();
36471
36472                
36473
36474                if (year == minYear)
36475
36476                    $prev.addClass("disabled");
36477
36478                $next.removeClass("disabled");
36479
36480                
36481
36482                getEdms();
36483
36484            }       
36485
36486        });
36487
36488        
36489
36490        $next.on("click", function(e) {
36491
36492            e.preventDefault();   
36493
36494            if (!loading && parseInt(year) <= (parseInt(maxYear) - 1)) {
36495
36496                if (typeof(xhr) !== "undefined") 
36497
36498                    xhr.abort();
36499
36500                loading = false;    
36501
36502                $no_record.hide();
36503
36504                $loadMore.show();       
36505
36506
36507
36508                year++;
36509
36510                page = 1;        
36511
36512                $edm_content.empty();
36513
36514                
36515
36516                if (year == maxYear)
36517
36518                    $next.addClass("disabled");
36519
36520                $prev.removeClass("disabled");
36521
36522                
36523
36524                getEdms();
36525
36526            }       
36527
36528        });
36529
36530        
36531
36532		$loadMore.on("click", function(e)	{
36533
36534			e.preventDefault();
36535
36536			if(!loading) {
36537
36538                page++;
36539
36540				getEdms();
36541
36542			}
36543
36544		});
36545
36546	};
36547
36548	
36549
36550})(jQuery);
36551
36552
36553var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
36554
36555
36556
36557(function($) {
36558
36559	var body_selector = ".page-events",
36560
36561		$body_selector = $(body_selector),
36562
36563        $masonry = $body_selector.find(".masonryAreaWrapper"),
36564
36565        $no_record = $body_selector.find(".no_record"),
36566
36567        $loadMore = $body_selector.find(".loadWrapper .btn"),
36568
36569        txt1 = $loadMore.text(),
36570
36571        txt2 = $loadMore.attr("data-txt"),
36572
36573        loading = false,
36574
36575        xhr;        
36576
36577	
36578
36579	var page = 1, count = 8, currentOrderBy = 'event_date_from', currentOrder = 'desc', searchTag = '';
36580
36581    
36582
36583	//INIT
36584
36585	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
36586
36587	YHA.INIT_FUNC[body_selector] = {};
36588
36589
36590
36591	function getEvents(type) {
36592
36593        loading = true;
36594
36595
36596
36597        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
36598
36599        
36600
36601		var query = {
36602
36603			'orderby' : currentOrderBy,
36604
36605			'order' : currentOrder,
36606
36607			'page' : page,
36608
36609			'count' : count,
36610
36611            'type' : type
36612
36613		};
36614
36615        loading = true; 
36616
36617		xhr = $.get(YHA.common.base_url + "/api/news/get_events/", query, function(response) {      
36618
36619            if(response.status)	{                
36620
36621                if(response.data.length < 1 || response.data.length < count) 
36622
36623                    $loadMore.hide();
36624
36625                createBlocks(response.data);
36626
36627            }
36628
36629            $loadMore.text(txt1);
36630
36631            loading = false;
36632
36633            
36634
36635            if (!$masonry.find(".article").length) {
36636
36637                $loadMore.hide();
36638
36639                $no_record.show();
36640
36641            }
36642
36643                                
36644
36645            xhr = (function() {return;})();       
36646
36647		}, 'json');
36648
36649	}
36650
36651
36652
36653	function createBlocks(posts) {
36654
36655		var post;
36656
36657        for ( var i = 0, l = posts.length; i < l; i++ ) {
36658
36659            post = posts[i];
36660
36661			var $html = $('<div class="article">' +
36662
36663                    '<a href="' + post.url + '">' +
36664
36665                        (post.thumbnail ? '<img src="' + post.thumbnail.url + '" alt="' + post.thumbnail.alt + '" />' : '') +
36666
36667                        '<div class="articleContent">' +
36668
36669                            '<div class="news-date">' + post.event_date_from + '</div>' +
36670
36671                            '<h4 class="title blue-title">
36671' + post.title + '</h4>' +
36672
36673                            '<span class="rightArrow"><i class="fa fa-arrow-right"></i></span>' +
36674
36675                        '</div>' +
36676
36677                    '</a>' +
36678
36679                '</div>');
36680
36681            
36682
36683            $("<img />").attr("src", post.thumbnail.url).load(function() {
36684
36685                $masonry.masonry('layout');
36686
36687            });
36688
36689            
36690
36691            $masonry.append($html).masonry("appended", $html).masonry('layout');
36692
36693		}
36694
36695	}
36696
36697
36698
36699	YHA.INIT_FUNC[body_selector]['init'] = function(){
36700
36701
36702
36703		$body_selector.find('.featured-event-box').slick({
36704
36705		    arrows: false,
36706
36707		    dots: true
36708
36709		  });
36710
36711
36712
36713		$body_selector.find('.event-chooser a').click(function() {                        
36714
36715            if (typeof(xhr) !== "undefined") 
36716
36717                xhr.abort();
36718
36719            loading = false;    
36720
36721            $no_record.hide();
36722
36723            $loadMore.show();
36724
36725            
36726
36727			$(this).siblings('a').removeClass('active');
36728
36729			$(this).addClass('active');
36730
36731            
36732
36733            page = 1;                
36734
36735            $masonry.masonry('remove', $('.article')).masonry('layout');
36736
36737            getEvents($(this).attr('data-type'));
36738
36739		});
36740
36741
36742
36743		$body_selector.find(".loadWrapper").on("click", function(e)	{
36744
36745			e.preventDefault();
36746
36747			if(!loading) {
36748
36749                page++;
36750
36751                getEvents($body_selector.find('.event-chooser a.active').attr('data-type'));
36752
36753            }
36754
36755		});
36756
36757	};
36758
36759	
36760
36761})(jQuery);
36762
36763
36764var YHA = YHA || {};
36765
36766
36767
36768(function($) {
36769
36770	var body_selector = ".page-experience",
36771
36772        $body_selector = $(".page-experience"),
36773
36774        $masonry = $body_selector.find(".masonryAreaWrapper"),
36775
36776        $no_record = $body_selector.find(".no_record"),
36777
36778        $loadMore = $body_selector.find(".loadWrapper .btn"),
36779
36780        txt1 = $loadMore.text(),
36781
36782        txt2 = $loadMore.attr("data-txt"),
36783
36784        loading = false,
36785
36786        xhr;
36787
36788
36789
36790    var page = 1, count = 8, currentCategory = 'all', currentOrderBy = 'article_date', currentOrder = 'desc', searchTag = $body_selector.find("input[name=search]").val();
36791
36792    var stopLoad = false, searchLock = false, searchInputInterval;
36793
36794    
36795
36796	//INIT
36797
36798	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
36799
36800	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
36801
36802	YHA.INIT_FUNC[body_selector] = {};
36803
36804	YHA.RESPON_FUNC[body_selector] = {};
36805
36806
36807
36808	var delay = (function(){
36809
36810		var timer = 0;
36811
36812		return function(callback, ms){
36813
36814			clearTimeout (timer);
36815
36816			timer = setTimeout(callback, ms);
36817
36818		};
36819
36820	})();
36821
36822
36823
36824	function getExperiences() {
36825
36826        loading = true;
36827
36828
36829
36830        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
36831
36832        
36833
36834		var query = {
36835
36836			'orderby' : currentOrderBy,
36837
36838			'order' : currentOrder,
36839
36840			'page' : page,
36841
36842			'count' : count,
36843
36844		};
36845
36846		if(currentCategory != 'all') 
36847
36848			query['category_slug'] = currentCategory;		
36849
36850		if(searchTag != '') 
36851
36852			query['tag'] = searchTag;
36853
36854	        
36855
36856		xhr = $.get(YHA.common.base_url + "/api/explore/get_experiences/", query, function(response){           
36857
36858            if(response.status)	{                
36859
36860                if(response.data.length < 1 || response.data.length < count) 
36861
36862                    $loadMore.hide();
36863
36864                createBlocks(response.data);
36865
36866            }
36867
36868            $loadMore.text(txt1);
36869
36870            loading = false;
36871
36872            
36873
36874            if (!$masonry.find(".article").length) {
36875
36876                $loadMore.hide();
36877
36878                $no_record.show();
36879
36880            }
36881
36882                                
36883
36884            xhr = (function() {return;})();
36885
36886		}, 'json');
36887
36888	}
36889
36890
36891
36892	function createBlocks(posts) {
36893
36894        var post;
36895
36896        for ( var i = 0, l = posts.length; i < l; i++ ) {
36897
36898            post = posts[i];
36899
36900			var $html = $('<div class="article">' +
36901
36902                    '<a href="' + post.url + '">' +
36903
36904                        (post.image_url != "" ? '<img src="' + post.image_url + '" alt="' + post.title + '" class="thumb" />' : '' ) +
36905
36906                        '<img class="ribbon" src="' + YHA.common.template_url + '/images/' + YHA.common.lang + '/tab_' + post.category_name.toLowerCase() + '.png"/>' +
36907
36908                        '<div class="articleContent">' +
36909
36910                            '<h4 class="title">
36910' + post.title + '</h4>' +
36911
36912                            '<div class="date">' + post.article_date + '</div>' +
36913
36914                            '<span class="rightArrow"><i class="fa fa-arrow-right"></i></span>' +
36915
36916                        '</div>' +
36917
36918                    '</a>' +
36919
36920                '</div>');
36921
36922            $masonry.append($html).masonry("appended", $html);            
36923
36924            
36925
36926            $("<img />").attr("src", post.image_url).load(function() {
36927
36928                $masonry.masonry('layout');
36929
36930            });
36931
36932		}
36933
36934        $masonry.masonry('layout');
36935
36936	}
36937
36938
36939
36940	function changeCategory(category)	{
36941
36942        if (typeof(xhr) !== "undefined") 
36943
36944            xhr.abort();
36945
36946        loading = false;        
36947
36948        $no_record.hide();
36949
36950        $loadMore.show();            
36951
36952        
36953
36954		currentCategory = category;
36955
36956		page = 1;
36957
36958		$masonry.masonry('remove', $('.article')).masonry('layout');
36959
36960		getExperiences();
36961
36962	}
36963
36964
36965
36966	function changeOrderBy(sortBy)	{
36967
36968        if (typeof(xhr) !== "undefined") 
36969
36970            xhr.abort();
36971
36972        loading = false;    
36973
36974        $no_record.hide();
36975
36976        $loadMore.show();            
36977
36978        
36979
36980		var orderArray = sortBy.split(',');         
36981
36982		currentOrderBy = orderArray[0];
36983
36984		currentOrder = orderArray[1];
36985
36986		page = 1;
36987
36988		$masonry.masonry('remove', $('.article')).masonry('layout');
36989
36990		getExperiences();
36991
36992	}
36993
36994
36995
36996	//INIT
36997
36998	YHA.INIT_FUNC[body_selector]['init'] = function(){
36999
37000		$body_selector.find("select[name=category]").change(function() {
37001
37002			changeCategory($(this).val());	
37003
37004		});
37005
37006		$body_selector.find("select[name=sortBy]").change(function() {
37007
37008			changeOrderBy($(this).val());	
37009
37010		});
37011
37012		$body_selector.find("input[name=search]").keyup(function() {
37013
37014			var value = $(this).val();
37015
37016		    delay(function(){
37017
37018                if (typeof(xhr) !== "undefined") 
37019
37020                    xhr.abort();
37021
37022                loading = false;  
37023
37024                $no_record.hide();
37025
37026                $loadMore.show();            
37027
37028                
37029
37030				searchTag = value;
37031
37032				page = 1;
37033
37034				$masonry.masonry('remove', $('.article')).masonry('layout');
37035
37036				getExperiences();
37037
37038		    }, 500 );
37039
37040		});
37041
37042        
37043
37044		$loadMore.on("click", function(e)	{
37045
37046			e.preventDefault();
37047
37048			if(!loading) {
37049
37050                page++;
37051
37052				getExperiences();
37053
37054			}
37055
37056		});
37057
37058	};
37059
37060
37061
37062
37063
37064})(jQuery);
37065var YHA = YHA || {};
37066
37067
37068
37069(function($) {
37070
37071	var body_selector = ".page-photo-gallery",
37072
37073		$body_selector = $(body_selector),
37074
37075		$masonry = $body_selector.find(".masonryAreaWrapper"),
37076
37077		$no_record = $body_selector.find(".no_record"),
37078
37079		$loadMore = $body_selector.find(".loadWrapper .btn"),
37080
37081		txt1 = $loadMore.text(),
37082
37083		txt2 = $loadMore.attr("data-txt"),
37084
37085		loading = false,
37086
37087		xhr;
37088
37089
37090
37091	var page = 1, count = 1;
37092
37093
37094
37095	//INIT
37096
37097	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
37098
37099	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
37100
37101	YHA.INIT_FUNC[body_selector] = {};
37102
37103	YHA.RESPON_FUNC[body_selector] = {};
37104
37105
37106
37107	function getExperiences() {
37108
37109		loading = true;
37110
37111
37112
37113		$loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
37114
37115
37116
37117		var query = {
37118
37119			'page' : page,
37120
37121			'count' : count,
37122
37123		};
37124
37125
37126
37127		xhr = $.get(YHA.common.base_url + "/api/news/get_galleries_list/", query, function(response){
37128
37129			if(response.status)	{
37130
37131				if(response.data.length < 1 || response.data.length < count)
37132
37133					$loadMore.hide();
37134
37135				createBlocks(response.data);
37136
37137			}
37138
37139			$loadMore.text(txt1);
37140
37141			loading = false;
37142
37143
37144
37145			if (!$masonry.find(".article").length) {
37146
37147				$loadMore.hide();
37148
37149				$no_record.show();
37150
37151			}
37152
37153
37154
37155			xhr = (function() {return;})();
37156
37157		}, 'json');
37158
37159	}
37160
37161
37162
37163	function createBlocks(posts) {
37164
37165		var post;
37166
37167		//(post.image ?'<img src="' + post.image.url + '" alt="' + post.title + '" />':'') +
37168
37169		for ( var i = 0, l = posts.length; i < l; i++ ) {
37170
37171			post = posts[i];
37172
37173			var $html = $('' +
37174
37175				'<div class="article">' +
37176
37177					'<a href="' + post.url + '">' +
37178
37179						(post.image ?'<img src="' + post.image.url + '" alt="' + post.title + '" />':'') +
37180
37181						'<div class="articleContent">' +
37182
37183							'<div class="title">' + post.title + '</div>' +
37184
37185							'<div class="date">' + post.date + '</div>' +
37186
37187							'<div class="summary">' +
37188
37189								(post.total_images > 0 ?'<span>' + post.total_images + '<i class="fa fa-picture-o"></i></span>':'') +
37190
37191								(post.total_videos > 0 ?'<span>' + post.total_videos + '<i class="fa fa-film"></i></span>':'') +
37192
37193							'</div>' +
37194
37195						'</div>' +
37196
37197					'</a>' +
37198
37199				'</div>');
37200
37201
37202
37203			$masonry.append($html).masonry("appended", $html);
37204
37205
37206
37207			$("<img />").attr("src", post.image.url).load(function() {
37208
37209				$masonry.masonry('layout');
37210
37211			});
37212
37213		}
37214
37215		$masonry.masonry('layout');
37216
37217	}
37218
37219
37220
37221	//INIT
37222
37223	YHA.INIT_FUNC[body_selector]['init'] = function(){
37224
37225		$loadMore.on("click", function(e)	{
37226
37227			e.preventDefault();
37228
37229			if(!loading) {
37230
37231				page++;
37232
37233				getExperiences();
37234
37235			}
37236
37237		});
37238
37239	};
37240
37241
37242
37243
37244
37245})(jQuery);
37246var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
37247
37248
37249
37250(function($) {
37251
37252	var body_selector = ".page-group-member-application";
37253
37254	var $submitBtn = $("#btn-continuous"),
37255
37256		txt1 = $submitBtn.html(),
37257
37258		txt2 = $submitBtn.attr("data-txt"),
37259
37260		loading = false;
37261
37262
37263
37264    function redirectToPaymentGateway(response) {
37265
37266        var hiddenForm = response.html;
37267
37268        $('#form-section').hide();
37269
37270        $('#payment-processing').show();
37271
37272        window.scrollTo(0,0);
37273
37274        $(body_selector + ' .hidden-section').html(hiddenForm);
37275
37276    }
37277
37278
37279
37280	function showThankyou() {
37281
37282		$('#form-section').hide();
37283
37284		$('#thankyou-section').show();
37285
37286		window.scrollTo(0,0);
37287
37288	}
37289
37290	//INIT
37291
37292	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
37293
37294	YHA.INIT_FUNC[body_selector] = {};
37295
37296
37297
37298	YHA.INIT_FUNC[body_selector]['init'] = function() {
37299
37300		$('input[type=radio][name=application_type]').change(function() {
37301
37302			if(/(renewal)/i.test($(this).val())) {
37303
37304				$('#member-id').attr('disabled', false).focus();
37305
37306			} else {
37307
37308				$('#member-id').attr('disabled', true);
37309
37310			}
37311
37312		});
37313
37314		$('input[data-target-input]').change(function() {
37315
37316			var targetInput = $(this).attr('data-target-input');
37317
37318			if($(this).is(':checked')) {
37319
37320				$(targetInput).attr('disabled', false).focus();
37321
37322			} else {
37323
37324				$(targetInput).attr('disabled', true);
37325
37326			}
37327
37328		});
37329
37330		$("input:file").change(function (){
37331
37332			var filename = $(this).val().split('\\').pop();
37333
37334			$(this).parents('.field-group-file-upload').find('.file-name').html(filename);
37335
37336		});
37337
37338		$("#btn-continuous").click(function() {
37339
37340			if(!loading) {
37341
37342				loading = true;
37343
37344				$submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
37345
37346				var $applicationForm = $('#application-form');
37347
37348				$applicationForm.ajaxSubmit({
37349
37350					url : YHA.common.base_url + "/api/group_membership/submit_form",
37351
37352					success: function(response) {
37353
37354						loading = false;
37355
37356						$submitBtn.html(txt1);
37357
37358						if(response.status) {
37359
37360							if(response.html) {
37361
37362                                redirectToPaymentGateway(response);
37363
37364							} else {
37365
37366                                $('.ref_id').text(response.ref_id);
37367
37368                                showThankyou();
37369
37370							}
37371
37372						} else {
37373
37374							var errorData = response.errors;
37375
37376							var allError = "";
37377
37378							for(var i in errorData) {
37379
37380								allError = errorData[0]['msg']+'<br>';
37381
37382								break;
37383
37384							}
37385
37386							YHA.common.popupError(allError);
37387
37388						}
37389
37390					},
37391
37392					error: function() {
37393
37394						loading = false;
37395
37396						$submitBtn.html(txt1);
37397
37398						YHA.common.popupError('Network error');
37399
37400					}
37401
37402				});
37403
37404			}
37405
37406		});
37407
37408	};
37409
37410})(jQuery);
37411var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
37412
37413
37414
37415(function($) {
37416
37417	var body_selector = ".page-individual-member-application";
37418
37419	var $submitBtn = $("#btn-continuous"),
37420
37421		txt1 = $submitBtn.html(),
37422
37423		txt2 = $submitBtn.attr("data-txt"),
37424
37425		loading = false;
37426
37427	var $year_selector = $('select[name=birthday_year]'),
37428
37429		$month_selector = $('select[name=birthday_month]'),
37430
37431		$day_selector = $('select[name=birthday_day]');
37432
37433
37434
37435	function redirectToPaymentGateway(response) {
37436
37437		var hiddenForm = response.html;
37438
37439		$('#form-section').hide();
37440
37441		$('#payment-processing').show();
37442
37443		window.scrollTo(0,0);
37444
37445		$(body_selector + ' .hidden-section').html(hiddenForm);
37446
37447	}
37448
37449	function setDayOptions(max_days) {
37450
37451		var html = $day_selector.find('option:first-child')[0].outerHTML;
37452
37453		var currentDay = parseInt($day_selector.val());
37454
37455		for(var i = 1; i <= max_days; i++) {
37456
37457			if(currentDay == i) {
37458
37459				html += '<option value="'+ i + '" selected>' + i + '</option>';
37460
37461			} else {
37462
37463				html += '<option value="'+ i + '">' + i + '</option>';
37464
37465			}
37466
37467		}
37468
37469		$day_selector.html(html);
37470
37471		if(currentDay > max_days) {
37472
37473			$day_selector.prop('selectedIndex',0);
37474
37475		}
37476
37477	}
37478
37479	function checkDays() {
37480
37481		var monthsWithShortDays= [2,4,5,9,11];
37482
37483		var currentMonth = parseInt($month_selector.val());
37484
37485		var currentYear = parseInt($year_selector.val());
37486
37487
37488
37489		if(currentMonth == 2) {
37490
37491			if(currentYear % 4 == 0) {
37492
37493				setDayOptions(29);
37494
37495			} else {
37496
37497				setDayOptions(28);
37498
37499			}
37500
37501		} else if(monthsWithShortDays.indexOf(currentMonth) > -1) {
37502
37503			setDayOptions(30);
37504
37505		} else {
37506
37507			setDayOptions(31);
37508
37509		}
37510
37511	}
37512
37513	//INIT
37514
37515	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
37516
37517	YHA.INIT_FUNC[body_selector] = {};
37518
37519
37520
37521	YHA.INIT_FUNC[body_selector]['init'] = function(){
37522
37523		$year_selector.change(function() {
37524
37525			checkDays();
37526
37527		});
37528
37529		$month_selector.change(function() {
37530
37531			checkDays();
37532
37533		});
37534
37535		$('input[type=radio][name=application_type]').change(function() {
37536
37537			if(/(renewal)/i.test($(this).val())) {
37538
37539				$('#member-id').attr('disabled', false).focus();
37540
37541			} else {
37542
37543				$('#member-id').attr('disabled', true);
37544
37545			}
37546
37547		});
37548
37549		$('input[data-target-input]').change(function() {
37550
37551			var targetInput = $(this).attr('data-target-input');
37552
37553			if($(this).is(':checked')) {
37554
37555				$(targetInput).attr('disabled', false).focus();
37556
37557			} else {
37558
37559				$(targetInput).attr('disabled', true);
37560
37561			}
37562
37563		});
37564
37565		$("#btn-continuous").click(function()
37566
37567		{
37568
37569			if(!loading) {
37570
37571				loading = true;
37572
37573				$submitBtn.html('<span><i class="fa"></i><p><i>' + txt2 + '</i></p></span>');
37574
37575				var $applicationForm = $('#application-form');
37576
37577				$applicationForm.ajaxSubmit({
37578
37579					url : YHA.common.base_url + "/api/individual_membership/submit_form",
37580
37581					success: function(response) {
37582
37583						loading = false;
37584
37585						$submitBtn.html(txt1);
37586
37587						if(response.status) {
37588
37589							redirectToPaymentGateway(response);
37590
37591						} else {
37592
37593							var errorData = response.errors;
37594
37595							var allError = "";
37596
37597							for(var i in errorData) {
37598
37599								allError = errorData[0]['msg']+'<br>';
37600
37601								break;
37602
37603							}
37604
37605							YHA.common.popupError(allError);
37606
37607						}
37608
37609					},
37610
37611					error: function() {
37612
37613						loading = false;
37614
37615						$submitBtn.html(txt1);
37616
37617						YHA.common.popupError('Network error');
37618
37619					}
37620
37621				});
37622
37623			}
37624
37625		});
37626
37627	};
37628
37629})(jQuery);
37630var YHA = YHA || {};
37631
37632
37633
37634(function($) {
37635
37636	var body_selector = ".page-media-center",
37637
37638        $body_selector = $(body_selector),
37639
37640        $masonry = $body_selector.find(".masonryAreaWrapper"),
37641
37642        $no_record = $body_selector.find(".countryWrapper .no_record"),
37643
37644        $loadMore = $body_selector.find(" .loadWrapper .btn"),
37645
37646        txt1 = $loadMore.text(),
37647
37648        txt2 = $loadMore.attr("data-txt"),
37649
37650        loading = false,
37651
37652        xhr;        
37653
37654    var page = 1, count = 9, currentOrderBy = 'news_date', currentOrder = 'desc', searchTag = '';
37655
37656    var stopLoad = false, searchLock = false, searchInputInterval;
37657
37658        
37659
37660	//INIT
37661
37662	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
37663
37664	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
37665
37666	YHA.INIT_FUNC[body_selector] = {};
37667
37668	YHA.RESPON_FUNC[body_selector] = {};
37669
37670
37671
37672	var delay = (function(){
37673
37674		var timer = 0;
37675
37676		return function(callback, ms){
37677
37678			clearTimeout (timer);
37679
37680			timer = setTimeout(callback, ms);
37681
37682		};
37683
37684	})();
37685
37686
37687
37688	function getMediaCenters() {
37689
37690        loading = true;
37691
37692
37693
37694        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
37695
37696        
37697
37698		var query = {
37699
37700			'orderby' : currentOrderBy,
37701
37702			'order' : currentOrder,
37703
37704			'page' : page,
37705
37706			'count' : count
37707
37708		};
37709
37710        loading = true; 
37711
37712        $year.html(year).attr("data-year", year);  
37713
37714		xhr = $.get(YHA.common.base_url + "/api/news/get_news/", query, function(response) {        
37715
37716            if(response.status)	{                
37717
37718                if(response.data.length < 1 || response.data.length < count) 
37719
37720                    $loadMore.hide();
37721
37722                createBlocks(response.data);
37723
37724            }
37725
37726            $loadMore.text(txt1);
37727
37728            loading = false;
37729
37730            
37731
37732            if (!$masonry.find(".article").length) {
37733
37734                $loadMore.hide();
37735
37736                $no_record.show();
37737
37738            }
37739
37740                                
37741
37742            xhr = (function() {return;})();            
37743
37744		}, 'json');
37745
37746	}
37747
37748
37749
37750	function createBlocks(posts) {
37751
37752		var post;
37753
37754        for ( var i = 0, l = posts.length; i < l; i++ ) {
37755
37756            post = posts[i];
37757
37758            
37759
37760			var $html = $('' +
37761
37762                '<div class="article">' +
37763
37764                    '<a href="' + post.url + '">' +
37765
37766                        (post.image_url ? '<img src="' + post.image_url + '" alt="' + post.title + '" />' : '') + 
37767
37768                        '<div class="articleContent">' +
37769
37770                            '<div class="news-date">' + post.date + '</div>' +
37771
37772                            '<div class="blue-title">' + post.title + '</div>' +
37773
37774                            '<span class="rightArrow"><i class="fa fa-arrow-right"></i></span>' +
37775
37776                        '</div>' +
37777
37778                    '</a>' +
37779
37780                '</div>');
37781
37782            $masonry.append($html).masonry("appended", $html);
37783
37784            
37785
37786            $("<img />").attr("src", post.image_url).load(function() {
37787
37788                $masonry.masonry('layout');
37789
37790            });
37791
37792		}
37793
37794        $masonry.masonry('layout');        
37795
37796	}
37797
37798    
37799
37800	//INIT
37801
37802	YHA.INIT_FUNC[body_selector]['init'] = function(){                 
37803
37804		$loadMore.on("click", function(e)	{
37805
37806			e.preventDefault();
37807
37808			if(!loading) {
37809
37810                page++;
37811
37812				getMediaCenters();
37813
37814			}
37815
37816		});
37817
37818	};
37819
37820
37821
37822
37823
37824})(jQuery);
37825var YHA = YHA || {};
37826
37827
37828
37829(function($) {
37830
37831	var body_selector = ".page-member-offers",
37832
37833        $body_selector = $(body_selector),
37834
37835        $masonry = $body_selector.find(".masonryAreaWrapper"),
37836
37837        $cat_icons = $body_selector.find(".circle_icons"),
37838
37839        $cat_select = $body_selector.find(".categoryWrapper select"),     
37840
37841        $no_record = $body_selector.find(".no_record"),
37842
37843        $loadMore = $body_selector.find(".loadWrapper .btn"),
37844
37845        txt1 = $loadMore.text(),
37846
37847        txt2 = $loadMore.attr("data-txt"),
37848
37849        loading = false,
37850
37851        xhr,
37852
37853        page = 1, 
37854
37855        count = 5,
37856
37857        currentCategory = $cat_icons.find(".on").attr("data-id");
37858
37859  
37860
37861	//INIT
37862
37863	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
37864
37865	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
37866
37867	YHA.INIT_FUNC[body_selector] = {};
37868
37869	YHA.RESPON_FUNC[body_selector] = {};
37870
37871
37872
37873	var delay = (function(){
37874
37875		var timer = 0;
37876
37877		return function(callback, ms){
37878
37879			clearTimeout (timer);
37880
37881			timer = setTimeout(callback, ms);
37882
37883		};
37884
37885	})();
37886
37887
37888
37889	function getMemberOffers() {
37890
37891        loading = true;
37892
37893
37894
37895        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
37896
37897        
37898
37899		var query = {
37900
37901			'page' : page,
37902
37903			'count' : count,
37904
37905            'cat' : currentCategory
37906
37907		};
37908
37909        loading = true; 
37910
37911		xhr = $.get(YHA.common.base_url + "/api/memberoffer/get_member_offers/", query, function(response) {
37912
37913            if(response.status)	{                
37914
37915                if(response.data.length < 1 || response.data.length < count) 
37916
37917                    $loadMore.hide();
37918
37919                createBlocks(response.data);
37920
37921            }
37922
37923            $loadMore.text(txt1);
37924
37925            loading = false;
37926
37927            
37928
37929            if (!$masonry.find(".article").length) { 
37930
37931                $loadMore.hide();
37932
37933                $no_record.show();
37934
37935            }
37936
37937                                
37938
37939            xhr = (function() {return;})();
37940
37941		}, 'json');
37942
37943	}
37944
37945
37946
37947	function createBlocks(posts) {
37948
37949        var post;
37950
37951        var txt_gotowebsite =  $masonry.attr("data-txt");
37952
37953        for ( var i = 0, l = posts.length; i < l; i++ ) {
37954
37955            post = posts[i];
37956
37957			var $html = $('' +
37958
37959                '<div class="article">' +
37960
37961                    (post.image ? '<img src="' + post.image.url + '" alt="' + post.image.alt + '" title="' + post.image.title + '" />' : '') +                      
37962
37963                    '<div class="articleContent">' +
37964
37965                        '<div class="article-title">' + post.title + '</div>' +
37966
37967                        (post.subtitle ? '<div class="blue-title">' + post.subtitle + '</div>' : '') +                      
37968
37969                        (post.content ? '<div class="article-para">' + post.content + '</div>' : '') +                      
37970
37971                        (post.address ? '<div class="icon-para"><i class="fa fa-home"></i>' + post.address + '</div>' : '') +       
37972
37973                        (post.phone ? '<div class="icon-para"><i class="fa fa-phone"></i>' + post.phone + '</div>' : '') +         
37974
37975                        (post.url ? '<ul class="arrow-list"><li><a href="' + post.url + '" target="_blank">' + txt_gotowebsite + '</a></li></ul>' : '') +                      
37976
37977                    '</div>' +
37978
37979                '</div>');
37980
37981            if (post.image) {
37982
37983                // console.log(post.image.url);
37984
37985                $("<img />").attr("src", post.image.url).load(function() {
37986
37987                    // console.log('img loaded: ' + post.image.url);
37988
37989                    $masonry.masonry('layout');
37990
37991                });
37992
37993            }
37994
37995            $masonry.append($html).masonry("appended", $html).masonry('layout');
37996
37997		}
37998
37999	}
38000
38001
38002
38003	function updateCategory(category)	{
38004
38005        if (currentCategory != category) {
38006
38007            if (typeof(xhr) !== "undefined") 
38008
38009                xhr.abort();
38010
38011            loading = false;         
38012
38013            currentCategory = category;
38014
38015            page = 1;
38016
38017            $no_record.hide();
38018
38019            $loadMore.show();  
38020
38021            
38022
38023            $cat_icons.find("a.on").removeClass("on");
38024
38025            $cat_icons.find("a[data-id=" + currentCategory + "]").addClass("on");
38026
38027                        
38028
38029            $cat_select.find("option[selected=selected]").removeAttr("selected");
38030
38031            $cat_select.find("option[value=" + currentCategory + "]").attr("selected","selected");
38032
38033            
38034
38035            $masonry.find(".article").each(function() {
38036
38037                $masonry.masonry("remove", this);                    
38038
38039            });
38040
38041            $masonry.masonry("layout");                         
38042
38043            getMemberOffers();
38044
38045        }
38046
38047	}
38048
38049    
38050
38051	//INIT
38052
38053	YHA.INIT_FUNC[body_selector]['init'] = function(){
38054
38055        $cat_icons.on("click", "a", function(e) {
38056
38057            e.preventDefault();
38058
38059            updateCategory($(this).attr("data-id"));
38060
38061        });
38062
38063        
38064
38065        $cat_select.on("change", function(e) {
38066
38067            e.preventDefault();
38068
38069            updateCategory($(this).val());
38070
38071        });
38072
38073                 
38074
38075		$loadMore.on("click", function(e)	{
38076
38077			e.preventDefault();
38078
38079			if(!loading) {
38080
38081                page++;
38082
38083				getMemberOffers();	
38084
38085			}  
38086
38087		});
38088
38089	};
38090
38091
38092
38093
38094
38095})(jQuery);
38096var YHA = YHA || {};
38097
38098
38099
38100(function($) {
38101
38102	var body_selector = ".page-news",
38103
38104        $body_selector = $(".page-news"),
38105
38106        $masonry = $body_selector.find(".masonryAreaWrapper"),
38107
38108        $yearchooser = $body_selector.find(".yearchooser"),
38109
38110        $year = $yearchooser.find("span"),
38111
38112        minYear = $year.attr("data-min"),
38113
38114        maxYear = $year.attr("data-max"),
38115
38116        $no_record = $body_selector.find(".countryWrapper .no_record"),
38117
38118        $loadMore = $body_selector.find(" .loadWrapper .btn"),
38119
38120        txt1 = $loadMore.text(),
38121
38122        txt2 = $loadMore.attr("data-txt"),
38123
38124        loading = false,
38125
38126        xhr;        
38127
38128    var year=$year.attr("data-year"), page = 1, count = 9, currentOrderBy = 'news_date', currentOrder = 'desc', searchTag = '';
38129
38130    var stopLoad = false, searchLock = false, searchInputInterval;
38131
38132        
38133
38134	//INIT
38135
38136	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
38137
38138	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
38139
38140	YHA.INIT_FUNC[body_selector] = {};
38141
38142	YHA.RESPON_FUNC[body_selector] = {};
38143
38144
38145
38146	var delay = (function(){
38147
38148		var timer = 0;
38149
38150		return function(callback, ms){
38151
38152			clearTimeout (timer);
38153
38154			timer = setTimeout(callback, ms);
38155
38156		};
38157
38158	})();
38159
38160
38161
38162	function getNews() {
38163
38164        loading = true;
38165
38166
38167
38168        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
38169
38170        
38171
38172		var query = {
38173
38174			'orderby' : currentOrderBy,
38175
38176			'order' : currentOrder,
38177
38178			'page' : page,
38179
38180			'count' : count,
38181
38182            'year' : year
38183
38184		};
38185
38186        loading = true; 
38187
38188        $year.html(year).attr("data-year", year);  
38189
38190		xhr = $.get(YHA.common.base_url + "/api/news/get_news/", query, function(response) {        
38191
38192            if(response.status)	{                
38193
38194                if(response.data.length < 1 || response.data.length < count) 
38195
38196                    $loadMore.hide();
38197
38198                createBlocks(response.data);
38199
38200            }
38201
38202            $loadMore.text(txt1);
38203
38204            loading = false;
38205
38206            
38207
38208            if (!$masonry.find(".article").length) {
38209
38210                $loadMore.hide();
38211
38212                $no_record.show();
38213
38214            }
38215
38216                                
38217
38218            xhr = (function() {return;})();            
38219
38220		}, 'json');
38221
38222	}
38223
38224
38225
38226	function createBlocks(posts) {
38227
38228		var post;
38229
38230        for ( var i = 0, l = posts.length; i < l; i++ ) {
38231
38232            post = posts[i];
38233
38234            
38235
38236			var $html = $('' +
38237
38238                '<div class="article">' +
38239
38240                    '<a href="' + post.url + '">' +
38241
38242                        (post.image_url ? '<img src="' + post.image_url + '" alt="' + post.title + '" />' : '') + 
38243
38244                        '<div class="articleContent">' +
38245
38246                            '<div class="news-date">' + post.date + '</div>' +
38247
38248                            '<h4 class="title blue-title">' + post.title + '</h4>' +
38249
38250                            '<span class="rightArrow"><i class="fa fa-arrow-right"></i></span>' +
38251
38252                        '</div>' +
38253
38254                    '</a>' +
38255
38256                '</div>');
38257
38258            $masonry.append($html).masonry("appended", $html);
38259
38260            
38261
38262            $("<img />").attr("src", post.image_url).load(function() {
38263
38264                $masonry.masonry('layout');
38265
38266            });
38267
38268		}
38269
38270        $masonry.masonry('layout');        
38271
38272	}
38273
38274    
38275
38276	//INIT
38277
38278	YHA.INIT_FUNC[body_selector]['init'] = function(){
38279
38280        var $prev = $yearchooser.find(".prev"),
38281
38282            $next = $yearchooser.find(".next");
38283
38284        $prev.on("click", function(e) {
38285
38286            e.preventDefault();
38287
38288            if (!loading && parseInt(year) >= (parseInt(minYear) + 1)) {
38289
38290                if (typeof(xhr) !== "undefined") 
38291
38292                    xhr.abort();
38293
38294                loading = false;    
38295
38296                $no_record.hide();
38297
38298                $loadMore.show();
38299
38300
38301
38302                year--;
38303
38304                page = 1;
38305
38306                $masonry.masonry('remove', $('.article')).masonry('layout');
38307
38308                
38309
38310                if (year == minYear)
38311
38312                    $prev.addClass("disabled");
38313
38314                $next.removeClass("disabled");
38315
38316                
38317
38318                getNews();
38319
38320            }       
38321
38322        });
38323
38324        
38325
38326        $next.on("click", function(e) {
38327
38328            e.preventDefault();   
38329
38330            if (!loading && parseInt(year) <= (parseInt(maxYear) - 1)) {
38331
38332                if (typeof(xhr) !== "undefined") 
38333
38334                    xhr.abort();
38335
38336                loading = false;    
38337
38338                $no_record.hide();
38339
38340                $loadMore.show();       
38341
38342
38343
38344                year++;
38345
38346                page = 1;        
38347
38348                $masonry.masonry('remove', $('.article')).masonry('layout');
38349
38350                
38351
38352                if (year == maxYear)
38353
38354                    $next.addClass("disabled");
38355
38356                $prev.removeClass("disabled");
38357
38358                
38359
38360                getNews();
38361
38362            }            
38363
38364        });
38365
38366                 
38367
38368		$loadMore.on("click", function(e)	{
38369
38370			e.preventDefault();
38371
38372			if(!loading) {
38373
38374                page++;
38375
38376				getNews();
38377
38378			}
38379
38380		});
38381
38382	};
38383
38384
38385
38386
38387
38388})(jQuery);
38389var YHA = YHA || {};
38390
38391
38392
38393(function($) {
38394
38395	var body_selector = ".page-tips",
38396
38397        $body_selector = $(body_selector),
38398
38399        $list = $body_selector.find(".countryWrapper > ul"),
38400
38401        $cat_icons = $body_selector.find(".categoryWrapper .circle_icons"),
38402
38403        $cat_select = $body_selector.find(".categoryWrapper select"),     
38404
38405        $no_record = $body_selector.find(".countryWrapper .no_record"),
38406
38407        $loadMore = $body_selector.find(" .loadWrapper .btn"),
38408
38409        txt1 = $loadMore.text(),
38410
38411        txt2 = $loadMore.attr("data-txt"),
38412
38413        loading = false,
38414
38415        xhr,
38416
38417        page = 1, 
38418
38419        count = 9, 
38420
38421        currentCategory = $cat_icons.find(".on").attr("data-id");
38422
38423
38424
38425	//INIT
38426
38427	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
38428
38429	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
38430
38431	YHA.INIT_FUNC[body_selector] = {};
38432
38433	YHA.RESPON_FUNC[body_selector] = {};
38434
38435
38436
38437	function getTips() {
38438
38439        loading = true;
38440
38441
38442
38443        $loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
38444
38445
38446
38447        var query = {
38448
38449            'page' : page,
38450
38451            'count' : count,
38452
38453        };
38454
38455        if(currentCategory != 'all') {
38456
38457            query['category_slug'] = currentCategory;
38458
38459        }
38460
38461        xhr = $.get(YHA.common.base_url + "/api/explore/get_tips/", query, function(response){
38462
38463            if(response.status)	{                
38464
38465                if(response.data.length < 1 || response.data.length < count) 
38466
38467                    $loadMore.hide();
38468
38469                createBlocks(response.data);
38470
38471            }
38472
38473            $loadMore.text(txt1);
38474
38475            loading = false;
38476
38477            
38478
38479            if (!$list.find("li").length) {
38480
38481                $loadMore.hide();
38482
38483                $no_record.show();
38484
38485            }
38486
38487                                
38488
38489            xhr = (function() {return;})();
38490
38491        }, 'json');
38492
38493	}
38494
38495
38496
38497	function createBlocks(posts) {
38498
38499        var post;
38500
38501        for ( var i = 0, l = posts.length; i < l; i++ ) {
38502
38503            post = posts[i];
38504
38505			var experienceHtml = '' +
38506
38507                '<li>' +
38508
38509                    '<a href="' + post.url + '">' +
38510
38511                        '<span><img src="' + post.image_url + '" alt="' + post.image_alt + '" title="' + post.image_title + '" /></span>' +
38512
38513                        '<div>' +
38514
38515                            '<div>' +
38516
38517                                '<p>' +
38518
38519                                    '<span class="h1">' + post.title + '</span>' +
38520
38521                                '</p>' +
38522
38523                            '</div>' +
38524
38525                        '</div>' +
38526
38527                    '</a>' +
38528
38529                '</li>';
38530
38531			$list.append(experienceHtml);
38532
38533		}
38534
38535	}
38536
38537    
38538
38539	function updateCategory(category)	{
38540
38541        if (currentCategory != category) {
38542
38543            if (typeof(xhr) !== "undefined") 
38544
38545                xhr.abort();
38546
38547            loading = false;         
38548
38549            currentCategory = category;
38550
38551            page = 1;
38552
38553            $no_record.hide();
38554
38555            $loadMore.show();  
38556
38557            
38558
38559            $list.html('');
38560
38561            
38562
38563            $cat_icons.find("a.on").removeClass("on");
38564
38565            $cat_icons.find("a[data-id=" + currentCategory + "]").addClass("on");
38566
38567                        
38568
38569            $cat_select.find("option[selected=selected]").removeAttr("selected");
38570
38571            $cat_select.find("option[value=" + currentCategory + "]").attr("selected","selected");
38572
38573                                        
38574
38575            getTips();
38576
38577        }
38578
38579	}
38580
38581
38582
38583	//INIT
38584
38585	YHA.INIT_FUNC[body_selector]['travel-tips-icons'] = function(){
38586
38587        $cat_icons.on("click", "a", function(e) {
38588
38589            e.preventDefault();
38590
38591            updateCategory($(this).attr("data-id"));
38592
38593        });
38594
38595        
38596
38597        $cat_select.on("change", function(e) {
38598
38599            e.preventDefault();
38600
38601            updateCategory($(this).val());
38602
38603        });
38604
38605
38606
38607		$loadMore.on("click", function(e)	{
38608
38609			e.preventDefault();
38610
38611			if(!loading) {
38612
38613                page++;
38614
38615				getTips();	
38616
38617			}
38618
38619		});
38620
38621	};
38622
38623
38624
38625
38626
38627})(jQuery);
38628var YHA = YHA || {INIT_FUNC:{},RESPON_FUNC:{}};
38629
38630
38631
38632function initCalendarData(calendarData, quantity) {
38633
38634	console.log(quantity);
38635
38636	for(var i = 0; i < calendarData.length; i++) {
38637
38638		if(calendarData[i].quantity < quantity) {
38639
38640			calendarData[i]['className'] = 'slot-disable';
38641
38642		} else {
38643
38644			calendarData[i]['className'] = '';
38645
38646		}
38647		if(calendarData[i].title == '00:00-00:00' || calendarData[i].title == '16:00-00:00' || calendarData[i].title == '16:00-22:00') {
38648			switch(YHA.common.lang) {
38649				case 'en':
38650					calendarData[i].title = 'Check In Date';
38651					break;
38652				case 'zh':
38653					calendarData[i].title = '入住日期';
38654					break;
38655				case 'sc':
38656					calendarData[i].title = '入住日期';
38657					break;
38658			}
38659		}
38660
38661	}
38662
38663	return calendarData;
38664
38665}
38666
38667(function($) {
38668
38669	var body_selector = ".page-tour-detail";
38670
38671	var activity_type = $('input[name="activity_type"]').val();
38672
38673	var currentwidth = 0;
38674
38675	var stickyActive = false;
38676
38677
38678
38679	var stepNow = 1,
38680
38681		currentStep = 0,
38682
38683		previewStep = false,
38684
38685
38686
38687		errMsg = "",
38688
38689
38690
38691		calendar_data = [],
38692
38693		calendar_oject = "",
38694
38695
38696
38697		selected_id = "",
38698
38699		quantity = activity_type==='family'?1:0,
38700
38701
38702
38703		same_person = false,
38704
38705
38706
38707		stepContentArr = ["calendarContainer","formContainer","previewContainer"];
38708
38709
38710
38711	var $submitBtn = $("#btn-submit"), $paymentBtn = $("#btn-payment"),
38712
38713		original_txt_submit_btn = $submitBtn.html(), original_txt_payment_btn = $paymentBtn.html(),
38714
38715		loading_txt_submit_btn = $submitBtn.attr("data-txt"), loading_txt_payment_btn = $paymentBtn.attr("data-txt"),
38716
38717		submitting = false;
38718
38719
38720
38721	//INIT
38722
38723	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
38724
38725	YHA.INIT_FUNC[body_selector] = {};
38726
38727
38728
38729	function formatPopupDateTitle(date) {
38730
38731		var thisDate = date;
38732
38733		var month = thisDate.getMonth();
38734
38735		var day = thisDate.getDate();
38736
38737		var shortMonthsInYear   = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
38738
38739			'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
38740
38741		switch(YHA.common.lang) {
38742
38743			case 'en':
38744
38745				return day + ' ' + shortMonthsInYear[month];
38746
38747				break;
38748
38749			case 'zh':
38750
38751			case 'sc':
38752
38753				return (month+1) + '月' + day + '日';
38754
38755				break;
38756
38757			default:
38758
38759				return day + ' ' + shortMonthsInYear[month];
38760
38761		}
38762
38763	}
38764
38765	function checkEventOnOff()
38766
38767	{
38768
38769		$(".fc-event-container").find(".fc-title").each(function(index)
38770
38771		{
38772
38773			if($(this).attr('id')==selected_id)
38774
38775			{
38776
38777				$(this).parent().parent().addClass("selected");
38778
38779			}else
38780
38781			{
38782
38783				$(this).parent().parent().removeClass("selected");
38784
38785			}
38786
38787		});
38788
38789	}
38790
38791
38792
38793	function checkRadio(data)
38794
38795	{
38796
38797		if(data == undefined || data == "undefined")
38798
38799		{
38800
38801			return "";
38802
38803		}else{
38804
38805			return data;
38806
38807		}
38808
38809	}
38810
38811
38812
38813	function hexc(colorval)
38814
38815	{
38816
38817		var parts = colorval.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
38818
38819		delete(parts[0]);
38820
38821		for (var i = 1; i <= 3; ++i) {
38822
38823			parts[i] = parseInt(parts[i]).toString(16);
38824
38825			if (parts[i].length == 1) parts[i] = '0' + parts[i];
38826
38827		}
38828
38829		return '#' + parts.join('');
38830
38831	}
38832
38833
38834
38835	function resetTourData()
38836
38837	{
38838
38839		selected_id = "";
38840
38841	}
38842
38843
38844
38845	function getDateEventAndPopUp(calEvent, jsEvent, view)
38846
38847	{
38848
38849
38850
38851		var current_date = new Date(calEvent.start);
38852
38853
38854
38855		var entire_date = moment(current_date).format('YYYY-MM-DD');
38856
38857
38858
38859		newCalendarData = $.grep(calendar_data, function( n ) {
38860
38861			// console.log(n.start);
38862
38863			return ( n.start == entire_date);
38864
38865		});
38866
38867		newCalendarData.sort(function(a, b){
38868
38869			if (a.title < b.title)
38870
38871				return -1;
38872
38873			else if (a.title > b.title)
38874
38875				return 1;
38876
38877			else
38878
38879				return 0;
38880
38881		});
38882
38883
38884
38885		$("#calendar_date_popup").css({"display":"block"});
38886
38887		$("#calendar_date_popup").html();
38888
38889
38890
38891		var inputDate = '<div id="calendar_title_popup">'+ formatPopupDateTitle(current_date) + '</div>';
38892
38893
38894
38895		var inputEvent = '';
38896
38897
38898
38899		for(var i=0; i < newCalendarData.length; i++)
38900
38901		{
38902
38903			inputEvent += '<div class="event_item" id="'+newCalendarData[i].id+'"><span>'+newCalendarData[i].title+'</span></div>';
38904
38905		}
38906
38907
38908
38909
38910
38911		$("#calendar_date_popup").html(inputDate+inputEvent);
38912
38913
38914
38915		$(".event_item").click(function()
38916
38917		{
38918
38919			selected_id = $(this).attr("id");
38920
38921
38922
38923			$(".event_item").removeClass("selected");
38924
38925
38926
38927			$(this).addClass("selected");
38928
38929
38930
38931			checkEventOnOff();
38932
38933		});
38934
38935
38936
38937		resetTourData();
38938
38939
38940
38941		$.magnificPopup.open({
38942
38943			items: {
38944
38945				src: $("#calendar_date_popup")
38946
38947			}
38948
38949		});
38950
38951	}
38952
38953
38954
38955	function createPostData() {
38956
38957		var data = {};
38958
38959        data['activity_type'] = $('input[name="activity_type"]').val();
38960
38961        data['booking_type'] = $('input[name="booking_type"]').val();
38962
38963
38964
38965		var contact_person = $("#contact_person_input").val();
38966
38967		var nationality = '';
38968
38969		var nationalityTxt = '';
38970
38971
38972
38973		$( "#nationality option:selected" ).each(function(index)
38974
38975		{
38976
38977			if($( this ).val() == "") {
38978
38979				nationality = '';
38980
38981                nationalityTxt = '';
38982
38983			} else {
38984
38985                nationality = $( this ).val();
38986
38987                nationalityTxt = $( this ).text();
38988
38989            }
38990
38991		});
38992
38993
38994
38995		var memberRegistrationCountry = '';
38996
38997		var memberRegistrationCountryTxt = '';
38998
38999
39000
39001		$( "#member_registration_country option:selected" ).each(function(index)
39002
39003		{
39004
39005			if($( this ).val() == "") {
39006
39007				memberRegistrationCountry = '';
39008
39009				memberRegistrationCountryTxt = '';
39010
39011			} else {
39012
39013				memberRegistrationCountry = $( this ).val();
39014
39015				memberRegistrationCountryTxt = $( this ).text();
39016
39017			}
39018
39019		});
39020
39021
39022
39023		var hkid = $("#hkid_input").val();
39024
39025		var contact = $("#contact_input").val();
39026
39027		var email = $("#email_input").val();
39028
39029
39030
39031		var title = $('input[name=gender]:checked', '#title_choice').val();
39032
39033		title = checkRadio(title);
39034
39035
39036
39037		var member = $('input[name=member]:checked', '#member_choice').val();
39038
39039		member = checkRadio(member);
39040
39041
39042
39043        if(data['activity_type'] === 'guided_tour') {
39044
39045            var now_person = quantity;
39046
39047            var person = {
39048
39049                'number': now_person,
39050
39051                'same': same_person
39052
39053            };
39054
39055            if(same_person)
39056
39057            {
39058
39059                person['person_1']  = contact_person;
39060
39061            }else{
39062
39063                person['person_1']  = $("#person_1_input").val();
39064
39065            }
39066
39067            for(var i=1; i<parseInt(now_person);i++)
39068
39069            {
39070
39071                var target = (i+1);
39072
39073                person['person_' + target] = $("#person_"+target+"_input").val();
39074
39075            }
39076
39077        } else if(activity_type === 'family') {
39078
39079            var totalParticipants = quantity;
39080
39081            var person = {
39082
39083                'number' : totalParticipants
39084
39085            };
39086
39087            for(var i = 1; i <= parseInt(totalParticipants); i++)
39088
39089            {
39090
39091                person['person_' + i] = {
39092
39093                    name: $("#person_" + i + "_name").val(),
39094
39095                    children_name: $("#person_" + i + "_children_name").val(),
39096
39097                    children_age: $("#person_" + i + "_children_age").val()
39098
39099                };
39100
39101            }
39102
39103		} else {
39104
39105            var totalParticipants = quantity;
39106
39107            var person = {
39108
39109                'number' : totalParticipants
39110
39111            };
39112
39113            for(var i = 1; i <= parseInt(totalParticipants); i++)
39114
39115            {
39116
39117                person['person_' + i] = {
39118
39119                    name: $("#person_" + i + "_name").val(),
39120
39121                    age: $("#person_" + i + "_age").val(),
39122
39123                    hkid: $("#person_" + i + "_hkid").val()
39124
39125                };
39126
39127            }
39128
39129		}
39130
39131
39132
39133		if ($('#receive_promotion').is(":checked"))
39134
39135		{
39136
39137			data['receive_promotion'] = $('#receive_promotion').val();
39138
39139		} else {
39140
39141			data['receive_promotion'] = 0;
39142
39143		}
39144
39145        if ($('#data_confirmation').is(":checked"))
39146
39147        {
39148
39149            data['data_confirmation'] = $('#data_confirmation').val();
39150
39151        } else {
39152
39153            data['data_confirmation'] = 0;
39154
39155        }
39156
39157		data['tour_id'] = $('input[name=tour_id]').val();
39158
39159		data['member_id'] = $('#member_id').val();
39160
39161		data['tour_slot_id'] = selected_id;
39162
39163		data['quantity'] = quantity;
39164
39165		data['contact_person'] = contact_person;
39166
39167		data['title'] = title;
39168
39169		data['nationality'] = nationality;
39170
39171		data['nationalityTxt'] = nationalityTxt;
39172
39173		data['member_registration_country'] = memberRegistrationCountry;
39174
39175		data['memberRegistrationCountryTxt'] = memberRegistrationCountryTxt;
39176
39177		data['hkid'] = hkid;
39178
39179		data['contact'] = contact;
39180
39181		data['email'] = email;
39182
39183		data['no_of_disabled_participants'] = $('#no_of_disabled_participants').val();
39184
39185		data['member'] = member;
39186
39187		data['person'] = person;
39188
39189		return data;
39190
39191	}
39192
39193	YHA.INIT_FUNC[body_selector]['init'] = function()
39194
39195	{
39196
39197		//console.log("??");
39198
39199		calendar_data = initCalendarData(window.calendar_global_data, 0);
39200
39201		var toggled = false;
39202
39203		var $sliershow_for = $('#slidershow-for');
39204
39205		var $sliershow_nav = $('#slidershow-nav');
39206
39207		var slider_for = null;
39208
39209		var slider_nav = null;
39210
39211		if($sliershow_for.length
39212
39213		&& $sliershow_nav.length){
39214
39215			slider_for = $sliershow_for.slick({
39216
39217			  slidesToShow: 1,
39218
39219			  slidesToScroll: 1,
39220
39221			  arrows: false,
39222
39223			  fade: true,
39224
39225			  asNavFor: '#slidershow-nav',
39226
39227			  responsive : [
39228
39229			  	{
39230
39231			  		breakpoint: 768,
39232
39233			  		settings: {
39234
39235			  			arrows: true,
39236
39237			  			fade: false,
39238
39239			  		}
39240
39241			  	}
39242
39243			  ]
39244
39245		 	});
39246
39247		 	slider_nav = $sliershow_nav.slick({
39248
39249			  slidesToShow: 4,
39250
39251			  slidesToScroll: 1,
39252
39253			  asNavFor: '#slidershow-for',
39254
39255			  focusOnSelect: true
39256
39257			});
39258
39259			
39260
39261		}
39262
39263		
39264
39265		$('.btn-booking').click(function() {
39266
39267			$('#tour-detail-page').stop().animate({opacity: 0}, 800, function() {
39268
39269				$(this).hide();
39270
39271				$('#tour-booking-page').show().stop().animate({opacity: 1}, 800);
39272
39273				var lang = 'en';
39274
39275				switch(YHA.common.lang) {
39276
39277					case 'zh':
39278
39279						lang = 'zh-TW';
39280
39281						break;
39282
39283					case 'sc':
39284
39285						lang = 'zh-cn';
39286
39287						break;
39288
39289					default:
39290
39291						lang = 'en';
39292
39293				}
39294
39295				var defaultDate = moment();
39296
39297				if(window.calendar_global_data[0]) {
39298
39299                    defaultDate = moment(window.calendar_global_data[0]['start']);
39300
39301				}
39302
39303				calendar_oject = $('#calendar').fullCalendar(
39304
39305					{
39306
39307						header:{
39308
39309							left:   '',
39310
39311							center: 'prev,title,next',
39312
39313							right:  ''
39314
39315						},
39316
39317						lang: lang,
39318
39319						height: 1000,
39320
39321						events:calendar_data,
39322
39323						defaultDate: defaultDate,
39324
39325						eventAfterAllRender: function(view)
39326
39327						{
39328
39329							checkEventOnOff();
39330
39331						},
39332
39333						viewRender: function(currentView){
39334
39335							var minDate = moment();
39336
39337							// Past
39338
39339							if (minDate >= currentView.start && minDate <= currentView.end) {
39340
39341								$(".fc-prev-button").prop('disabled', true);
39342
39343								$(".fc-prev-button").addClass('fc-state-disabled');
39344
39345							} else {
39346
39347								$(".fc-prev-button").removeClass('fc-state-disabled');
39348
39349								$(".fc-prev-button").prop('disabled', false);
39350
39351							}
39352
39353						},
39354
39355						eventClick: function(calEvent, jsEvent, view)
39356
39357						{
39358
39359
39360
39361							if($(this).find("span").css("display")=="inline")
39362
39363							{
39364
39365								//for pc
39366
39367								$(".fc-event-container").find(".fc-day-grid-event").each(function(index)
39368
39369								{
39370
39371									if(hexc($(this).css('backgroundColor'))=="#f28c26")
39372
39373									{
39374
39375										//reset all event
39376
39377										$(this).removeClass('selected');
39378
39379									}
39380
39381								});
39382
39383
39384
39385								if(hexc($(this).css('backgroundColor'))=="#ffffff")
39386
39387								{
39388
39389									$(this).addClass('selected');
39390
39391
39392
39393									selected_id = calEvent.id;
39394
39395								}
39396
39397
39398
39399
39400
39401							}else{
39402
39403
39404
39405								//for mobile
39406
39407								if(hexc($(this).css('backgroundColor'))=="#169cc2")
39408
39409								{
39410
39411									//reset all event
39412
39413									$(".fc-event-container").find(".fc-day-grid-event").each(function(index)
39414
39415									{
39416
39417										if(hexc($(this).css('backgroundColor'))=="#f28c26")
39418
39419										{
39420
39421											$(this).removeClass('selected');
39422
39423										}
39424
39425									});
39426
39427
39428
39429									getDateEventAndPopUp(calEvent, jsEvent, view);
39430
39431								}
39432
39433							}
39434
39435						}
39436
39437					});
39438
39439			});
39440
39441		});
39442
39443	};
39444
39445	YHA.INIT_FUNC[body_selector]['init-booking'] = function() {
39446
39447		// ***************************************************************************
39448
39449
39450
39451		//payment
39452
39453		$("#btn-payment").click(function()
39454
39455		{
39456
39457			//----------------------FOR PAYMENT GATE WAY
39458
39459			if(!submitting) {
39460
39461				submitting = true;
39462
39463				$paymentBtn.html('<span><i class="fa"></i><p><i>' + loading_txt_payment_btn + '</i></p></span>');
39464
39465				var postData = createPostData();
39466
39467				$.post(YHA.common.base_url + "/api/tour/submit_form", postData ,(function(response)
39468
39469				{
39470
39471					submitting = false;
39472
39473					$paymentBtn.html(original_txt_payment_btn);
39474
39475					if(response.status)
39476
39477					{
39478
39479						if(response.html) {
39480
39481							var hiddenForm = response.html;
39482
39483							$('#tour-booking-page').hide();
39484
39485							$('#payment-processing').show();
39486
39487							window.scrollTo(0,0);
39488
39489							$('.hidden-section').html(hiddenForm);
39490
39491						} else  {
39492
39493							window.location.replace(response.data.redirect_url);
39494
39495						}
39496
39497
39498
39499					} else {
39500
39501						var errorData = response.errors;
39502
39503						var allError = "";
39504
39505
39506
39507						for(var i in errorData)
39508
39509						{
39510
39511							allError = errorData[0]['msg']+'<br>';
39512
39513							break;
39514
39515						}
39516
39517
39518
39519						YHA.common.popupError(allError);
39520
39521					}
39522
39523
39524
39525				}), 'json');
39526
39527			}
39528
39529
39530
39531		});
39532
39533
39534
39535		//form submit
39536
39537		$("#btn-submit").click(function()
39538
39539		{
39540
39541			//check form-------
39542
39543
39544
39545			if (!submitting)
39546
39547			{
39548
39549				submitting = true;
39550
39551				$submitBtn.html('<span><i class="fa"></i><p><i>' + loading_txt_submit_btn + '</i></p></span>');
39552
39553				var postData = createPostData();
39554
39555				// console.log(postData);
39556
39557				input_result(
39558
39559					postData['contact_person'],
39560
39561					postData['title'],
39562
39563					postData['nationalityTxt'],
39564
39565					postData['memberRegistrationCountryTxt'],
39566
39567					postData['hkid'],
39568
39569					postData['contact'],
39570
39571					postData['email'],
39572
39573					postData['no_of_disabled_participants'],
39574
39575					$('input[name=member]:checked', '#member_choice').siblings('label').text(),
39576
39577					postData['member_id'],
39578
39579					postData['person']['number']
39580
39581				);
39582
39583				$.post(YHA.common.base_url + "/api/tour/validation", postData ,(function(response)
39584
39585					{
39586
39587						submitting = false;
39588
39589						$submitBtn.html(original_txt_submit_btn);
39590
39591						if(response.status)
39592
39593						{
39594
39595							nextStep();
39596
39597
39598
39599						} else {
39600
39601							var errorData = response.errors;
39602
39603							var allError = "";
39604
39605
39606
39607							for(var i in errorData)
39608
39609							{
39610
39611								allError = errorData[0]['msg']+'<br>';
39612
39613								break;
39614
39615							}
39616
39617
39618
39619							YHA.common.popupError(allError);
39620
39621						}
39622
39623
39624
39625					}), 'json');
39626
39627			}
39628
39629
39630
39631
39632
39633		});
39634
39635		// ***************************************************************************
39636
39637		function input_result(contact_person,title,nationality,memberRegistrationCountry, hkid,contact,mail,no_of_disabled_participants,member,member_id, now_person)
39638
39639		{
39640
39641			$("#result_contact_person").html(contact_person);
39642
39643			$("#result_title").html(title);
39644
39645			$("#result_nationality").html(nationality);
39646
39647			$("#result_member_registration_country").html(memberRegistrationCountry);
39648
39649
39650
39651			$("#result_contact").html(contact);
39652
39653
39654
39655			if(showPassport=="true")
39656
39657			{
39658
39659				$("#preview_hkid").css({"display":"block"});
39660
39661				$("#result_hkid").html(hkid);
39662
39663			} else {
39664
39665				$("#preview_hkid").css({"display":"none"});
39666
39667			}
39668
39669
39670
39671			if($('input[name=member]:checked').val() == '1')
39672
39673			{
39674
39675				$("#preview_member_id").show();
39676
39677				$('#preview_member_registration_country').show();
39678
39679				$("#result_member_id").html(member_id);
39680
39681			} else {
39682
39683				$("#preview_member_id").hide();
39684
39685				$('#preview_member_registration_country').hide();
39686
39687			}
39688
39689
39690
39691			$("#result_mail").html(mail);
39692
39693			$("#result_disable .result_value").html(no_of_disabled_participants);
39694
39695			$("#result_member").html(member);
39696
39697			$("#result_number").html(now_person);
39698
39699			// $("#result_quantity_num").html(quantity);
39700
39701
39702
39703			var person_detail = '';
39704
39705
39706
39707			//console.log("now_person:"+now_person);
39708
39709			if(activity_type === 'guided_tour') {
39710
39711                if(same_person)
39712
39713                {
39714
39715                    person_detail += '<div class="preview_item number_info"><div class="row collapse"><div class="title columns fontf-rs small-12 medium-3"></div><div class="content columns small-12 medium-9"><b>No. 1</b> '+contact_person+'</div></div></div>';
39716
39717
39718
39719                }else{
39720
39721                    person_detail += '<div class="preview_item number_info"><div class="row collapse"><div class="title columns fontf-rs small-12 medium-3"></div><div class="content columns small-12 medium-9"><b>No. 1</b> '+$("#person_1_input").val()+'</div></div></div>';
39722
39723                }
39724
39725
39726
39727                for(var i=1; i<parseInt(now_person);i++)
39728
39729                {
39730
39731                    var target = i+1;
39732
39733                    person_detail += '<div class="preview_item number_info"><div class="row collapse"><div class="title columns fontf-rs small-12 medium-3"></div><div class="content columns small-12 medium-9"><b>No. '+target+'</b> '+$("#person_"+target+"_input").val()+'</div></div></div>';
39734
39735
39736
39737                }
39738
39739			} else {
39740
39741                var totalParticipants = quantity;
39742
39743                for(var i = 1; i <= parseInt(totalParticipants); i++)
39744
39745                {
39746
39747                	var name = $("#person_" + i +"_name").val();
39748
39749                	if(activity_type === 'family') {
39750
39751                        var childAge = $("#person_" + i +"_children_age").val();
39752
39753                        var childName = $("#person_" + i +"_children_name").val();
39754
39755                        var personContent = name + '/' + childName + (childAge?'(' + childAge + ')':'');
39756
39757					} else {
39758
39759                        var age = $("#person_" + i +"_age").val();
39760
39761                        var hkid = $("#person_" + i +"_hkid").val();
39762
39763                        var personContent = name + (age?'(' + age + ')':'') + (hkid?' - ' + hkid:'');
39764
39765					}
39766
39767
39768
39769                    person_detail += '<div class="preview_item number_info"><div class="row collapse"><div class="title columns fontf-rs small-12 medium-3"></div><div class="content columns small-12 medium-9"><b>No. ' + i + '</b> ' + personContent + '</div></div></div>';
39770
39771
39772
39773                }
39774
39775			}
39776
39777
39778
39779
39780
39781			$("#person_container").html(person_detail);
39782
39783		}
39784
39785
39786
39787		function addPersonContent(index)
39788
39789		{
39790
39791			if(activity_type == 'guided_tour') {
39792
39793                return '<div class="row collapse detail_question" id="number_'+(index)+'_box"><div class="form_question form_text columns fontf-rs small-12 medium-2">No. '+(index)+'*</div><div class="columns small-12 medium-10"><input id="person_'+(index)+'_input" type="text" name="person"/></div></div>';
39794
39795			} else {
39796
39797				var html = $('#person-template').html();
39798
39799				var person_1_label = $('#person-template .form_question').text();
39800
39801				var newLabel = person_1_label.replace('1', index);
39802
39803                html = html.replace(person_1_label, newLabel);
39804
39805				html = html.replace(/number_1/g, 'number_'+index);
39806
39807                html = html.replace(/person_1/g, 'person_'+index);
39808
39809                // console.log(html);
39810
39811                return html;
39812
39813			}
39814
39815		}
39816
39817
39818
39819		$('input[type=radio][name=member]').change(function()
39820
39821		{
39822
39823            var numberOfHeads = quantity;
39824
39825			if(free=="false")
39826
39827			{
39828
39829				if (this.value == '1')
39830
39831				{
39832
39833					$("#result_total_price").html('HK$' + numberOfHeads * window.member_price);
39834
39835					$("#result_total").html('HK$' + numberOfHeads * window.member_price);
39836
39837				} else if (this.value == '0')
39838
39839				{
39840
39841					$("#result_total_price").html('HK$' + numberOfHeads * window.non_member_price);
39842
39843					$("#result_total").html('HK$' + numberOfHeads * window.non_member_price);
39844
39845				}
39846
39847			}
39848
39849			if($(this).val() == '1') {
39850
39851				$('#member_id').attr('disabled', false).focus();
39852
39853				$('#member_registration_country select').attr('disabled', false);
39854
39855			} else {
39856
39857				$('#member_id').val('').attr('disabled', true);
39858
39859				$('#member_registration_country select').val('').attr('disabled', true);
39860
39861			}
39862
39863		});
39864
39865
39866
39867		$("#quantity").change(function ()
39868
39869		{
39870
39871			resetTourData();
39872
39873			checkEventOnOff();
39874
39875			$( "#quantity option:selected" ).each(function()
39876
39877			{
39878
39879				quantity = parseInt($( this ).text());
39880
39881				$("#result_quantity").html(quantity);
39882
39883				if(window.non_member_price > 0) {
39884
39885					$("#result_total_price").html('HK$' + quantity * window.non_member_price);
39886
39887					$("#result_total").html('HK$' + quantity * window.non_member_price);
39888
39889				}
39890
39891				newCalendarData = initCalendarData(calendar_data, quantity);
39892
39893				calendar_oject.fullCalendar('removeEvents');
39894
39895				calendar_oject.fullCalendar('addEventSource', newCalendarData);
39896
39897				calendar_oject.fullCalendar('refetchEvents');
39898
39899
39900
39901				// add participants input
39902
39903				var num = parseInt($(this).text())-1;
39904
39905
39906
39907				$("#person_name_container").html("");
39908
39909
39910
39911				addPersonInput = "";
39912
39913
39914
39915				for(var i=0; i<num; i++)
39916
39917				{
39918
39919					addPersonInput += addPersonContent(i+2);
39920
39921				}
39922
39923
39924
39925				$("#person_name_container").html(addPersonInput);
39926
39927
39928
39929				// update no_of_disabled_participants
39930
39931
39932
39933				var html = '';
39934
39935				for(var i = 0; i <= quantity; i++)
39936
39937				{
39938
39939					html += '<option value="' + i + '">' + i + '</option>';
39940
39941				}
39942
39943				$('#no_of_disabled_participants').html(html);
39944
39945			});
39946
39947
39948
39949
39950
39951		});
39952
39953
39954
39955		//calendar btn
39956
39957		$("#btn-continuous").click(function()
39958
39959		{
39960
39961			//check selected tour------------
39962
39963			if(selected_id!="")
39964
39965			{
39966
39967                if($('#quantity').val() !="" || quantity > 0)
39968
39969                {
39970
39971                    nextStep();
39972
39973                }else{
39974
39975					if ($(this).data('tour_type')=='package') {
39976						if(lang === 'zh') {
39977							YHA.common.popupError('請選擇套餐數量');
39978						} else if (lang === 'sc') {
39979							YHA.common.popupError('请选择套餐数量');
39980						} else {
39981							YHA.common.popupError('Please choose No. of Package');
39982						}
39983					} else {
39984						if(lang === 'zh') {
39985
39986							YHA.common.popupError('請選擇參加人數');
39987
39988						} else if (lang === 'sc') {
39989
39990							YHA.common.popupError('请选择参加人数');
39991
39992						} else {
39993
39994							YHA.common.popupError('Please choose No. of Person');
39995
39996						}
39997                    }
39998
39999                }
40000
40001			}else{
40002				if ($(this).data('tour_type')=='package') {
40003					if(lang === 'zh') {
40004						YHA.common.popupError('請選擇入住日期');
40005					} else if (lang === 'sc') {
40006						YHA.common.popupError('请选择入住日期');
40007					} else {
40008						YHA.common.popupError('Please choose one check in date');
40009					}
40010				} else {
40011					if(lang === 'zh') {
40012						YHA.common.popupError('請選擇一個時段');
40013					} else if (lang === 'sc') {
40014						YHA.common.popupError('请选择一个时段');
40015					} else {
40016						YHA.common.popupError('Please select one timeslot');
40017					}
40018				}
40019
40020			}
40021
40022
40023
40024		});
40025
40026
40027
40028		$("#btn-reset").click(function()
40029
40030		{
40031
40032			$('#eventForm').trigger("reset");
40033
40034		});
40035
40036
40037
40038		//preview back btn
40039
40040		$("#btn-back").click(function()
40041
40042		{
40043
40044			prevStep();
40045
40046		});
40047
40048
40049
40050		$("#same_person_tickbox").click(function()
40051
40052		{
40053
40054			if($(this).hasClass("selected"))
40055
40056			{
40057
40058				same_person = false;
40059
40060				$("#person_1_input").prop("disabled", false);
40061
40062				$(this).removeClass("selected");
40063
40064			}else{
40065
40066				same_person = true;
40067
40068				$("#person_1_input").val($('#contact_person_input').val());
40069
40070				$("#person_1_input").prop("disabled", true);
40071
40072				$(this).addClass("selected");
40073
40074			}
40075
40076
40077
40078		});
40079
40080
40081
40082		//--------FLOW ------------------------------------
40083
40084
40085
40086		function nextStep()
40087
40088		{
40089
40090			var orgDiv = $("#"+stepContentArr[stepNow-1]);
40091
40092			var targetDiv = $("#"+stepContentArr[stepNow]);
40093
40094
40095
40096			orgDiv.stop().animate({"opacity":0},800,function()
40097
40098			{
40099
40100				orgDiv.css({"display":"none"});
40101
40102
40103
40104				stepNow += 1;
40105
40106
40107
40108				if(stepNow==2)
40109
40110				{
40111
40112					if(showPassport=="false")
40113
40114					{
40115
40116						$("#hkid_box").css({"display":"none"});
40117
40118					}else{
40119
40120						$("#hkid_box").css({"display":"block"});
40121
40122					}
40123
40124				}
40125
40126
40127
40128				window.scrollTo(0, 0);
40129
40130
40131
40132				targetDiv.css({"display":"block"});
40133
40134				targetDiv.stop().animate({"opacity":1},800);
40135
40136				goStep();
40137
40138			});
40139
40140
40141
40142
40143
40144		}
40145
40146
40147
40148		function prevStep()
40149
40150		{
40151
40152			var orgDiv = $("#"+stepContentArr[stepNow-1]);
40153
40154			var targetDiv = $("#"+stepContentArr[stepNow-2]);
40155
40156
40157
40158			orgDiv.stop().animate({"opacity":0},800,function()
40159
40160			{
40161
40162				orgDiv.css({"display":"none"});
40163
40164				stepNow -= 1;
40165
40166				window.scrollTo(0, 0);
40167
40168				targetDiv.css({"display":"block"});
40169
40170				targetDiv.stop().animate({"opacity":1},800);
40171
40172				goStep();
40173
40174			});
40175
40176		}
40177
40178
40179
40180
40181
40182		function goStep()
40183
40184		{
40185
40186			$(".stepWrapper").find(".step_holder").each(function(index)
40187
40188			{
40189
40190				var target = index+1;
40191
40192
40193
40194				if(stepNow==target)
40195
40196				{
40197
40198					$(this).find(".circle").addClass("selected");
40199
40200				}else{
40201
40202					$(this).find(".circle").removeClass("selected");
40203
40204				}
40205
40206
40207
40208				if( (stepNow==2 || stepNow==3) && target==2)
40209
40210				{
40211
40212					submitting = false;
40213
40214					$(this).find(".circle").addClass("selected");
40215
40216				}
40217
40218
40219
40220				if( (stepNow==3) && target==3)
40221
40222				{
40223
40224					$(this).find(".circle").removeClass("selected");
40225
40226				}
40227
40228
40229
40230
40231
40232			});
40233
40234		}
40235
40236
40237
40238		function initSection()
40239
40240		{
40241
40242			$("#"+stepContentArr[stepNow-1]).css({"display":"block"});
40243
40244			$("#"+stepContentArr[stepNow-1]).stop().animate({"opacity":1},800);
40245
40246
40247
40248			goStep();
40249
40250
40251
40252            $("#result_quantity").html(quantity);
40253
40254
40255
40256            if(window.non_member_price > 0) {
40257
40258                $("#result_total_price").html('HK$' + quantity * window.non_member_price);
40259
40260                $("#result_total").html('HK$' + quantity * window.non_member_price);
40261
40262            }
40263
40264		}
40265
40266
40267
40268		$('.stepWrapper .step_holder .circle').click(function(){
40269
40270			var targetStep = parseInt($(this).parent().attr('data-step'));
40271
40272			if(stepNow == (targetStep+1)) {
40273
40274				prevStep();
40275
40276			}
40277
40278		});
40279
40280		initSection();
40281
40282	};
40283
40284})(jQuery);
40285var YHA = YHA || {};
40286
40287
40288
40289(function($) {
40290
40291	var body_selector = ".page-tours",
40292
40293		$body_selector = $(".page-tours"),
40294
40295		$masonry = $body_selector.find(".masonryAreaWrapper"),
40296
40297		$no_record = $body_selector.find(".no_record"),
40298
40299		$loadMore = $body_selector.find(".loadWrapper .btn"),
40300
40301		txt1 = $loadMore.text(),
40302
40303		txt2 = $loadMore.attr("data-txt"),
40304
40305		loading = false,
40306
40307		xhr;
40308
40309
40310
40311	var page = 1, count = 1,currentOrderBy = 'tour_date', currentOrder = 'desc';
40312
40313
40314
40315	//INIT
40316
40317	YHA.INIT_FUNC = YHA.INIT_FUNC || {};
40318
40319	YHA.RESPON_FUNC = YHA.RESPON_FUNC || {};
40320
40321	YHA.INIT_FUNC[body_selector] = {};
40322
40323	YHA.RESPON_FUNC[body_selector] = {};
40324
40325
40326
40327	var delay = (function(){
40328
40329		var timer = 0;
40330
40331		return function(callback, ms){
40332
40333			clearTimeout (timer);
40334
40335			timer = setTimeout(callback, ms);
40336
40337		};
40338
40339	})();
40340
40341
40342
40343	function getTours() {
40344
40345		loading = true;
40346
40347
40348
40349		$loadMore.html('<i class="fa fa-refresh fa-spin"></i>&nbsp;' + txt2);
40350
40351
40352
40353		var query = {
40354
40355			'orderby' : currentOrderBy,
40356
40357			'order' : currentOrder,
40358
40359			'page' : page,
40360
40361			'count' : count
40362
40363		};
40364
40365
40366
40367		xhr = $.get(YHA.common.base_url + "/api/tour/get_tours/", query, function(response){
40368
40369			if(response.status)	{
40370
40371				if(response.data.length < 1 || response.data.length < count)
40372
40373					$loadMore.hide();
40374
40375				createBlocks(response.data);
40376
40377			}
40378
40379			$loadMore.text(txt1);
40380
40381			loading = false;
40382
40383
40384
40385			if (!$masonry.find(".article").length) {
40386
40387				$loadMore.hide();
40388
40389				$no_record.show();
40390
40391			}
40392
40393
40394
40395			xhr = (function() {return;})();
40396
40397		}, 'json');
40398
40399	}
40400
40401
40402
40403	function createBlocks(posts) {
40404
40405		var post;
40406
40407		for ( var i = 0, l = posts.length; i < l; i++ ) {
40408
40409			post = posts[i];
40410
40411			var $html = $('<div class="article">' +
40412
40413				'<a href="' + post.url + '">' +
40414
40415				(post.thumbnail != "" ? '<img src="' + post.thumbnail.url + '" alt="' + post.title + '" class="thumb" />' : '' ) +
40416
40417				'<img class="ribbon" src="' + YHA.common.template_url + '/images/' + YHA.common.lang + '/tab_' + post.tour_type.toLowerCase() + '.png"/>' +
40418
40419				'<div class="articleContent">' +
40420
40421				'<h4 class="title">' + post.title + '</h4>' +
40422
40423				'<span class="rightArrow"><i class="fa fa-arrow-right"></i></span>' +
40424
40425				'</div>' +
40426
40427				'</a>' +
40428
40429				'</div>');
40430
40431			$masonry.append($html).masonry("appended", $html);
40432
40433
40434
40435			$("<img />").attr("src", post.thumbnail.url).load(function() {
40436
40437				$masonry.masonry('layout');
40438
40439			});
40440
40441		}
40442
40443		$masonry.masonry('layout');
40444
40445	}
40446
40447
40448
40449	function changeOrderBy(sortBy)	{
40450
40451		if (typeof(xhr) !== "undefined")
40452
40453			xhr.abort();
40454
40455		loading = false;
40456
40457		$no_record.hide();
40458
40459		$loadMore.show();
40460
40461
40462
40463		var orderArray = sortBy.split(',');
40464
40465		currentOrderBy = orderArray[0];
40466
40467		currentOrder = orderArray[1];
40468
40469		page = 1;
40470
40471		$masonry.masonry('remove', $('.article')).masonry('layout');
40472
40473		getTours();
40474
40475	}
40476
40477
40478
40479	//INIT
40480
40481	YHA.INIT_FUNC[body_selector]['init'] = function(){
40482
40483		$(document).ready(function() {
40484
40485			$body_selector.find('.featured-tour-box').slick({
40486
40487				arrows: false,
40488
40489				dots: true,
40490
40491                adaptiveHeight: true
40492
40493			});
40494
40495		});
40496
40497		$body_selector.find("select[name=sortBy]").change(function() {
40498
40499			changeOrderBy($(this).val());
40500
40501		});
40502
40503		$loadMore.on("click", function(e)	{
40504
40505			e.preventDefault();
40506
40507			if(!loading) {
40508
40509				page++;
40510
40511				getTours();
40512
40513			}
40514
40515		});
40516
40517	};
40518
40519
40520
40521
40522
40523})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.