PageSourceSearch

https://takemypicture.com/_js/cargo.site.package.js?26.11.18.1

js takemypicture.com collected 2026-10-04 00:24:38 UTC 221,679 bytes, 7,276 lines download raw bytes

1/**
2*
3* @author: Cargo
4*
5**/
6var intransition =
7	soundDependenciesCalled =
8	start_sound = 
9	this_play = 
10	mouse_down = 
11	tool_over = 
12	timer =
13	lastT = 
14	viewport_threshold = false,
15	cycleTimeout  = new Array(),
16	cyclePause    = new Array(),
17	cycleComplete = new Array();
18
19/////////////////////////////////////////////////////////////////////////////////////////////////
20
21if (typeof (Cargo) === "undefined") {
22	Cargo = {};
23	// Legacy
24	//CARGO = Cargo;
25}
26
27// To use for global variables Cargo.Config.get('dispatch_url')
28Cargo.Config = {
29		'CARGO_URL'					: (/cargocollective.com/.test(document.location.host) || /persona.co/.test(document.location.host)) ? document.location.host :  'cargocollective.com',
30		'Print_Url'					: '',
31		'Admin_Print_Url'			: '',
32		'dispatch_url'				: 'dispatch.php',
33		'dispatch_prefix'			: 'dispatch/',
34		'project_single'			: '/entry-detail.php',
35		'custom_thumbsize_path'		: '/dispatch/user/saveCustomThumbPosition',
36		'css_inspector_position'	: '/dispatch/user/saveCssInspectorPosition',
37		'drag_drop_options'			: '/dispatch/user/saveDragDropOptions',
38		'get_drag_drop_options'		: '/dispatch/user/getDragDropOptions',
39		'save_edit_frame'			: '/dispatch/admin/saveEditContent_',
40		'save_syntax_color'			: '/dispatch/admin/toggleSyntaxColor',
41		'MAX_COMMENT_IMAGES'		: 10,
42		'CDN_CONTAINER_TEMPLATE'    : '//payload.cargocollective.com/',
43		'website_title'				: $("meta[name='cargo_title']").attr("content"),
44		'fourOfour'					: '/dispatch/user/user404',
45		'loading_animation'			: '<img src="/_gfx/loadingAnim.gif">',
46		
47		get : function(key, def) {
48			return this[key] ? this[key] : def;
49		},
50			
51		GetDesign : function() {
52			return $("#design").val();
53		},
54		
55		GetTemplate : function() {
56			return $("#template").val();
57		},
58		
59		GetCurrentPageType : function() {
60			var type = $(".entry").attr("page_type");
61			return (typeof type == "undefined") ? "none" : type;
62		},
63
64		GetCurrentPage : function() {
65			return $("#current_page").val();
66		},
67
68		GetTotalPages : function() {
69			return $("#total_pages").val();
70		},
71
72		GetPageLimit : function() {
73			return $("#page_limit").val();
74		},
75		
76		isIE : function() {
77			return (/MSIE (\d+\.\d+);/.test(navigator.userAgent));
78		},
79
80		isMobile : function() {
81			return (/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent));
82		},
83		
84		isIE8 : function() {
85			var rv = -1; // Return value assumes failure.
86			if (this.isIE())  {
87				var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
88				if (re.exec(navigator.userAgent) != null) rv = parseFloat( RegExp.$1 );
89			}
90			
91			return (rv < 9 && rv > 0) ? true : false;
92		},
93
94		isOldIE : function() {
95			var rv = -1; // Return value assumes failure.
96			if (this.isIE())  {
97				var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
98				if (re.exec(navigator.userAgent) != null) rv = parseFloat( RegExp.$1 );
99			}
100			
101			return (rv <= 9 && rv > 0) ? true : false;
102		},
103
104		SetCookieUrl : function(url) {
105			$.cookie('curl', url, {path: '/'});
106		},
107
108		GetCookieUrl : function() {
109			return $.cookie('curl');
110		},
111
112		SetCookieUid : function(uid) {
113			$.cookie('cuid', uid, {path: '/'});
114		},
115
116		GetCookieUid : function() {
117			return $.cookie('cuid');
118		},
119
120		GetUid : function() {
121			return $('#uid').val();
122		},
123		
124		/**
125		 *	Returns the width of the scrollbars
126		 *	Useful for checking for Lion webkit
127		 *	via http://www.fleegix.org/articles/2006-05-30-getting-the-scrollbar-width-in-pixels
128		 */
129		GetScrollBarWidth : function() { 
130			var scr = null;
131		    var inn = null;
132		    var wNoScroll = 0;
133		    var wScroll = 0;
134
135		    // Outer scrolling div
136		    scr = document.createElement('div');
137		    scr.style.position = 'absolute';
138		    scr.style.top = '-1000px';
139		    scr.style.left = '-1000px';
140		    scr.style.width = '100px';
141		    scr.style.height = '50px';
142		    // Start with no scrollbar
143		    scr.style.overflow = 'hidden';
144
145		    // Inner content div
146		    inn = document.createElement('div');
147		    inn.style.width = '100%';
148		    inn.style.height = '200px';
149
150		    // Put the inner div in the scrolling div
151		    scr.appendChild(inn);
152		    // Append the scrolling div to the doc
153		    document.body.appendChild(scr);
154
155		    // Width of the inner div sans scrollbar
156		    wNoScroll = inn.offsetWidth;
157		    // Add the scrollbar
158		    scr.style.overflow = 'auto';
159		    // Width of the inner div width scrollbar
160		    wScroll = inn.offsetWidth;
161
162		    // Remove the scrolling div from the doc
163		    document.body.removeChild(
164		        document.body.lastChild);
165
166		    // Pixel width of the scroller
167		    return (wNoScroll - wScroll);
168		}
169		
170}; // end config
171
172/**
173 *	Make a safe logging method
174 */
175Cargo.log = function(args) {
176	if (typeof console == 'undefined' || !window.console) {
177		return;
178	}
179	console.log(args);
180};
181
182
183/**
184 *	Location based lookups
185 *	eg. getting direct links, current domain, etc
186 */
187/* !Cargo.Location */
188Cargo.Location = {
189		GetDomain : function(no_trailing_slash) {
190        	var domain = document.location.protocol + "//" + location.hostname;
191        	return (!no_trailing_slash) ? domain+"/" : domain;
192		},
193			
194		GetCargoUrl : function() {
195        	var url  = ($("#url").val() == "") ? $('#follow_url').val() : $("#url").val();
196        	return url;
197		},
198
199		GetDomainOrUrl : function() {
200			if( this.IsCustomDomain() ) {
201				return this.GetCargoUrl();
202			} else {
203				var url = location.pathname.split("/")[1];
204				return (url == "gallery" || url == "selections") ? null : url;
205			}
206		},
207		
208		GetNetworkId : function() {
209			return ($("#nid").length > 0) ? $("#nid").val() : false;
210		},
211		
212		GetDirectLink : function( pid ) {
213			return $("directlink#dl_"+pid).attr("link");
214			// this.MakeDirectLink( location.pathname.replace( this.GetBaseUrl()+"/", "") );
215		},
216		
217		// Use this to get absolute paths
218		GetPathAbs : function( path_rel ) {
219			return this.GetDomain() + path_rel;
220		},
221		
222		/*
223		 *	Pass a url path in and create a direct link
224		 */
225		MakeDirectLink : function( purl ) {
226			var direct_link = this.GetDomain( true );
227			
228			if( !this.IsCustomDomain() ) {
229				direct_link += this.GetBaseUrl();
230			}
231			
232			if( purl ) {
233				return direct_link + "/" + purl;
234			 } else {
235			 	return direct_link;
236			 }
237		},	
238		
239		/*
240		 *	Helper method to retrieve the base URL
241		 *	Useful for domain vs cargo URL 
242		 *	Allows a modifier value to be given
243		 *		e.g. "following" for [cargourl]/following
244		 */
245		GetBaseUrl : function(modifier) {
246			modifier = (modifier) ? "/" + modifier : "";
247			
248			if( location.hostname.indexOf( Cargo.Config.get('CARGO_URL') ) >= 0 ) {
249				var return_url = "/" + Cargo.Location.GetCargoUrl() + modifier;
250				if( $("#follow_sort").length > 0 && $("#follow_sort").val() != "" ) {
251					/*
252					 * 	Because of following cookie memory, sometimes this URL could simply be /following
253					 * 	even if the sort is "all". Test for this case by sniffing the location.pathname
254					 */
255					var filter = "/"+$("#follow_sort").val()+"/";
256					if( location.pathname.indexOf( filter ) >= 0 && modifier == "following") {
257						return_url += "/"+$("#follow_sort").val();
258					}
259					
260				}
261				return return_url;
262				
263			} else {
264				return modifier;
265			}
266		},
267		
268		IsFollowing : function() {
269			return ($('#follow_url').val() || $("#follow_type").length > 0) ? true : false;
270		},
271
272		IsUserImageGallery : function() {
273			return ( location.pathname.indexOf("/images") >= 0 ) ? true : false;
274		},
275
276		IsHomepageGallery : function() {
277			return ( location.pathname.indexOf("/gallery") >= 0 ) ? true : false;
278		},
279
280		IsUserSelections : function() {
281			return ( location.pathname.indexOf("/selections") >= 0 ) ? true : false;
282		},
283			
284		IsCustomDomain : function() {
285			return ( location.hostname.indexOf( Cargo.Config.get('CARGO_URL') ) < 0 ) ? true : false;
286		},
287		
288		IsUserFilter : function() {
289			if( location.pathname.indexOf("filter/") >= 0 && $(".view_tag_info").length > 0 ) {
290				return true;
291			} else {
292				return false;
293			}
294		},
295		
296		GetUserFilter : function() {
297			if( this.IsUserFilter() ) {
298				return location.pathname.split("filter/")[1].split("/")[0];
299			} else {
300				return "";
301			}
302		},
303		
304		IsSoloLink : function() {
305			return ($("#is_solo").length > 0 && $("#is_solo").val() == "true") ? true : false;
306		},
307		
308		IsDirectLink : function() {
309			return ($("#is_direct").length > 0 && $("#is_direct").val() == "true") ? true : false;
310		},
311		
312		IsEditingProject : function() {
313			return !!( this.IsInAdmin() && this.IsDirectLink() );
314		},
315		
316		IsStartProject : function() {
317			if( 
318				$("#start_page").length > 0 && 
319				$("#start_page").val() != "none" && 
320				$("#current_open").val() == "none" && 
321				!Cargo.Location.IsUserFilter() &&
322				$("#entry_"+$("#start_page").val()).length > 0
323			) {
324				return true;
325			
326			} else {
327				return false;
328			}
329		},
330		
331		GetStartProjectPid : function() {
332			if( 
333				$("#start_page").length > 0 && 
334				$("#start_page").val() != "none"
335			) {
336				return $("#start_page").val();
337			} else {
338				return false;
339			}
340		},
341		
342		IsInAdmin : function() {
343			return ( location.pathname.indexOf("/adminedit") >= 0 ) ? true : false;
344		},
345		
346		IsFeedIndex : function() {
347			return ($(".index_view").length > 0) ? true : false;
348		},
349		
350		IsSearch : function() {
351			return ($('#search_form_results').length > 0) ? true : false;
352		},
353		
354		IsTraceMarks : function() {
355			return ($('tracemark_data').length > 0) ? true : false;
356		},
357		
358		IsNetwork : function() {
359			return ($('#nid').length > 0 && $("#template").val() == "network") ? true : false;
360		},
361		
362		IsNetworkMemberList : function() {
363			return ($('memberlist').length > 0) ? true : false;
364		},
365
366		IsInFrame : function() {
367			return (window.self !== window.top);
368		}
369}
370
371// Helper class for getting dispatch urls
372/* !Cargo.Dispatcher */
373Cargo.Dispatcher = {
374		// Path should be 'c/a'
375	GetUrl : function(path, g) {
376		if(typeof(g) == 'array' && g.length > 0) {
377			path += '/' + g.split('/');
378		}
379		return Cargo.Location.GetDomain() + Cargo.Config.get('dispatch_prefix') + path;
380	}
381};
382
383
384
385/**
386 *	Ajax methods
387 *	Standardixed ways to handle ajax
388 */
389/* !Cargo.Ajax */
390Cargo.Ajax = {
391	_is_init : false,
392	
393	Init : function() {
394		if(Cargo.Ajax._is_init == false) {
395			Cargo.Ajax._is_init = true;
396		
397			$(".ajax_post_form").live("keypress", function(e) {
398				if (e.keyCode == 13) {
399					$(".ajax_post", this).trigger("click");
400					return false;
401				}
402			});
403		
404			$(".ajax_post").live("click", function(elem) {
405				var container_selector = $(this).parents(".ajax_post_container");
406				var parent_form = $('form', container_selector);
407				var params      = parent_form.serialize(),
408					route       = parent_form.attr("action"),
409					identifier   = parent_form.find('input[name="identifier"]').val();
410
411				/* Trigger a before handler */
412				var handler_event_name = Cargo.Ajax.GetBeforeHandlerName(identifier);
413				$(document).trigger(handler_event_name, [container_selector]);
414			
415				$.post(route, params, function(data) {
416					var response_data = $.parseJSON(data);
417					/* Trigger a complete handler */
418					var handler_event_name = Cargo.Ajax.GetCompleteHandlerName(identifier);
419					$(document).trigger(handler_event_name, [container_selector, response_data]);
420				});
421			
422				return false;
423			});
424		
425			/* Ajax event handlers. custom-defined per ajax type */
426			Cargo.Ajax.BindBeforeHandler("promote_form", function(event, container_selector) {
427				$(container_selector)
428					.find('.ajax_post').hide();
429				$(container_selector)
430					.append('<div class="ajax_loading">'+Cargo.Config.loading_animation+'</div>');
431				Cargo.ReplaceLoadingAnims();
432			});
433			
434			Cargo.Ajax.BindCompleteHandler("promote_form", function(event, container_selector, response_data) {
435				if(response_data.error.length == 0) {
436					$(container_selector)
437						.find('.ajax_loading')
438						.remove();
439					$(container_selector)
440						.find('.ajax_post')
441						.show()
442						.text(response_data.jdata.ajax_post_val);
443					$(container_selector)
444						.find('input[name="action_type"]')
445						.val(response_data.jdata.action_type_val);
446				}
447			});
448		
449			/* handlers for password form */
450			Cargo.Ajax.BindBeforeHandler("password_form", function(event, container_selector) {
451				$("#password_protected_title").hide();
452				$(container_selector)
453					.find('.ajax_post').hide();
454				$('#ErrorMessage')
455					.html('<span class="ajax_loading2">'+Cargo.Config.loading_animation+'</span>');
456			});
457			Cargo.Ajax.BindCompleteHandler("password_form", function(event, container_selector, response_data) {
458				$(container_selector)
459					.find('.ajax_loading2')
460					.remove();
461				$(container_selector)
462					.find('.ajax_post')
463					.show();
464				if(response_data.error.length == 0) {
465					document.location.href = $(container_selector)
466						.find('input[name="TargetUrl"]')
467						.val();
468				} else {
469					$("#ErrorMessage").html(response_data.jdata.ErrorMessage);
470					// Hack for password protection
471					$("#password_protected_title").hide();
472					$(container_selector)
473						.find('input[name="user_password"]')
474						.val('');
475				}
476			});
477		
478		}
479		
480	},
481	
482	GetBeforeHandlerName : function(identifier) {
483		return 'ajax_' + identifier + '_before_handler';
484	},
485
486	GetCompleteHandlerName : function(identifier) {
487		return 'ajax_' + identifier + '_complete_handler';
488	},
489
490	BindBeforeHandler : function(identifier, func_closure) {
491		$(document).bind( Cargo.Ajax.GetBeforeHandlerName(identifier), func_closure );
492	},
493	
494	BindCompleteHandler : function(identifier, func_closure) {
495		$(document).bind( Cargo.Ajax.GetCompleteHandlerName(identifier), func_closure );
496	}
497	
498};
499
500/* !Cargo.GetContainerDomainByPid */
501Cargo.GetContainerDomainByPid = function(pid) {
502	// this code used to replace %s in the template by the partition number
503	// left in, in case this function is being used out-of-tree
504	return Cargo.Config.get('CDN_CONTAINER_TEMPLATE');
505};
506
507/**
508 *	Standardized auto pagination
509 * 	Usage
510 *
511 *	Cargo.AutoPagination.Init( {
512 *			"ajax_route" 		: "tracemark/loadTracemarks",
513 *			"more_load_handle"	: "#moreload",
514 *			"height_selector"   : function() { return Tracemark.GetShortestColumn(); }
515 *		});
516 */
517/* !Cargo.AutoPagination */
518Cargo.AutoPagination = {
519	Data : {
520		"should_paginate"	: true,
521		"is_updating"		: false,		// are we currently waiting on ajax?
522		"within_bounds"		: false,		// within the bounds of paginating?
523		"preload_distance"	: 1500,			// Distance before the end of the page to fire
524		"page"				: 0,			// Page count
525		"more_load_handle"	: "#moreload",	// Handler to show the loading message / attach new page
526		"ajax_route"		: "",			// Route for the ajax
527		"is_ajax"			: true,			// Is this cycle ajax loaded?
528		"height_selector"   : 'document',	// Can be dynamic: function() { return getSelector(); }
529		"limit"				: 80,			// If we are using offset, and not page, use this value
530		"offset"			: 0				// If we are not using page, then use offset based on page
531	},
532	/*
533	 *	Initialize by setting defaults and binding the scroll event
534	 */
535	Init : function( settings ) {
536		this.Data.should_paginate = true;
537
538		// Make sure we are not in the middle of an update before re-init
539		if(this.Data.is_updating) {
540			setTimeout(function() {
541				Cargo.AutoPagination.Init(settings);
542			}, 100);
543		} else {
544			// Loop through the default settings and set them
545			for(key in settings) {
546				this.Data[key] = settings[key];
547			}
548			
549			// Bind the scroll
550			$(window).bind("scroll", function(event) {
551				Cargo.AutoPagination.CheckPageHeight(event);
552			});
553		}
554
555	},
556
557
558	End : function() {
559		this.Data.should_paginate = false;
560		this.Data.is_updating = false;
561		$(document).trigger("paginationDone");
562	},
563
564	/*
565	 *	Checks if we are within bounds of paginating
566	 */
567	CheckPageHeight : function() {
568		if (this.Data.should_paginate === false) {
569			return;
570		}
571
572		// Check to see if the selector is a function or a string
573		var selector = (typeof this.Data.height_selector == "function") ? this.Data.height_selector() : this.Data.height_selector;
574		
575		var window_scroll = $(window).scrollTop()+$(window).height();
576		var document_size = $(selector).height()-this.Data.preload_distance;
577
578		this.Data.within_bounds = ( window_scroll >= document_size ) ? true : false;
579		
580		if (this.Data.within_bounds && !this.Data.is_updating) {
581			this.Paginate();
582		}
583	
584	},
585	
586	/*
587	 *	Paginates
588	 */
589	Paginate : function() {
590		this.Data.is_updating = true;
591		$(this.Data.more_load_handle).show(); // Show the handler
592		Cargo.ReplaceLoadingAnims($(this.Data.more_load_handle).find('img'));
593		this.Data.page++; 					  // up the page count
594		
595		this.Data.offset = this.Data.page * this.Data.limit;
596		$.post( 
597			Cargo.Dispatcher.GetUrl(this.Data.ajax_route), 
598			Cargo.AutoPagination.Data, 
599			function(data) { Cargo.AutoPagination.PaginateCallback(data) }
600		);
601		
602		$(document).trigger("paginationStart", [ (this.Data.page) ]);
603	},
604	
605	/**
606	 *	Pagination callback varibale
607	 */
608	PaginateCallback : function(dataObj) {
609		var jdata = $.parseJSON(dataObj);
610
611		$(this.Data.more_load_handle).hide();
612
613		// Prevent further pagination attempts
614		if ((typeof jdata.jdata.end_pagination !== 'undefined') && (jdata.jdata.end_pagination === true)) {
615			this.End();
616		}
617
618		if(jdata.error != "" || jdata.html == "") {
619			// This is probably a blank value
620			// Do nothing, stop paginating
621			
622		} else {
623			$(this.Data.more_load_handle).before( jdata.html );
624			this.Data.is_updating = false;
625		}
626
627		
628		$(document).trigger("paginationComplete", [ (this.Data.page+1) ]);
629		
630	}
631}
632	
633	// A lazy loader of sorts
634Cargo.loaded_scripts = [];
635	
636Cargo.require_once = function(url) {
637		url = url.toLowerCase();
638		// Check if its in our array
639		if(jQuery.inArray(url, this.loaded_scripts) >= 0) {
640			return;
641		}
642		// Check if its in the head (ie not loaded with this script)
643		var already_loaded = false;
644		$('script').each(function() {
645			var src = $(this).attr('src');
646		    if(src) {
647				src = src.toLowerCase();
648		        if(src.search(url) >= 0) {
649					Cargo.loaded_scripts.push(url);
650					already_loaded = true;
651					return false;
652				}
653		    }
654		});
655		// load it
656		if(already_loaded == false) {
657			addScript(url);
658			this.loaded_scripts.push(url);
659		}
660		return;
661}
662
663	
664/**
665 *	Cargo javascript router
666 *	Has a list of routes
667 *	Loads data based on route
668 */
669/* !Cargo.Router */
670Cargo.Router = {
671		/**
672		 *	Routes for sites
673		 *	Each route requires a regex
674		 *	The regex will assume the base URL has 
675		 * 		been stripped (do not include Cargo/url)
676		 *	The result must be formatted like a value set
677		 *		these values will be set using eval()
678		 *		they are separated by lines for legibility using \
679		 *	Additionally, a conditional must be met
680		 *		Because routes often look the same, 
681		 *		we must meet a conditional to prove the page
682		 *	  - A value of true means no conditional (true will always pass)
683		 *	Finally, the action is set on what to do
684		 *		Options include "home", "close" and "load"
685		 *		Cargo.History.HomePopstate()  // user/network/following landing page
686		 *		Cargo.History.ClosePopstate() // close any open projects. Similar to home
687		 *		Projects.LoadProject() 		  // load any project or page
688		 */
689		/* !Routes */
690		"Routes" : {
691			/*
692			 *	Network
693			 */
694			"network_filter_project" : {
695				"regex" 		: "^\/filter\/([^\/]*)\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
696				"result"		: '	Projects.Data.network_filter="$1"; \
697									Projects.Data.user_url="$2"; \
698									Projects.Data.purl="$3"; \
699									Projects.Data.network_url=$("#url").val();',
700				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
701				"action"		: "Projects.LoadProject();"
702				// /filter/sound/richard/13278
703			},
704			
705			"network_filter_page" : {
706				"regex" 		: "^\/filter\/([^\/]*)\/([a-zA-Z0-9._-]+)$",
707				"result"		: '	Projects.Data.network_filter="$1"; \
708									Projects.Data.purl="$2"; \
709									Projects.Data.user_url=$("#url").val(); \
710									Projects.Data.network_url=$("#url").val();',
711				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
712				"action"		: "Projects.LoadProject();"
713				// /filter/sound/About-this-project
714			},
715			
716			"network_filter" : {
717				"regex" 		: "^\/filter\/([^\/]*)$",
718				"result"		: 'Projects.Data.network_filter="$1";',
719				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
720				"action"		: "Cargo.History.ClosePopstate();"
721				// /filter/sound
722			},
723			
724			"network_sort_project" : {
725				"regex" 		: "^\/display\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
726				"result"		: '	Projects.Data.network_sort="$1"; \
727									Projects.Data.user_url="$2"; \
728									Projects.Data.purl="$3"; \
729									Projects.Data.network_url=$("#url").val();',
730				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
731				"action"		: "Projects.LoadProject();"
732				// /display/mycomments/richard/Untitled-project
733			},
734			
735			"network_sort_page" : {
736				"regex" 		: "^\/display\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
737				"result"		: '	Projects.Data.network_sort="$1"; \
738									Projects.Data.purl="$2"; \
739									Projects.Data.user_url=$("#url").val(); \
740									Projects.Data.network_url=$("#url").val();',
741				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
742				"action"		: "Projects.LoadProject();"
743				// /display/mycomments/About-this-project
744			},
745			
746			"network_sort" : {
747				"regex" 		: "^\/display\/([a-zA-Z0-9._-]+)$",
748				"result"		: '	Projects.Data.network_sort="$1"; \
749									Projects.Data.network_url=$("#url").val();',
750				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
751				"action"		: "Cargo.History.ClosePopstate();"
752				// /display/mycomments
753			},
754			
755			"network_adminedit" : {
756				"regex" 		: "\/adminedit$",
757				"result"		: "",
758				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
759				"action"		: ""
760				// /adminedit
761			},
762			
763			"network_project" : {
764				"regex" 		: "^\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
765				"result"		: '	Projects.Data.user_url="$1"; \
766									Projects.Data.purl="$2"; \
767									Projects.Data.network_url=$("#url").val();',
768				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
769				"action"		: "Projects.LoadProject();"
770				// /richard/Photo-Koto
771			},
772			
773			"network_page" : {
774				"regex" 		: "^\/([a-zA-Z0-9._-]+)$",
775				"result"		: '	Projects.Data.purl="$1"; \
776									Projects.Data.nurl=$("#url").val(); \
777									Projects.Data.network_url=$("#url").val();',
778				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
779				"action"		: "Projects.LoadProject();"
780				// /About-this-project
781			},
782			
783			"network_home" : {
784				"regex" 		: "",
785				"result"		: 'Projects.Data.network_url=$("#url").val();',
786				"conditional" 	: '$("#nuid").length > 0 && $("#follow_sort").length <= 0',
787				"action"		: "Cargo.History.HomePopstate();"
788				// /
789			},
790			
791			/*
792			 *	Following
793			 */
794			 "following_project_comments" : {
795				"regex" 		: "^\/following\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\/comments$",
796				"result"		: '	Projects.Data.user_url="$1"; \
797									Projects.Data.purl="$2"; \
798									Projects.Data.attr="comments";',
799				"conditional" 	: '$("#follow_sort").length > 0',
800				"action"		: "Projects.LoadProject();"
801				 //following/Tapisteries-recentes/comments
802			},
803			
804			"following_sort_project_comments" : {
805				"regex" 		: "^\/following\/([a-zA-Z]+)\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)\/comments$",
806				"result"		: '	Projects.Data.follow_sort="$1"; \
807									Projects.Data.user_url="$2"; \
808									Projects.Data.purl="$3"; \
809									Projects.Data.attr="comments";',
810				"conditional" 	: '$("#follow_sort").length > 0',
811				"action"		: "Projects.LoadProject();"
812				 //following/postswithcomments/mondiran/Tapisteries-recentes/comments
813			},
814				
815			"following_sort_project" : {
816				"regex" 		: "^\/following\/([a-zA-Z]+)\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
817				"result"		: '	Projects.Data.follow_sort="$1"; \
818									Projects.Data.user_url="$2"; \
819									Projects.Data.purl="$3";',
820				"conditional" 	: '$("#follow_sort").length > 0',
821				"action"		: "Projects.LoadProject();"
822				// /following/postswithcomments/mondrian/Self-portrait
823			},
824			
825			"following_project" : {
826				"regex" 		: "^\/following\/([a-zA-Z0-9._-]+)\/([a-zA-Z0-9._-]+)$",
827				"result"		: '	Projects.Data.user_url="$1"; \
828									Projects.Data.purl="$2";',
829				"conditional" 	: '$("#follow_sort").length > 0',
830				"action"		: "Projects.LoadProject();"
831				// /following/mondrian/Self-portrait
832			},
833			
834			"following_sort" : {
835				"regex" 		: "^\/following\/([a-zA-Z0-9._-]+)$",
836				"result"		: 'Projects.Data.follow_sort="$1";',
837				"conditional" 	: '$("#follow_sort").length > 0',
838				"action"		: "Cargo.History.ClosePopstate();"
839				// /following/postswithcomments
840			},
841			
842			
843			"following" : {
844				"regex" 		: "^\/following$",
845				"result"		: "",
846				"conditional" 	: '$("#follow_sort").length > 0',
847				"action"		: "Cargo.History.HomePopstate();"
848				// /following
849			},
850			
851			/*
852			 *	User
853			 */
854			"user_filter_project" : {
855				"regex" 		: "^\/filter\/([^\/]*)\/([a-zA-Z0-9._-]+)$",
856				"result"		: '	Projects.Data.user_filter="$1"; \
857									Projects.Data.purl="$2";',
858				"conditional" 	: '$("#url").length > 0',
859				"action"		: "Projects.LoadProject();"
860				// /filter/oil-on-canvas/Sidney-Janis-Gallery
861			},
862			
863			"user_filter" : {
864				"regex" 		: "^\/filter\/([^\/]*)$",
865				"result"		: 'Projects.Data.user_filter="$1";',
866				"conditional" 	: '$("#url").length > 0',
867				"action"		: "Cargo.History.ClosePopstate();"
868				// /filter/oil-on-canvas
869			},
870
871			"user_preview" : {
872				"regex" 		: "\/preview\/(html|css)$",
873				"result"		: '',
874				"conditional" 	: '$("#url").length > 0',
875				"action"		: "Cargo.History.HomePopstate();"
876				// /preview/html
877			},
878			
879			"sc_user_adminedit" : {
880				"regex" 		: "^\/([a-zA-Z0-9._-]+)\/adminedit$",
881				"result"		: 'Projects.Data.purl="$1";',
882				"conditional" 	: '($("#url").length > 0 && $("#template").val() == "spacecollective")',
883				"action"		: "Projects.LoadProject();"
884				// /adminedit (only for SpaceCollective designs)
885			},
886			
887			"user_adminedit" : {
888				"regex" 		: "\/adminedit$",
889				"result"		: "",
890				"conditional" 	: '$("#url").length > 0',
891				"action"		: ""
892				// /adminedit
893			},
894			
895			"user_project" : {
896				"regex" 		: "^\/([a-zA-Z0-9._-]+)$",
897				"result"		: 'Projects.Data.purl="$1";',
898				"conditional" 	: '$("#url").length > 0',
899				"action"		: "Projects.LoadProject();"
900				// /Tapisteries-recentes
901			},
902			
903			"user_solo" : {
904				"regex" 		: "^(.*)\/solo$",
905				"result"		: "",
906				"conditional" 	: '$("#url").length > 0',
907				"action"		: "false"
908				// /Tapisteries-recentes/solo
909				// Do nothing, php has already done it's job
910			},
911			
912			"user_home" : {
913				"regex" 		: "",
914				"result"		: "",
915				"conditional" 	: '$("#url").length > 0',
916				"action"		: "Cargo.History.HomePopstate();"
917				// /
918			}
919		},
920		
921		/**
922		 *	Take in a route from History.RunRoute
923		 *	Strip the route of it's base URL
924		 *	Loop through the routes list to find a match
925		 *	Load the data based on route
926		 *	Return;
927		 */
928		LoadRoute : function( route ) {
929			// Remove the base URL from the route
930			route = route.replace( new RegExp( Cargo.Location.GetBaseUrl(), "i" ), "");
931
932			for(key in this.Routes) {
933				// Evaluate the conditional to make sure it matches
934				if( eval(this.Routes[key]["conditional"]) ) {
935					var expression = new RegExp( this.Routes[key]["regex"] );
936					
937					// Test the expression to see if we have a match
938					if( expression.test(route) ) {
939						// Match found, set the result and return
940						var result = route.replace(expression, this.Routes[key]["result"]);
941						
942						/* If there are still slashes in the result, 
943						 * we've either failed to find a route,
944						 * or we've found a false positive  */
945						if(result.indexOf("/") >= 0 && result.length > 1 && key != "network_home") { 
946							//Projects.Render404();
947							/*
948							if( window.console && window.Cargo.log ) {
949								Cargo.log("404 — Route: "+route+" — result: "+result+" — action: "+this.Routes[key]["action"]+" — key: "+key);
950							}
951							*/
952							// Cargo.log("Found dead route");
953							return;
954							
955						} else if(result.length > 1 || key == "network_home") {
956							// Strip a slash if there is one
957							result = result.replace('/', '');
958							try {
959								$.globalEval( result );
960							
961							} catch(err) {
962								/*
963								if( window.console && window.Cargo.log ) {
964									Cargo.log("Error loading route: "+err);
965								}
966								*/
967							}
968						}
969						
970						break;
971					}
972				}
973			}
974			
975			// Cargo.log("Route: "+route+" -- Found route: "+key+" -- Action: "+this.Routes[key]["action"]);
976			
977			// Perform the action
978			$.globalEval( this.Routes[key]["action"] );
979			
980		}
981}; // End Router 
982	
983/**
984 *	Create an object for getting and setting history
985 */
986/* !Cargo.History */
987Cargo.History = {
988	
989		"LastPayload" : "",
990		
991		"FirstLoad"	  : true,
992		
993		// If there is a hash link pasted in, this is the pid
994		"HashPID" : "",
995		
996		/*	Return a class based on the key
997		 * 	Example: key = Photography-project
998		 *	returns: jQuery object of the clicked <a> tag
999		 *
1000		 *	@author: Cargo
1001		 */
1002		Get : function(key) {
1003			if(key) {
1004				return this[key.toLowerCase()] ? this[key.toLowerCase()] : false;
1005			}
1006		},
1007		
1008		/*
1009		 *	Set a single property
1010		 */
1011		Set : function(key, value) {
1012			this[key.toLowerCase()] = value;
1013		},
1014		
1015		/*
1016		 *	Returns a pid based on a purl
1017		 *	Used in history
1018		 *	Example: key = My-Project-1
1019		 *	Returns: 12345
1020		 */
1021		GetPidFromPurl : function(purl) {
1022			var link_Obj = Cargo.History.Get(purl),
1023				// Strip out the Cargo/url
1024				purl = purl.replace(/\/\S*\//g,''),
1025				// Could be pid, check if it is numeric
1026				pid_return = (/^\d+$/.test(purl)) ? purl : false,
1027				pid = (link_Obj) ? $(link_Obj).attr("id").replace("p","") : pid_return;
1028				
1029				/*
1030				 * 	If the pid was not found in any link on the page
1031				 *	BUT the pid was found in an incoming hash, use that
1032				 */
1033				if(pid === false && Cargo.History.HashPID != "") {
1034					pid = Cargo.History.HashPID;
1035					Cargo.History.HashPID = "";
1036				}
1037				
1038				// Set the global pid
1039				Projects.Data.pid = pid;
1040		},
1041		
1042		/*
1043		 *	Returns a purl based on the pid
1044		 *	Used in next / prev project
1045		 *	Example: pid = 12345
1046		 *	Return: My-Project-1
1047		 */
1048		GetPurlFromPid : function(pid) {
1049			for(key in this) {
1050				if(typeof this[key] != "function" && key != "LastPayload" && key != "FirstLoad" && 
1050key != "HashPID") {
1051					var thispid = $(this[key]).attr("id").replace("p","");
1052					if(thispid == pid) {
1053						return key.toLowerCase();
1054					}
1055				}
1056			}
1057			
1058			// If we made it this far, then we need to paginate
1059			if( typeof getMoreHistory == "function" ) {
1060				getMoreHistory();
1061			}
1062			
1063			// No purl was found, let's build one
1064			return Cargo.Location.GetBaseUrl() + "/" + pid;
1065		},
1066		
1067		/**
1068		 *	Creates a URL to be inserted into the history link
1069		 *	Checks for filters	
1070		 */
1071		MakeLink : function(base_href, this_item) {
1072			var href = "",
1073				hash = "";
1074				
1075			// Following
1076			if( Cargo.Location.IsFollowing() ) {
1077				// Strip the base out of the following
1078				base_href = base_href.replace( Cargo.Location.GetBaseUrl("following"), "");
1079				
1080				// Check the base URL, remove the filter (because the following may not have the filter)
1081				var base_follow_url = Cargo.Location.GetBaseUrl();
1082					base_follow_url = base_follow_url.replace(this.GetFollowingFilter(), "");
1083				
1084				// Rebuild a clean link
1085				href = hash = base_follow_url + "/following" + this.GetFollowingFilter() + base_href;
1086				
1087				if ( !Cargo.History.SupportSlashHistory() ) {
1088					// With old browsers, just push the project name
1089					hash = stripLeadingSlash( base_href );
1090				}
1091			
1092			
1093			// User
1094			} else {
1095				// Strip the Cargo/url out
1096				base_href = base_href.replace( new RegExp( Cargo.Location.GetBaseUrl(), "i" ), "");
1097				
1098				// Strip the custom domain out
1099				base_href = base_href.replace( Cargo.Location.GetDomain(), "/");
1100				
1101				// Check if there is a network filter, if so use that. Otherwise, use user filter
1102				var filter = ( this.GetNetworkSorting() ) ? this.GetNetworkSorting() : this.GetUserFilter();
1103				
1104				// If the filter is already in the link, the link is already made
1105				if( base_href.indexOf(filter) >= 0 ) {
1106					href = hash = Cargo.Location.GetBaseUrl() + base_href;
1107				} else {
1108					// Rebuild the entire path
1109					href = hash = Cargo.Location.GetBaseUrl() + filter + base_href;
1110				}
1111								
1112				if ( !Cargo.History.SupportSlashHistory() ) {
1113					// With old browsers, just push the project name
1114					hash = stripLeadingSlash( base_href );
1115					
1116				}
1117			}
1118			
1119			/*
1120			 *	If a jQuery object for "this_item" exists:
1121			 *	Set the value of the link. Change the href and add the "hash" data
1122			 */
1123			if(this_item) {
1124				$(this_item).attr("href", href).data("hash", hash);
1125			
1126			/*
1127			 *	If this is not passed, return the hash value
1128			 */
1129			} else {
1130				return hash;
1131			}
1132		},
1133					
1134		/**
1135		 *	Checks if there is a filter on following pages
1136		 */
1137		IsFollowingFilter : function(url) {
1138			if(url) {
1139				url = url.replace(Cargo.Location.GetBaseUrl("following"), "").split("/").splice(1);
1140				return (url.length >= 2) ? false : true;
1141			}
1142		},
1143		
1144		/**
1145		 *	Checks if there is a filter on following pages
1146		 */
1147		GetFollowingFilter : function() {
1148			var filter = "/"+$("#follow_sort").val();
1149			// If the filter is in the URL path (sometimes it is not due to following memory)
1150			return ( location.pathname.indexOf(filter) > 0 ) ? filter : "";
1151
1152		},
1153		
1154		/**
1155		 *	Returns the network's filter
1156		 */
1157		GetNetworkFilter : function() {
1158			var pathname = location.pathname
1159							.replace(Cargo.Location.GetBaseUrl(), "")
1160							.split("/")
1161							.splice(1);
1162			if(
1163				pathname.length >= 2 && 
1164				pathname[0] == "filter" &&
1165				$("#nuid").length > 0
1166			) {
1167				return "/" + pathname[0] + "/" + pathname[1];
1168			
1169			} else {
1170				return "";
1171			}
1172		},
1173		
1174		/**
1175		 *	Check if this is a network or not
1176		 *	returns true || false
1177		 */
1178		IsNetwork : function() {
1179			return ($("#nuid").length > 0) ? true : false;
1180		},
1181		
1182		
1183		/**
1184		 *	Returns the network's sorting display
1185		 */
1186		GetNetworkSorting : function() {
1187			var pathname = location.pathname
1188							.replace(Cargo.Location.GetBaseUrl(), "")
1189							.split("/")
1190							.splice(1);
1191			if(
1192				pathname.length >= 2 && 
1193				pathname[0] == "display" &&
1194				$("#nuid").length > 0
1195			) {
1196				return "/" + pathname[0] + "/" + pathname[1];
1197			
1198			} else {
1199				return "";
1200			}
1201		},
1202		
1203		/**
1204		 *	Returns the user filter
1205		 */
1206		GetUserFilter : function() {
1207			var pathname = location.pathname
1208							.replace(Cargo.Location.GetBaseUrl(), "")
1209							.split("/")
1210							.splice(1);
1211			if(pathname.length >= 2 && pathname[0] == "filter") {
1212				return "/" + pathname[0] + "/" + pathname[1];
1213			
1214			} else {
1215				return "";
1216			}
1217		},
1218		
1219		
1220		/*
1221		 *	Checks if this browser supports HTML5 history pushing
1222		 *	Returns true || false
1223		 */
1224		SupportSlashHistory : function() {
1225			//return false;
1226			return !!(window.history && (typeof window.history.pushState != "undefined"));
1227		},
1228		
1229		
1230		/*
1231		 *	Pushes a location into history
1232		 *	Conditional on browser support
1233		 *	Can be manually called, or is bound to the click
1234		 *	e.g. next/prev links
1235		 */
1236		Load : function(url, title) {
1237			//Cargo.log("URL: "+url);
1238			
1239			if ( Cargo.History.SupportSlashHistory() ) {
1240				if( url.indexOf("index.php") < 0 ) {
1241					// Don't load a php file
1242					window.history.pushState({}, title, url);
1243					// Run this route
1244					Cargo.History.RunRoute(url);
1245				} 
1246			
1247			} else {
1248				// Does not support slash history	
1249				$.history.load( url );
1250			}
1251
1252			
1253		},
1254		
1255		/*	
1256		 *	Unloads the last history item
1257		 *	Useful when closing a project
1258		 *		or when you've reached the end of your history
1259		 *	Set's the "unloading" var to prevent start page re-open
1260		 */
1261		Unload : function(title) {
1262			// Prevent start re-open
1263			Projects.Data.unloading = true;
1264			
1265			if ( Cargo.History.SupportSlashHistory() ) {
1266				// For custom domains, load a / as index
1267				if( Cargo.Location.IsCustomDomain() ) {
1268					this.Load( this.MakeLink("/") );
1269				
1270				} else {
1271					this.Load( this.MakeLink("") );
1272				}
1273				
1274				
1275			} else {
1276				$.history.load( "#" );
1277			}
1278			
1279			this.SetLastPayload("");
1280			
1281			// Set the title
1282			Cargo.History.SetWindowTitle(true);
1283		},
1284		
1285		/*
1286		 *	Set the last loaded URL
1287		 */
1288		SetLastPayload : function(url) {
1289			this.LastPayload = url;
1290		},
1291		
1292		/*
1293		 *	Check the last laoded URL
1294		 */
1295		CheckLastPayload : function(url) {
1296			return !!(this.LastPayload != url);
1297		},
1298		
1299		
1300		/**
1301		 *	Get the uri based on the location
1302		 *	Determines what the URL to load will be		 
1303		 *	This method is called by the RunRoute function
1304		 */
1305		GetUriFromLocation : function() {
1306			var url = location.pathname;
1307			
1308			// Slash link
1309			if( Cargo.History.SupportSlashHistory() ) {
1310				// Sanitize the trailing slash
1311				return stripTrailingSlash( url );
1312				
1313				
1314			// hash link
1315			} else if( location.hash != "" && !Cargo.History.SupportSlashHistory() ) {
1316				var split_link = location.hash.split("/");
1317				
1318				// Check if there is a pid in this string (old URL)
1319				if(parseInt( split_link[0].replace("#","") ) ) {
1320					// This URL looks like: #1234/Title
1321					url = "/"+split_link[1];
1322					
1323				} else {
1324					url = location.hash;
1325				}
1326				
1327				return url;
1328			}
1329		},
1330		
1331		/*
1332		 *	This function runs the route that was found by the router
1333		 *	This is only for HTML5 history, RunRouteHash is for old browsers
1334		 */
1335		RunRoute : function(route) {
1336			// If we made it here with a hash in the URL, redirect to the slash URL
1337			if(location.hash != "" && Cargo.History.SupportSlashHistory() ) {
1338				// Redirect the hash link to slash link
1339				this.HashToSlash();
1340				return false;
1341			}
1342			
1343			// Take the incoming route and remove the trailing slash
1344			route = stripTrailingSlash( route );
1345			
1346			/*
1347			 *	Check last payload, don't allow a double load
1348			 */
1349			if(this.CheckLastPayload( route ) === false) {
1350				// Scroll to the top
1351				Projects.Helper.ScrollToTop();
1352				return;	
1353			} 
1354			
1355			/*
1356			 *	If no route is passed, it could be a direct link
1357			 *	Figure out what that link is
1358			 */
1359			if(!route) {
1360				route = this.GetUriFromLocation();
1361			}
1362			
1363			// Remember the latest URL to prevent double loads
1364			this.SetLastPayload( route );
1365			
1366			// Get the PID for this project project
1367			Cargo.History.GetPidFromPurl( route );
1368			
1369			/*
1370			 *	Make sure we're not on homepage and there is a start project open
1371			 *	Compare the base URL to the path in the location bar
1372			 *	If that is home + there is something already loaded, don't load this route
1373			 *	Also checks if there is a project already open, to prevent double opens
1374			 */
1375			if( 
1376				( ( location.pathname == Cargo.Location.GetBaseUrl() || location.pathname == "/" ) &&
1377				  $("#start_page").length > 0 && $("#start_page").val() != "none" &&
1378				  $("#entry_"+$("#start_page").val()).length > 0 )
1379				||
1380				( (location.pathname == Cargo.Location.GetBaseUrl() || location.pathname == "/" ) &&
1381					Cargo.Config.GetTemplate() == "spacecollective" && this.FirstLoad
1382					&& ($("#start_page").length == 0 || $("#start_page").val() == "none")
1383				)
1384				||
1385					$("#entry_"+Projects.Data.pid).length > 0
1386				||
1387					route.indexOf("index.php") >= 0
1388			  )  {
1389				
1390				// Do nothing
1391				
1392			} else {
1393				// Load from the Router
1394				Cargo.Router.LoadRoute( route );
1395			}
1396						
1397			// Make sure this posts back
1398			if(this.notify) this.notify( route );
1399			
1400			
1401			this.FirstLoad = false;
1402			
1403		},
1404		
1405		
1406		/*
1407		 *	This method is not using the router
1408		 *	It grabs the #hash value and figures out where to go from there
1409		 */
1410		RunRouteHash : function(url, firstload) {
1411			url = stripTrailingSlash( url );
1412			
1413			// Don't allow homestate
1414			if(url && (url == "#" || url == "") ) {
1415				return;
1416			}
1417			
1418			/*
1419			 *	Check last payload, don't allow a double load
1420			 */
1421			if(this.CheckLastPayload(url) === false) {
1422				return;	
1423			} 
1424			
1425			/*
1426			 *	If no URL is passed, it could be a direct link
1427			 *	Figure out what that link is
1428			 */
1429			if(!url) {
1430				url = this.GetUriFromLocation();
1431				// If no URL to load, hault
1432				if( !url ) {
1433					// If this is a new browser, stop here. We're done
1434					if( Cargo.History.SupportSlashHistory() ) {
1435						return;
1436					
1437					// Otherwise, this is the homepage of the old browser
1438					} else {
1439						this.HomePopstate();
1440					}
1441				}
1442			}	
1443			
1444			// Remember the latest URL to prevent double loads
1445			this.SetLastPayload(url);
1446			
1447			// Set the PID for this project project
1448			Cargo.History.GetPidFromPurl(url);
1449			
1450			
1451			// Network, split the input and go from there
1452			if( Cargo.History.IsNetwork && url && url.split("/").length >= 2 ) {
1453				var uri 				  = url.split("/");
1454				Projects.Data.user_url 	  = uri[0];
1455				Projects.Data.purl 		  = uri[1];
1456				Projects.Data.network_url = $("#url").val();
1457			}
1458			// Not a network, get data like normal
1459			else if( url && Projects.Data.user_url == "" || Projects.Data.purl == "" ) {
1460				Projects.Data.user_url 	= $("#url").val();
1461				Projects.Data.purl 		= url;
1462			
1463			} 
1464			// Navigated home, check for start project
1465			else if( !url && Cargo.Location.GetStartProjectPid() ) {
1466				Projects.Data.pid = Cargo.Location.GetStartProjectPid();
1467			}
1468			
1469			if(Projects.Data.pid) {
1470				// Check to see if the project is already loaded
1471				if( $("#entry_"+Projects.Data.pid).length > 0 ) {
1472					/*
1473					 *	If content is already loaded, just do the cleanup
1474					 */
1475					Projects.TriggerPreloadHelpers( Projects.Data.pid );
1476					// If this project is not already open, open it
1477					if( $("#entry_"+Projects.Data.pid).length > 0 ) {
1478						Projects.TriggerPostloadHelpers();
1479					
1480					// Changing the page may have dumped our content :(
1481					// Reload in this case
1482					} else {
1483						Projects.AjaxLoadByPid();
1484					}
1485				
1486				} else {
1487					Projects.AjaxLoadByPid();
1488
1489				}
1490			
1491			} else if(
1492				!Projects.Data.pid && 
1493				Cargo.Location.IsFollowing() &&
1494				Cargo.Location.GetBaseUrl("following") != url
1495			) {
1496				/* 
1497				 *	This is the following page, the pasted link may not
1498				 * 	exist yet. Verify that it is not a filter link first
1499				 *	If it is not, load by purl
1500				 */
1501				if( !this.IsFollowingFilter(url) ) {
1502					Projects.AjaxLoadByPurl();
1503					
1504				} 
1505				
1506			} else if(Cargo.Location.GetBaseUrl() == url || url == "#") {
1507				/*
1508				 *	Navigated back to home
1509				 */
1510				this.HomePopstate();
1511				
1512			
1513			} else if( !Projects.Data.pid && Cargo.History.GetNetworkSorting() ) {
1514				/*
1515				 *	Network sorting filter page
1516				 *	This is like home
1517				 */
1518				this.HomePopstate();
1519							
1520			} else if( !Projects.Data.pid && !Cargo.Location.IsFollowing() ) {
1521				/*
1522				 *	This is a direct link with no pid on a user page
1523				 *	Could be a project that is turned off
1524				 *	May not exist, but try to load it anyway
1525				 */
1526				Projects.AjaxLoadByPurl();
1527			}
1528			
1529			if(this.notify) this.notify(url);
1530			
1531		},
1532		
1533		/**
1534		 * 	When the popstate is the homepage
1535		 *	Chooses whether to load the start project
1536		 *		or close the open project
1537		 */
1538		HomePopstate : function() {
1539			/*
1540			 *	Safari reads the init load as a pop state
1541			 *	Check for start page, don't close the start page
1542			 *	If no start page, then close the project, we're back home
1543			 */
1544			if(
1545				$("#start_page").length > 0 &&
1546				$("#start_page").val() != "none" &&
1547				Projects.Data.unloading === false &&
1548				Cargo.History.SupportSlashHistory()
1549			) {
1550				Projects.Data.is_start_page = true;
1551				Projects.Data.pid = $("#start_page").val();
1552				
1553				/*
1554				 *	SpaceCollective double loads start pages, this hack fixes that
1555				 */
1556				if($("#item_"+Projects.Data.pid).length > 0) {
1557					if( $("#item_"+Projects.Data.pid).hasClass("project_feed_full") === false ) {
1558						Projects.AjaxLoadByPid( Projects.Data.pid );
1559					}
1560				} else {
1561					Projects.AjaxLoadByPid( Projects.Data.pid );
1562					$(document).trigger("startProjectLoaded");
1563				}
1564				
1565			} else {
1566				this.ClosePopstate();
1567			}
1568		},
1569		
1570		/**
1571		 *	This is fired on either a back button pop (from HomePopstate)
1572		 *		or from the router when we hit a "landing"
1573		 *		page of /filter, or network/sort
1574		 */
1575		ClosePopstate : function() {
1576			Projects.CloseProject(true);
1577			
1578			// For network
1579			$(".project_feed_thumb").removeClass("selected");
1580			$("#prev_open, #current_open").val("none");
1581			
1582			// Global value to stop double load
1583			Projects.Data.unloading = false;
1584			
1585			// Set the title back
1586			Cargo.History.SetWindowTitle(true);
1587			
1588		},
1589		
1590		/**
1591		 *	Convert a hash link to a slash link
1592		 *	At the end of this, we fire the history load event
1593		 */
1594		HashToSlash : function() {
1595			var uri = this.SanitizeURI(),
1596				path = stripTrailingSlash( location.pathname );
1597			
1598			uri = path + uri.replace("#/", "/").replace("#", "/");
1599			
1600			// Custom domains will have an additional slash, get rid of those
1601			uri = uri.replace("//", "/");
1602			
1603			// Send them on their way
1604			Cargo.History.Load( uri );
1605		},
1606		
1607		/**
1608		 *	Sanitize the incoming URI by removing any PID
1609		 */
1610		SanitizeURI : function() {
1611			var url 		  = "",
1612				hash_to_parts = location.hash
1613								.replace("#/", "/")
1614								.replace("#/", "/")
1615								.replace("#", "/")
1616								.split("/")
1617								.splice(1);
1618								
1619			// If the last char is a slash, remove it
1620			url = stripTrailingSlash( url );
1621			
1622			// If the first part of the hash array is a pid, remove it
1623			if(hash_to_parts.length >= 2 && parseInt(hash_to_parts[0]) > 0) {
1624				// Set the hashpid for use later
1625				Cargo.History.HashPID = hash_to_parts[0];
1626				
1627				for(var i=1; i<hash_to_parts.length; i++) {
1628					url += "/" + hash_to_parts[i];
1629				}
1630			
1631			} else {
1632				url += location.hash;
1633			}
1634			
1635			return url;
1636		},
1637		
1638		
1639		/*
1640		 *	Starts the HTML5 history plugin
1641		 */
1642		StartHistory : function(notify) {
1643			/*
1644			 * 	Check for a hash
1645			 *	Coming in from an old hash link
1646			 */
1647			if( location.hash && Cargo.History.SupportSlashHistory() ) {
1648				// Only update for new browsers
1649				Cargo.History.RunRoute();
1650			
1651			} else if ( !Cargo.History.SupportSlashHistory() ) {
1652				// This browser does not support HTML5 history
1653				$.history.init(function(url) { 
1654					/*
1655					 *	Check to see if there is a pid coming in
1656					 *	If so, reload with just the sanitized url
1657					 */
1658					if(
1659						url != Cargo.History.SanitizeURI() &&
1660						"#"+url != Cargo.History.SanitizeURI()
1661					) {
1662						Cargo.History.Load( Cargo.History.SanitizeURI() );
1663					
1664					} else {
1665						// Load this url
1666						Cargo.History.RunRouteHash( stripLeadingSlash( url ) ); 
1667					}
1668				});
1669				
1670				/*
1671				 *	Fire some Cargo events
1672				 */
1673				this.InitEvents();
1674			
1675			} else {
1676			    // This browser is compliant
1677				    
1678				// Create a callback
1679				this.notify = notify;
1680				
1681				// Run the router
1682				Cargo.History.RunRoute();
1683				
1684				/*
1685				 * Check for incoming links
1686				 * If there is a pasted / direct link
1687				 * Make sure it's
1688				 * - not the homestate
1689				 * - not following homestate
1690				 * - not network filter state
1691				 * - not a network display/sort
1692				 * - not user filter state
1693				 */ 
1694				var pathname = location.pathname.toLowerCase();
1695				var baseurl  = Cargo.Location.GetBaseUrl().toLowerCase();
1696				if(
1697					pathname != baseurl &&
1698					pathname.indexOf(baseurl + "/preview/") < 0 &&
1699					pathname != Cargo.Location.GetBaseUrl("following") &&
1700					pathname != baseurl + Cargo.History.GetNetworkFilter().toLowerCase() &&
1701					pathname != baseurl + Cargo.History.GetNetworkSorting().toLowerCase() &&
1702					pathname != baseurl + Cargo.History.GetUserFilter().toLowerCase() &&
1703					pathname != baseurl + Cargo.History.GetUserFilter().toLowerCase() + "/" &&
1704					!Cargo.Location.IsInAdmin() &&
1705					pathname != "/" &&
1706					pathname != baseurl+"/" &&
1707					pathname != "/index.php" &&
1708					!Cargo.Location.IsNetworkMemberList()
1709				) { 
1710					// Give 1 ms timeout to prevent this event firing before document.ready
1711					setTimeout(function() {
1712						$(document).trigger("projectLoadComplete", [ false ]);
1713					}, 1);
1714				
1715				
1716				}
1717				
1718				/*
1719				 *	Fire some Cargo events
1720				 */
1721				this.InitEvents();
1722				
1723				// Used to detect initial (useless) popstate
1724				var popped = ('state' in window.history), 
1725					initialURL = location.href;
1726				
1727				/*
1728				 * 	Bind for the back/forward button
1729				 * 	by listening to the pop state
1730				 *	Timer to avoid Chrome's load issue
1731				 */
1732				setTimeout(function() {
1733					Cargo.History.BindEvent("popstate", function() {
1734						
1735						// Ignore inital popstate that webkit fires on page load
1736						var initialPop = !popped && location.href == initialURL;
1737							popped = true;
1738						
1739						if ( initialPop ) {
1740							return;
1741						}
1742						
1743						/*
1744						 * 	Check to see if a legacy link was loaded in
1745						 *	This may have been because of a user's custom nav
1746						 */
1747						if( location.hash ) {
1748							Cargo.History.RunRoute();
1749							
1750						} else {
1751							Cargo.History.RunRoute(location.pathname, true);
1752						}
1753						
1754					}, false);
1755				}, 1);
1756			}
1757			
1758		},
1759
1760		/**
1761		 *	Create a handler for event binding
1762		 *	This is in place because IE uses a different binder then
1763		 *	the rest of the browsers, naturally.
1764		 */
1765		BindEvent : function(event_name, event_function) {
1766			if (window.addEventListener){
1767			    window.addEventListener(event_name, event_function, false);
1768			  } else if (window.attachEvent){
1769			    window.attachEvent(event_name, event_function);
1770			  }
1771
1772		},
1773		
1774		
1775		/*
1776		 *	Takes all links with the rel= tag and binds them to the history
1777		 *	Processes the hash or slash out of the href
1778		 * 	@var pre_path : string; used as modifier e.g. "following" || "[network url]"
1779		 *	@var page : string; used when paginating and binding only one page at a time
1780		 */
1781		BindLinks : function(pre_path, page, single) {
1782			// If this is a new page, use the page to load history
1783			if(page && page > 0) {
1784				var history_links = "#page_" + page + " a[rel='history']"
1785			
1786			} else if(single) {
1787				// Used when adding just a single element as the history eg: SpaceCollective
1788				var history_links = single;
1789				
1790			} else {
1791				// Just use all history elements
1792				var history_links = "a[rel='history']";
1793			}
1794			
1795			$(history_links).unbind("click").die("click").each(function() {
1796				// Make the links
1797				Cargo.History.MakeLink( $(this).attr("href"), $(this) );
1798								
1799				// Set the value for lookup later
1800				Cargo.History.Set( $(this).data("hash"), $(this) );
1801				
1802			}).click(function(e) {
1803				// If control+click or middle click, open new tab
1804				if(e.metaKey || e.which == 2) {
1805					window.open( $(this).attr("href") );
1806				} else {
1807					Cargo.History.Load( $(this).data("hash") );
1808				}
1809					
1810				return false;
1811			});
1812		},
1813		
1814		/*
1815		 *	For ajax history, set the title of the page
1816		 */
1817		SetWindowTitle : function(is_unload) {
1818			if(!is_unload) {
1819				if(Projects.Data.project_title) {
1820					document.title = Projects.Data.project_title + " - " + Cargo.Config.website_title;
1821				}
1822			
1823			} else {
1824				document.title = Cargo.Config.website_title;	
1825			}
1826		},
1827		
1828		/*
1829		 *	Initialize the history plugin
1830		 *	If HTML5 pushState is available, this will take preference
1831		 *	Do not load this on search results, or permalink pages
1832		 * 	var "pre_path" = string; e.g. "following" || "network"
1833		 */
1834		Init : function(pre_path, page, single) {
1835			if(
1836				$(".search_results").length == 0 && 
1837				($("#maincontainer").length > 0 || $("#items_container").length > 0)
1838			) {
1839				// Bind all the links found on the page
1840				Cargo.History.BindLinks(pre_path, page, single);
1841				
1842				if( !single && (!page || page <= 1) ) {
1843					// Start the history
1844					Cargo.History.StartHistory(function(url) { });
1845				}
1846				
1847			}
1848		},
1849		
1850		/**
1851		 *	Initialize the history for designs that use auto pagination
1852		 *	eg. tesla, apollo, limelight
1853		 *	Binds only new links to the page
1854		 *	Just a wrapper for init
1855		 */
1856		InitPagination : function(page) {
1857			this.Init(false, page, false);
1858		},
1859		
1860		/**
1861		 *	First some initial events 
1862		 *	This will tell the homestate if there are direct links, start pages etc
1863		 *	Abstracted for use with old + new history
1864		 */
1865		InitEvents : function() {
1866			// If this is a editing a project
1867			if( Cargo.Location.IsEditingProject() ) {
1868				$(document).trigger("editProjectLoaded", [ location.pathname ]);
1869			}
1870			// If this is a solo link
1871			else if( Cargo.Location.IsSoloLink() ) {
1872				$(document).trigger("soloLinkLoaded", [ location.pathname ]);
1873			}
1874			// If a direct link is loaded
1875			else if( Cargo.Location.IsDirectLink() ) {
1876				// Fire the event for direct link
1877				$(document).trigger("directLinkLoaded", [ location.pathname ]);
1878			}
1879			// Fire the direct link loaded event for admin and solo
1880			else if( Cargo.Location.IsEditingProject() || Cargo.Location.IsSoloLink() ) {
1881				// Fire the event for direct link
1882				$(document).trigger("directLinkLoaded", [ location.pathname ]);
1883			} 
1884			// If a start project is loaded on page load, fire an event
1885			else if( Cargo.Location.IsStartProject() ) {
1886				$(document).trigger("startProjectLoaded");
1887			
1888			} 
1889			
1890			
1891		},
1892		
1893		/**
1894		 *	Initialize the following-list and followed-list history
1895		 *	Uses the hash method only
1896		 */
1897		InitFollowlist : function() {
1898			$.history.init(changeFollowPage);
1899			$("a[rel='history']").live("click", function(){
1900				var hash = this.href;
1901				hash = hash.replace(/^.*#/, '');
1902				$.history.load(hash);
1903				return false;
1904			});
1905		}
1906		
1907}; // END History
1908
1909
1910/* !Cargo.Analytics */
1911Cargo.Analytics = {
1912	Config: {
1913		id: 'UA-1837333-7',
1914		name: '__cargo_analytics',
1915	},
1916
1917	enabled: true,
1918
1919	Init: function() {
1920
1921		if(typeof _use_google_analytics !== 'undefined') {
1922			this.enabled = _use_google_analytics === 1;
1923		}
1924
1925		if (Cargo.Location.IsCustomDomain()) {
1926			this.Config.custom_url = '/' + document.location.host;
1927		}
1928
1929		if(this.enabled) {
1930			
1931			// Include analytics.js
1932			(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
1933			(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
1934			m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
1935			})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
1936
1937			// Create Google Analytics tracker, send initial pageview
1938			ga('create', this.Config.id, 'auto', {'name': this.Config.name, 'cookieName': this.Config.name});
1939
1940			this.pageview(false);
1941
1942		}
1943
1944		// Send pageviews on project load
1945		$(document).bind("projectLoadComplete", function(e, pid) {
1946			if (! Cargo.Location.IsDirectLink() && ! Cargo.Location.IsStartProject()) {
1947				Cargo.Analytics.pageview(true);
1948			}
1949		});
1950	},
1951
1952	pageview: function(send_to_all_trackers, url) 
1953	{
1954		if (typeof url !== 'undefined' && ! send_to_all_trackers) {
1955			if(this.enabled) {
1956				ga(this.Config.name + '.send', 'pageview', {
1957					'page': url,
1958					'dimension3': 'Cargo 1'
1959				});
1960			}
1961			return;
1962		}
1963
1964		var tracker = this.Config.name,
1965			pathname = document.location.pathname.replace(/\/$/, '');
1966
1967		if(this.enabled) {
1968			if (typeof this.Config.custom_url !== 'undefined') {
1969				ga(this.Config.name + '.send', 'pageview', {
1970					'page': this.Config.custom_url + pathname,
1971					'dimension3': 'Cargo 1'
1972				});
1973			} else {
1974				ga(this.Config.name + '.send', 'pageview', {
1975					'dimension3': 'Cargo 1'
1976				});
1977			}
1978		}
1979
1980		// Send data for any other trackers
1981		if (typeof ga == 'function' && send_to_all_trackers) {
1982			ga(function() {
1983				ga.getAll().map(function(g) {
1984					var t = g.get('name');
1985					if (t != tracker) {
1986						ga(t + '.send', 'pageview');
1987					}
1988				});
1989			});
1990	
1991			// Push data to legacy trackers
1992			if (typeof _gaq !== 'undefined') {
1993				_gaq.push(['_trackPageview', pathname]);
1994			}
1995		}
1996	}
1997};
1998
1999Cargo.EU_cookie_notification = function() {
2000	if($('head meta[name="en_cookie_notification"]').length > 0) {
2001		if(!localStorage.getItem('eu_cookie_notification')) {
2002			var class_name = $('head meta[name="en_cookie_notification"]').attr('position'),
2003				content = $('head meta[name="en_cookie_notification"]').attr('description'),
2004				link = $('head meta[name="en_cookie_notification"]').attr('policy_link');
2005			content = content.replace('[policy_link]', '<a href="'+link+'" target="_blank">').replace('[/policy_link]','</a>');
2006
2007			$('body').prepend('<div id="eu_cookie_notification" class="'+class_name+'">'+content+'</div>');
2008
2009			$("#eu_cookie_notification").click(function(e) {
2010				if($(e.target).is('a')){
2011					return true;
2012				}
2013				
2014				$(this).remove();
2015				localStorage.setItem('eu_cookie_notification', 'true');
2016			});
2017		}
2018	}
2019};
2020
2021
2022/////////////////////////////////////////////////////////////////////////////////////////////////
2023/**
2024 *	Projects class
2025 *
2026 *
2027 *	@todo: description
2028 */
2029/* !Projects */
2030var Projects = {
2031
2032	"Data" : { 
2033		"is_start_page" : false,	// If opening project is a start project
2034		"unloading"		: false,	// If a project is unloading
2035		"pid"			: "",		// The current pid
2036		
2037		"purl"			: "",		// purl when parsing the URL
2038		"follow_sort"	: "",		// follow sort value when parsing the URL (postswithcomments)
2039		"network_sort"	: "",		// network sort value when parsing the URL (mine)
2040		"user_url"		: "", 		// The user URL when parsing the URL
2041		"network_url"	: "", 		// The newtwork URL when parsing the URL				
2042		"user_filter"	: "", 		// The filter on a user page			
2043		"network_filter": "", 		// The filter on a network 			
2044		"attr"			: "", 		// attribute of the URL (like comments) when parsing 
2045		"do_scroll"		: true,		// scroll to the top of the page after load, or not
2046		
2047		"slideheight"	: "", 		// Returned from Ajax opening
2048		"slidecount"	: "", 		// Returned from Ajax opening
2049		"content"		: "",		// The full content returned from Ajax
2050		"project_title"	: "",		// Title of the project, returned from Ajax
2051		"CloseObj" 		: "" 		// a jQuery object of the close button clicked
2052	},
2053	
2054	
2055	/**
2056	 *	Determines which type of project load
2057	 *	Always attempt to load from PID first
2058	 */
2059	LoadProject : function() {
2060		if( Projects.Data.pid !== false ) {
2061			Projects.AjaxLoadByPid();
2062		
2063		} else {
2064			Projects.AjaxLoadByPurl();
2065		}
2066	},
2067	
2068	/**
2069	 *	Ajax load a project via the pid
2070	 */
2071	AjaxLoadByPid : function( pid ) {
2072		
2073		if(pid) {
2074			// Set the PID
2075			this.Data.pid = pid;
2076		}
2077		
2078		/*
2079		 *	Check to see if there is a custom ajax load
2080		 *	If so, use that
2081		 */
2082		if (typeof Projects.CustomAjaxLoadByPid == "function") {
2083			Projects.CustomAjaxLoadByPid( this.Data.pid );
2084			return;
2085		}
2086		
2087		
2088		if( this.Data.user_url == "" ) {
2089			this.Data.user_url = $("#url").val();
2090			
2091		}
2092		
2093		// Assume we are going to load the project using ajax 
2094		this.FireAjax = true;
2095		
2096		// If everything is ok, we have a PID to load, fire away
2097		if( Projects.FireAjax === true && this.Data.pid && this.Data.pid != "none" ) {
2098			// Load all of the helpers at once
2099			Projects.TriggerPreloadHelpers();
2100
2101			var data = {
2102					pid 		 :	this.Data.pid, 
2103					url 		 :	this.Data.user_url,
2104					nurl 		 :	this.Data.network_url,
2105					is_following :	Cargo.Location.IsFollowing(),
2106					design 		 :	$("#design").val(),
2107					template 	 :	$("#template").val()/*,
2108					viewtype 	 :	$("#viewtype").val()
2109					*/
2110					},
2111					
2112				path = 	Cargo.Location.GetDomain() + 
2113						$("#templatepath").val() + 
2114						Cargo.Config.get('project_single');
2115			
2116
2117			$.post( path, data, function(dataObj) {
2118					if(dataObj !== "") {
2119						Projects.WriteProject(dataObj);
2120						
2121					} else {
2122						// If a failed load happens, close this load
2123						Projects.CloseProject();
2124					}
2125				});
2126		
2127		} else {
2128			// Hide the spinner
2129			Projects.Helper.HideSpinners();
2130		}
2131		
2132	},
2133	
2134	/**
2135	 *	Ajax load a project via the purl
2136	 */
2137	AjaxLoadByPurl : function() {
2138		// If no url is defined, define it
2139		if( this.Data.user_url == "" ) {
2140			this.Data.user_url = $("#url").val();
2141		}
2142		
2143		// Make sure we have something to look for
2144		if( this.Data.purl ) {
2145		
2146			var data = {
2147					purl 		 :	this.Data.purl, 
2148					url 		 :	this.Data.user_url,
2149					nurl 		 :	this.Data.network_url,
2150					is_following :	Cargo.Location.IsFollowing()
2151				},
2152					
2153				path = 	Cargo.Location.GetDomain() + 
2154						$("#templatepath").val() + 
2155						Cargo.Config.get('project_single');
2156			
2157			$.post( path, data, function(dataObj) {
2158					if(dataObj !== "") {
2159						// Write the project
2160						Projects.WriteProject(dataObj);
2161						
2162						// Set the current vals
2163						$("#prev_open").val( $("#current_open").val() );
2164						$("#current_open").val(Projects.Data.pid);
2165						
2166					} else {
2167						// If a failed load happens, close this load
2168						Projects.CloseProject();
2169					}
2170				});
2171				
2172		
2173		} 
2174	},
2175		
2176	/**
2177	 *	Write the return data from the ajax loaded post
2178	 *	Prints the project into a container
2179	 *	Does a little housekeeping and garbage collecting
2180	 */
2181	WriteProject : function(data) {
2182		// Gather data
2183		this.Helper.ProcessData(data);
2184		
2185		if(this.Data.pid === false || this.Data.pid === null) {
2186			/* 
2187			 *	Failed load, don't continue
2188			 * 	Trigger post load helpers
2189			 */
2190			Projects.TriggerPostloadHelpers();
2191			
2192			// Render a 404
2193			//Projects.Render404();
2194		
2195		} else if(
2196			$("#entry_"+this.Data.pid).length > 0 &&
2197			! $("#item_"+this.Data.pid).hasClass("project_feed_full")
2198		) {
2199			/*
2200			 * 	Content was loaded, but it is already on the page
2201			 *		Trigger post load helpers
2202			 */
2203			Projects.TriggerPostloadHelpers();
2204		
2205		} else {
2206			/*
2207			 *	Print the content
2208			 */
2209			 
2210			// Unload any audio on the page
2211			unloadAudio();
2212			
2213			// Check for a custom write project
2214			if (typeof Projects.CustomWriteProject == "function") {
2215				Projects.CustomWriteProject(data);
2216				return;			
2217			
2218			// If this is an SC project use a different method
2219			} else if( $("#template").val() == "spacecollective") {
2220				this.WriteProjectSC();
2221				return;
2222			
2223			// If this is a homepage project
2224			} else if($("#pRow"+this.Data.pid).length > 0) {
2225				this.WriteProjectHome();
2226				return;
2227			}
2228			
2229			// Figure out which container to load into 
2230			var container = Projects.Helper.GetContainer();
2231			
2232			// Print the project to the container
2233			$(container).html( this.Data.content );
2234
2235			// Trigger post load helpers
2236			Projects.TriggerPostloadHelpers();
2237			
2238			if(this.Data.attr == "comments") {
2239				// Scroll to the comments
2240				// Anchor to 1/3 screen
2241				anchorTo('comment_post_'+this.Data.pid, Math.ceil($(window).height()/1.5), true);
2242				this.Data.attr = ""; // Reset after use
2243				
2244			} else if( this.Data.do_scroll) {
2245				// Scroll to the top of the page
2246				Projects.Helper.ScrollToTop();
2247			}
2248		
2249		} // end if content is correct
2250		
2251	},
2252	
2253	/**
2254	 *	There is such a large difference between Escher and SC
2255	 *		this method is called by the WriteProject method 
2256	 */
2257	WriteProjectSC : function() {
2258		// Assume we can print this project
2259		this.PrintProject = true;
2260		
2261		// Unload any audio on the page
2262		unloadAudio();
2263		
2264		// Figure out which container to load into 
2265		container = Projects.Helper.GetContainer();
2266		
2267		// Make interventions before content is printed
2268		Projects.Helper.PostloadSC_pre_content();
2269		
2270		// Print the project to the container
2271		if(this.PrintProject === true) {
2272			$(container).html( this.Data.content );
2273		}
2274			
2275		// Make interventions after content is printed
2276		Projects.Helper.PostloadSC_post_content();
2277		
2278		// Hide the spinner
2279		Projects.Helper.HideSpinners();
2280		
2281		// Set the title
2282		Cargo.History.SetWindowTitle();
2283		
2284	},
2285	
2286	WriteProjectHome : function() {
2287		$("#pRow"+this.Data.pid).attr("class", "content_container_open").html( this.Data.content );
2288		Projects.Slideshow.CheckForSlideshow();
2289		Projects.Video.CheckForVideo();
2290	}, 
2291	
2292	/**
2293	 *	Fires all of the helper methods
2294	 *	Useful when needing to update highlights
2295	 *		without ajax loading a project
2296	 */
2297	TriggerPreloadHelpers : function(pid) {
2298		// Set this if it is incoming
2299		if(pid) this.Data.pid = pid;
2300		
2301		// Fire the Cargo events
2302		Projects.Helper.TriggerPreloadCargoEvents();
2303		
2304		// Show the spinner
2305		Projects.Helper.ShowSpinners();
2306		
2307		// Remove any old highlights
2308		Projects.Helper.RemoveNavHighlight();
2309		
2310		// Set the navigation highlight
2311		if( !Projects.Data.is_start_page ) {
2312			Projects.Helper.SetNavHighlight();
2313		}
2314		
2315		// Set the current page
2316		Projects.Helper.SetCurrentPages();
2317		
2318		// Intervention for the SpaceCollective design(s)
2319		Projects.Helper.PreloadInterventionSC();
2320		
2321		// Stop any slideshow cycles
2322		Projects.Helper.KillSlideshows();
2323		
2324		// Remove detail_preload
2325		$( Projects.Helper.GetContainer() ).removeClass("detail_preload");
2326		
2327		// Remove the fullscreen
2328		if( $("#freshbox").length > 0) {
2329			$(".entry").FreshBox().Close();
2330			$(".entry").FreshBox().CloseFullscreen();
2331		}
2332		
2333		// Video
2334		// Projects.Video.CheckForVideo();
2335	},
2336	
2337	/**
2338	 *	Fires all the helper methods
2339	 *	For after the project is returned from AJAX
2340	 */
2341	TriggerPostloadHelpers : function() {
2342		// Set the title
2343		Cargo.History.SetWindowTitle();
2344			
2345		// Hide the spinner
2346		Projects.Helper.HideSpinners();
2347		
2348		// Remove the thumb highlight
2349		Projects.Helper.RemoveThumbHighlight();
2350		
2351		// Remove any old highlights
2352		Projects.Helper.RemoveNavHighlight();
2353		
2354		// Set the highlight for the project thumb
2355		if( !Projects.Data.is_start_page ) {
2356			Projects.Helper.SetThumbHighlight();
2357			Projects.Helper.SetNavHighlight();
2358		}
2359		
2360		// Set the current page
2361		Projects.Helper.SetCurrentPages();
2362		
2363		// Any user options set that need to happen
2364		Projects.Helper.UserOptionActions();
2365		
2366		// Unhide the container
2367		var container = Projects.Helper.GetContainer();
2368		$(container).show();
2369		
2370		// Fire the Cargo events
2371		Projects.Helper.TriggerPostloadCargoEvents();
2372		
2373		// Reset the start page data
2374		if( Projects.Data.is_start_page ) {
2375			$(".project_index").remove();
2376			Projects.Data.is_start_page = false;
2377		}
2378
2379		// Video
2380		// Projects.Video.CheckForVideo();		
2381	},
2382	
2383	/**
2384	 *	Close a single project
2385	 *	Unloads all of the content and set the view state back to normal
2386	 */
2387	CloseProject : function(no_history) {
2388		var pid = $("#current_open").val();
2389		
2390		// This is a hack for the SC design. Should be converted, but for now leaving it
2391		if($("#template").val() == "spacecollective") {
2392			closeFeedPr(pid,false,'list');
2393			$(document).trigger("projectCloseComplete", [pid, $("#maincontainer")]); 
2394			Cargo.History.Unload();
2395			return;
2396		}
2397		
2398		// Unload any audio on the page
2399		unloadAudio();
2400		
2401		// Check for a custom write project
2402		if (typeof Projects.CustomCloseProject == "function") {
2403			Projects.CustomCloseProject(pid, no_history);
2404			return;	
2405		
2406		} else {
2407			// Fire some Cargo events
2408			$(document).trigger("projectClose", [ $("#maincontainer") ] );  
2409			$(document).trigger("projectIndex", [ pid ]);  
2410			
2411			// Unload the content
2412			$("#maincontainer").html("").css("display", "none").removeClass("detail_preload");
2413			
2414			// Unload the history
2415			if(!no_history) {
2416				Cargo.History.Unload();
2417			}
2418			
2419			if (jQuery.browser.safari && this.Data.do_scroll ) window.scrollTo(0,0);
2420			
2421			$(document).trigger("projectCloseUnload", [pid,  $("#maincontainer")]);  
2422			
2423			$('#pr_contain_item_'+pid).attr("class", "");
2424			
2425			if($("#o_thumb_nav").val() == "yes") { 
2426				$("#page_"+$("#current_page").val()).css("display","block");
2427			
2428			}
2429			
2430			$(".project_thumb, .project_feed_thumb").removeClass("active").removeClass("selected");
2431			$(".nav_active").removeClass("nav_active");
2432			
2433			$(document).trigger("projectCloseComplete", [pid, $("#maincontainer")]);  
2434			
2435			if( this.Data.do_scroll && !$.browser.safari ) {
2436				// Scroll back to the top
2437				Projects.Helper.ScrollToTop();
2438			}
2439		}
2440	},
2441	
2442	/*
2443	 *	Shows the next project
2444	 *	This is fired from the event "showNextProject"
2445	 *	Non-feed based designs only
2446	 */
2447	ShowNextProject : function() {
2448		// Set the default of the next spot to be the first spot
2449		var next = 0;
2450		
2451		// Make sure the SC/Network designs are not mid load (prevents rapid fire next project)
2452		if(
2453			$("#load_"+Projects.Data.pid).css("display") == "block" && 
2454			($("#template").val() == "spacecollective" || $("#template").val() == "network")
2455		) {
2456			return;
2457		
2458		// There is a pre-defined pid, load the next	
2459		} else if(Projects.Data.pid || $("#start_page").length > 0) {
2460			var cur  = Projects.Data.pid ? Projects.Data.pid : $("#start_page").val();
2461			var spot = array_search(cur, pr_list);
2462			
2463			if(spot !== false && spot < pr_list.length-1) {
2464				// Next = next
2465				next = parseInt(spot)+1;
2466			}
2467			
2468		}
2469		
2470		// Get the purl and load it
2471		var next_purl = Cargo.History.GetPurlFromPid(pr_list[next]);
2472		Cargo.History.Load( next_purl );
2473		
2474	},
2475	
2476	/*
2477	 *	Shows the previous project
2478	 *	This is fired from the event "showPrevProject"
2479	 *	Non-feed based designs only
2480	 */
2481	ShowPreviousProject : function() {
2482		// Set the default of the next spot to be the last spot
2483		var next = pr_list.length-1;
2484		
2485		// Make sure the SC/Network designs are not mid load (prevents rapid fire next project)
2486		if(
2487			$("#load_"+Projects.Data.pid).css("display") == "block" && 
2488			($("#template").val() == "spacecollective" || $("#template").val() == "network")
2489		) {
2490			return;
2491		
2492		// There is a pre-defined pid, load the prev	
2493		} else if(Projects.Data.pid) {
2494			var spot = array_search(Projects.Data.pid, pr_list);
2495			
2496			if(spot != 0) {
2497				// Make sure we're not at the start
2498				next = parseInt(spot)-1; 
2499			}
2500			
2501		}
2502		
2503		// Get the purl and load it
2504		var next_purl = Cargo.History.GetPurlFromPid(pr_list[next]);
2505		Cargo.History.Load( next_purl );
2506		
2507		
2508	},
2509	
2510	/*
2511	 *	Shows a random project
2512	 *	This is fired from the even "showRandomProject"
2513	 *	Non-feed based designs only
2514	 */
2515	ShowRandomProject : function() {
2516		// Set a default for the next spot
2517		var next = Math.floor(Math.random()*pr_list.length);
2518		
2519		// If there is a project open, make sure this is not that project
2520		if(Projects.Data.pid) {
2521			var cur = array_search(Projects.Data.pid, pr_list);
2522			if(cur == next) {
2523				// Randomize again
2524				next = Math.floor(Math.random()*pr_list.length);
2525			}
2526		}
2527		
2528		var next_purl = Cargo.History.GetPurlFromPid(pr_list[next]);
2529		
2530		// If no URL is found, then pass the PID instead
2531		if(next_purl == undefined) {
2532			next_purl = pr_list[next];
2533		}	
2534		Cargo.History.Load( next_purl );
2535	},
2536	
2537	/*
2538	 *	Shows the next project
2539	 *	This is fired from the event "showNextProject"
2540	 *	Feed based designs only
2541	 */
2542	ShowNextFeedProject : function() {
2543		var move_speed = 250;
2544		var padding = viewport_threshold;
2545		var current = $(".entry:in-viewport").attr("id");
2546
2547		// If we don't have a current post and we've scrolled, then we are still moving
2548		if(!current && $(window).scrollTop() > 20) {
2549			return false;
2550		}
2551		
2552		var next_post = (!current) ? "#"+$(".entry:first").nextAll(".entry").attr("id") : "#"+$("#"+current).nextAll(".entry").attr("id");
2553
2554		if (next_post != "#undefined") {
2555			var next_offset = $(next_post).offset().top-padding;
2556		
2557			clearTimeout(timer);
2558			window.scrollTo(0, (next_offset-padding)); 
2559			doscroll(next_offset,$(window).scrollTop(),0);
2560		
2561			//$.scrollTo(next_post, move_speed, {offset: {top:-padding}});
2562			var within_bounds = (($(window).scrollTop()+$(window).height()) >= ($("body").height()-1500)) ? true : false;
2563			if(next_post == "#"+$(".entry:last").prevAll(".entry").attr("id") && !within_bounds) getMoreHistory();
2564		}
2565	},
2566	
2567	/*
2568	 *	Shows the previous project
2569	 *	This is fired from the event "showPrevProject"
2570	 *	Feed based designs only
2571	 */
2572	ShowPreviousFeedProject : function() {
2573		var move_speed = 250;
2574		var padding = viewport_threshold;
2575		var current = "#"+$(".entry:in-viewport").attr("id");
2576		
2577		if (current != "#undefined") {
2578			if($(window).scrollTop() > $(current).offset().top) {
2579				if(current != "#"+$(".entry:last").attr("id")) current = "#"+$(current).nextAll(".entry").attr("id");
2580				else current = "."+$(current).next().attr("class");
2581				
2582				if(current == ".") current = "#new_page_content";
2583			}
2584			
2585			var prev_post = ($(current).prevAll(".entry").length <= 0) ? "body" : "#"+$(current).prevAll(".entry").attr("id");
2586			var prev_offset = $(prev_post).offset().top;
2587			
2588			clearTimeout(timer);
2589			window.scrollTo(0, prev_offset); 
2590			doscroll((prev_offset-padding),$(window).scrollTop(),0);
2591			//$.scrollTo(prev_post, move_speed, {offset: {top:-padding}});
2592			
2593		}
2594	},
2595	
2596	/**
2597	 *  Error handler for write project
2598	 *  This gets triggered by Projects.Helper.ProcessData
2599	 *  If there is an error found, this fires
2600	 */
2601	ErrorHandler : function() {
2602		if(this.Data.redirect_url != "" ) {
2603		  document.location.href = this.Data.redirect_url;
2604		}
2605	},
2606	
2607	/**
2608	 *	Render a 404 page
2609	 *	First ajax load the user 404 page
2610	 *	Then replace the entire content with the result
2611	 */
2612	Render404 : function() {
2613		
2614		Cargo.log("Not found: 404");
2615							
2616		/* Commented out until problems stop
2617		var data = {
2618			"url" : Cargo.Location.GetCargoUrl(),
2619			"uri" : Cargo.Location.GetCargoUrl()
2620		};
2621		
2622		$.ajax( {
2623			type 	: "POST",
2624			url 	: Cargo.Config.get("fourOfour") + "/" + Cargo.Location.GetCargoUrl() + "/" + Cargo.Location.GetCargoUrl(), 
2625			data	: data, 
2626			
2627			// Use the error type, because 404 renders "not found" headers
2628			error	: function(xhr, textStatus, errorThrown) {
2629				// Remove the user's stylesheet
2630				$("#user_stylesheet").remove();
2631				
2632				// Replace the body content with 404 page
2633				$("body").css("background-color","#0000ad").html(xhr.responseText);
2634			}
2635		});
2636		*/
2637		
2638	}
2639
2640}; // end Projects
2641	
2642/**
2643 *	Helper methods for projects
2644 *	Includes setting navigation, current pages, etc
2645 *	Accepts the pid value of the project being opened
2646 */
2647/* !Projects.Helper */
2648Projects.Helper = {
2649	
2650		/**
2651		 *	Process the ajax return data
2652		 */
2653		ProcessData : function(data) {
2654			try {
2655				// Verify this is proper JSON
2656				var jdata = $.parseJSON(data);
2657				Projects.Data.pid 			= jdata.pid,
2658				Projects.Data.slideheight	= jdata.slideheight,
2659				Projects.Data.slidecount 	= jdata.slidecount,
2660				Projects.Data.content 		= jdata.content;
2661				Projects.Data.project_title	= jdata.title;
2662				Projects.Data.project_title	= jdata.title;
2663				Projects.Data.error			= jdata.error;
2664				Projects.Data.redirect_url	= jdata.redirect_url;
2665				
2666			} catch (e) {
2667				// Invalid JSON
2668				Projects.Data.slideheight	= 0,
2669				Projects.Data.slidecount 	= 0,
2670				Projects.Data.content 		= data;
2671				Projects.Data.project_title	= "";
2672				return false;
2673			}
2674			
2675			if(Projects.Data.error && Projects.Data.error.length > 0) {
2676				Projects.ErrorHandler();
2677				return false;
2678			}
2679		    
2680		},
2681			
2682		/**
2683		 *	Set the current page, prev page, and spot
2684		 *	Then check pagination and go to that page if needed
2685		 */
2686		SetCurrentPages : function() {
2687			// Set previous and current
2688			$("#prev_open").val( $("#current_open").val() );
2689			$("#current_open").val(Projects.Data.pid);
2690			
2691			// Find and set what spot we are (for next/prev)
2692			if( typeof pid_list != "undefined" ) {
2693				var this_spot = pid_list.indexOf(Projects.Data.pid);
2694				this_spot = (!this_spot) ? -1 : this_spot;
2695				$("#this_spot").val(this_spot);
2696			}			
2697			
2698				var thispage	= $("#item_"+Projects.Data.pid).attr("page"),
2699					limit 		= $("#limit").val(),
2700					cur 		= $("#current_page").val();
2701				
2702				// Check to see if we need to go to a new page
2703				if(thispage && thispage != 0) {
2704					if(thispage != cur) {
2705						// Go to the new page
2706						changePage(thispage,limit);
2707						$("#this_spot").val( $("#item_"+Projects.Data.pid).attr("spot") );
2708					}
2709				}
2710			
2711			//}
2712		},
2713		
2714		/**
2715		 *	Intervention for the SC design
2716		 *	Sets a flag to not open, if need be 
2717		 */
2718		PreloadInterventionSC : function() {
2719			// If this is SpaceCollective and not a network
2720			if($('#items_container').length > 0 && $("#templatepath").val().indexOf("network") === 0) {
2721				// If this is the same project that is already open, don't re-open
2722				if( Projects.Data.pid == $("#prev_open").val() ) {
2723					Projects.FireAjax = false;
2724				}
2725			
2726			// Store this project in a var to re-use on close
2727			} else {
2728				$("#moduleholder_c").val( $("#moduleholder_o").val() );
2729				$("#moduleholder_o").val( $("#item_"+Projects.Data.pid).html() );
2730				$("#modulenumber").val( $("#prev_open").val() );
2731			}
2732			
2733		},
2734		
2735		/**
2736		 *	Intervention for the SC design after ajax load
2737		 *	This fires before the content is printed
2738		 */
2739		PostloadSC_pre_content : function() {
2740			
2741			var this_item = $("#item_"+Projects.Data.pid);
2742			
2743			// Same project and it's already open, don't print
2744			if( Projects.Data.pid == $("#prev_open").val() &&  $(this_item).attr("class") == "project_feed_full") {
2745				Projects.PrintProject = false;
2746			
2747			} else {
2748				$(this_item)
2749					.attr("onmouseover", "")
2750					.attr("onmouseout", "")
2751					.attr("class", "project_feed_full");
2752					
2753				if( Cargo.Config.isIE() ) {
2754					// Adds the rounded corners to IE
2755					$(this_item).addClass("ie");
2756				}
2757				
2758				// Adds rounded corners to everyone else
2759				try { DD_roundies.addRule(".project_feed_full", 5, true); } catch(err) { }
2760				
2761				// If there was a project already open, close it
2762				if( $("#moduleholder_c").val() != "none" && $("#modulenumber").val() != $(this_item).attr("name")) {
2763					printClosed( $("#modulenumber").val(), $("#moduleholder_c").val(), true);
2764					// Dump the values
2765					$("#modulenumber").val("none");
2766					$("#moduleholder_c").val("none");
2767				}
2768			}
2769		},
2770		
2771		/**
2772		 *	Intervention for the SC design after ajax
2773		 *	This fires after the content is printed
2774		 */
2775		PostloadSC_post_content : function() {
2776
2777			// disable scroll restore
2778			if ('scrollRestoration' in history) {
2779			  history.scrollRestoration = 'manual';
2780			}			
2781
2782			// Reshuffle the cards
2783			shiftPosition();
2784
2785			// Reset the start page data
2786			Projects.Data.is_start_page = false;
2787			
2788			// Add a spacer and hide the container
2789			$('#item_'+Projects.Data.pid+" #body_container").before(
2790				'<div style="height:'+ $('#item_'+Projects.Data.pid).height() +'px" id="cardspacer">&nbsp;</div>'
2791			).css("display","none");
2792			
2793			// For fixed headers, set a differnt top pad
2794			var toppad = 60;
2795			if($(".header_img").css("position") == "fixed") {
2796				toppad = $(".header_img").height();
2797			}
2798
2799			// Hide the project header if in the admin edit view
2800			if(Cargo.Location.IsInAdmin()) {
2801				$(".project_header").remove();
2802			}
2803			
2804			// If this is not a start project, scroll to the top
2805			if( $('#startpage').val() == 'none' || $('#startpage').val() != Projects.Data.pid ) {
2806				
2807				var window_top_height = toppad + getMass(".header_img", "height") + getMass(".nav_container.horizontal", "height");
2808				
2809				// If there is not already a defined way to handle this
2810				if( 
2811					$('#item_'+Projects.Data.pid).offset() && 
2812					(
2813						( $('#item_'+Projects.Data.pid).offset().top < window_top_height &&
2814				 	  	  $(window).scrollTop() > 10 ) ||
2815				 		$('#item_'+Projects.Data.pid).offset().top > window_top_height
2816				 	)
2817				) {
2818					
2819					$.scrollTo( 
2820						{ top:($('#item_'+Projects.Data.pid).offset().top-toppad), left:0}, 
2821						450, 
2822						{ onAfter:function(){ 
2823							$('#cardspacer').remove();
2824							$('#item_'+Projects.Data.pid+" #body_container").fadeIn(); 
2825							$('#item_'+Projects.Data.pid).addClass("open");
2826							shiftPosition();
2827						} 
2828					}); 
2829				
2830				} else {
2831					
2832					$('#cardspacer').remove();
2833					$('#item_'+Projects.Data.pid+" #body_container").fadeIn(); 
2834					$('#item_'+Projects.Data.pid).addClass("open");
2835				
2836				}
2837				
2838			// This is a start project, fade it in
2839			} else {
2840				$('#cardspacer').remove();
2841				$('#item_'+Projects.Data.pid+" #body_container").fadeIn(); 
2842			}
2843			
2844			$('#startpage').val('none');
2845			$(document).trigger("SCprojectLoadComplete", [ Projects.Data.pid ]);
2846			
2847			// Fire the Cargo events
2848			Projects.Helper.TriggerPostloadCargoEvents();
2849		},
2850		
2851		/**
2852		 *	Show the loading spinners
2853		 */
2854		ShowSpinners : function() {
2855			$("#load_"+Projects.Data.pid)
2856				.css("visibility", "visible")
2857				.show();
2858				
2859			if( $("#template").val() != "spacecollective") {
2860				$("#nav_loadspin")
2861					.css("visibility", "visible")
2862					.show();
2863			}
2864		},
2865		
2866		/**
2867		 *	Hide the loading spinners
2868		 */
2869		HideSpinners : function() {
2870			$("#load_"+Projects.Data.pid+", #nav_loadspin").hide();
2871		},
2872		
2873		/**
2874		 *	Highlights the nav item
2875		 */
2876		SetNavHighlight : function() {
2877			$("#menu_"+Projects.Data.pid).addClass("nav_active");
2878		},
2879		
2880		/**
2881		 *	Removes highlight from the nav
2882		 */
2883		RemoveNavHighlight : function() {
2884			$(".nav_active").removeClass("nav_active");
2885		},
2886		
2887		/**
2888		 *	Highlights the open thumbnail
2889		 */
2890		SetThumbHighlight : function() {
2891			$("#item_"+Projects.Data.pid).addClass("active");
2892			
2893		},
2894		
2895		/**
2896		 *	Removes the old highlight
2897		 */
2898		RemoveThumbHighlight : function() {
2899			$(".project_thumb.active").removeClass("active");			
2900		},
2901		
2902		/**
2903		 *	Triggers any preload events
2904		 */
2905		TriggerPreloadCargoEvents : function() {
2906			$(document).trigger("projectLoadStart", [ Projects.Data.pid, window.location.pathname.split("/") ]);
2907		},
2908		
2909		/**
2910		 *	Triggers any post write project events
2911		 */
2912		TriggerPostloadCargoEvents : function() {
2913			$(document).trigger("projectReady", [ {
2914				"pid" 			: Projects.Data.pid,
2915				"slideheight" 	: Projects.Data.slideheight
2916			} ]);
2917		
2918			$(document).trigger("projectLoadComplete", [ Projects.Data.pid ]);
2919		},
2920		
2921		/**
2922		 *	Determines which container to use
2923		 *	returns the container
2924		 */
2925		GetContainer : function() {
2926			// Escher based
2927			if( $('#maincontainer').length > 0 ) {
2928				return $('#maincontainer');
2929			
2930			// SpaceCollective based
2931			} else if( $('#items_container').length > 0 ) {
2932				return $('#item_'+Projects.Data.pid);
2933			
2934			// Homepage
2935			} else {
2936				return $("pRow"+Projects.Data.pid);
2937			}
2938			
2939		},
2940		
2941		/**
2942		 *	Any user options that happen after loading a project
2943		 *	For instance, hiding of thumbnails
2944		 */
2945		UserOptionActions : function() {
2946			// Hide the thumbnails
2947			if($("#o_thumb_nav").val() == "yes") { 
2948				$("#page_"+$("#current_page").val()).css("display","none");
2949				
2950			}
2951		},
2952		
2953		/**
2954		 *	Scroll to the top of the page
2955		 */
2956		ScrollToTop : function() {
2957			// Don't do this for SC
2958			if($("#items_container").length === 0 && $("#no_scroll").length === 0) {
2959				// If we are further then 50 from the top, jump to 50
2960				if(getScrollHeight() > 50) {
2961					window.scrollTo(0, 50);	
2962				}
2963				// Smooth scroll the rest of the way
2964				doscroll(0,getScrollHeight(),0);
2965			}
2966	
2967		},
2968		
2969		/**
2970		 *	Kill slideshow cycles
2971		 *	@todo move to slideshow class (when available)
2972		 */
2973		KillSlideshows : function() {
2974			// kill slideshow cycles
2975			for(i=0;i<20;i++) {
2976				clearTimeout(cycleTimeout[i]);
2977			}
2978	    	cycleTimeout	= [];
2979			cyclePause		= [];
2980			cycleComplete 	= [];
2981		}
2982
2983}; // end Helpers
2984
2985
2986
2987
2988/////////////////////////////////////////////////////////////////////////////////////////////////
2989/* !Projects.Slideshow */
2990Projects.Slideshow = {
2991	/* 
2992	 * Set a bunch of vars that will be used with each method
2993	 */
2994	"Data"	 : { 
2995		"do_placeholder" 	 : false,	// Use placeholder content, or activate the slideshow
2996		"thumbs_height"	 	 : [ ],		// The total height of each thumbnail container
2997		"slideheight_largest": [ ],		// The height of this slideshow
2998		"slidewidth_largest" : [ ],		// The width of this slideshow
2999		"slideheight_first"	 : [ ],		// The height of this slideshow
3000		"slidewidth_first"	 : [ ]		// The width of this slideshow
3001	},
3002	
3003	// Hold the config values
3004	"Config" : { },
3005	
3006	/*
3007	 *	Sets the variables to be used later
3008	 */
3009	SetData : function() {
3010		var template	 	   = Cargo.Config.GetTemplate();
3011		var design		 	   = Cargo.Config.GetDesign();
3012		if( template && design ) {
3013			this.Data.isSC 		   = template.indexOf("spacecollective") >= 0 ? true : false;
3014			this.Data.isOz 		   = design.indexOf("ozfeed") >= 0 ? true : false;
3015			this.Data.isTesla 	   = design.indexOf("tesla") >= 0 ? true : false;
3016			this.Data.isRunyon	   = design.indexOf("runyon") >= 0 ? true : false;
3017			this.Data.isWarhol	   = design.indexOf("warhol") >= 0 ? true : false;
3018			// Josh commented this out on 12-7-5 because we are not sure why this is in place
3019			this.Data.isMontessori = false; //design.indexOf("montessori") >= 0 ? true : false;
3020		}
3021		
3022		if(
3023			this.Data.isSC || 
3024			this.Data.isOz || 
3025			this.Data.isTesla || 
3026			this.Data.isMontessori || 
3027			this.Data.isRunyon
3028		) {
3029			this.Data.oneFail = true;
3030		}
3031		
3032		// Reset the slideshow values
3033		this.Data.slidewidth_largest = [ ];
3034		this.Data.slideheight_largest = [ ];
3035		this.Data.slidewidth_first = [ ];
3036		this.Data.slideheight_first = [ ];
3037		
3038	},
3039	
3040	LoadConfig : function() {
3041		var slideconfig = $("slideconfig");
3042		this.Config.thumb_position  = slideconfig.attr("thumb_position");
3043		this.Config.has_thumbs      = slideconfig.attr("has_thumbs");
3044		this.Config.nav_position    = slideconfig.attr("nav_position");
3045		this.Config.count_style     = slideconfig.attr("count_style");
3046		this.Config.has_count       = slideconfig.attr("has_count");
3047		this.Config.text_next       = slideconfig.attr("text_next");
3048		this.Config.text_slash      = slideconfig.attr("text_slash");
3049		this.Config.text_prev       = slideconfig.attr("text_prev");
3050		this.Config.has_textnav     = slideconfig.attr("has_textnav");
3051		this.Config.auto_delay      = slideconfig.attr("auto_delay");
3052		this.Config.is_autoplay     = slideconfig.attr("is_autoplay");
3053		this.Config.transition      = slideconfig.attr("transition");
3054		
3055		this.Config.delay 			= this.Config.transition == "none" ? 10 : 400;
3056		
3057		if(this.Config.is_autoplay == "yes") {
3058			this.Config.timeout = parseFloat(this.Config.auto_delay)*1000;
3059		} else {
3060			this.Config.timeout = 0;
3061		}
3062		
3063		if(this.Config.transition == "none") {
3064			this.Config.transition_speed = 1;
3065			this.Config.transition = "fade";
3066		} else {
3067			this.Config.transition_speed = '2000';
3068		}
3069		
3070		this.Config.first = true;
3071		this.Config.nextSlide;
3072	},
3073	
3074	/*
3075	 *	Will sniff the page for slideshows
3076	 *	Loop through each and create them
3077	 */
3078	CheckForSlideshow : function( ) {
3079		var slide_list = [];
3080		$(".slideshow_wrapper").each(function() { 
3081			var new_slide = $(this).attr("class").replace(/slideshow_wrapper/g,"").replace(/_/g,"").replace(/ /,"");
3082			
3083			if(!in_array(new_slide,slide_list)) {
3084				Projects.Slideshow.StartSlideshow( new_slide );
3085				slide_list.push(new_slide);
3086			}
3087		});
3088	},
3089	
3090	
3091	/*
3092	 *	Start the slideshow instance
3093	 *	This is an exact replica of the old slideshow method
3094	 *  @todo: remove all refs to legacy function
3095	 */
3096	StartSlideshow : function( pid ) {
3097		// Set the default vars
3098		this.SetData();
3099		
3100		// Load the config file
3101		this.LoadConfig();
3102		
3103		var this_selector = $(".slideshow_wrapper_"+pid).parent(".slideshow_component");
3104		
3105		var has_caption = false;
3106		
3107		var self = this;
3108		
3109		$(this_selector).each(function(i) {
3110			// First height/width
3111			self.Data.slideheight_first[i] = $("img:first", this).height();
3112			self.Data.slidewidth_first[i]  = $("img:first", this).width(); 
3113			
3114			// The w/h values might be 0, so grab from the attr
3115			self.Data.slideheight_first[i] = (self.Data.slideheight_first[i] == 0) ? $("img:first", this).attr("height") : self.Data.slideheight_first[i];
3116			self.Data.slidewidth_first[i]  = (self.Data.slidewidth_first[i]  == 0) ? $("img:first", this).attr("width")  : self.Data.slidewidth_first[i];
3117			
3118			// Tell this element that we've go this covered
3119			$(this).attr("rel", "started").attr("id", "slideshow_component_"+pid+"_"+i);
3120			
3121			// For inner loop use
3122			var Data   = Projects.Slideshow.Data;
3123			var Config = Projects.Slideshow.Config;
3124			
3125			// Add an id with unique sequential 
3126			$(".slideshow_wrapper_"+pid, this).attr({ 
3127				"id"    : "slideshow_wrapper_"+pid+"_"+i,
3128				"class" : "slideshow_wrapper"
3129			});
3130			$(".slideshow_container_"+pid, this).attr({ 
3131				"id"    : "slideshow_container_"+pid+"_"+i,
3132				"class" : "slideshow_container"
3133			});
3134			$(".slideshow_count_"+pid, this).attr({
3135				"id"    : "slideshow_count_"+pid+"_"+i,
3136				"class" : "slideshow_count"
3137			});
3138			$(".slideclick_"+pid, this).attr({
3139				"id"    : "slideclick_"+pid+"_"+i,
3140				"class" : "slideclick"
3141			});
3142			$(".slideshow_caption_"+pid, this).attr({
3143				"id"    : "slideshow_caption_"+pid+"_"+i,
3144				"class" : "slideshow_caption"
3145			});
3146			$(".slideshow_nav_"+pid, this)
3147				.attr("id", "slideshow_nav_"+pid+"_"+i)
3148				.removeClass("slideshow_nav_"+pid);
3149				
3150			$(".slide_prev_"+pid, this).attr("id", "prev_"+pid+"_"+i);
3151			$(".slide_next_"+pid, this).attr("id", "next_"+pid+"_"+i);
3152			
3153			// Loop through each image, get the widest and tallest
3154			$(".slideshow_container img", this).each(function(n) {
3155				var this_w = ($(this).width() > $(this).get(0).getAttribute("width")) ? $(this).width() : $(this).get(0).getAttribute("width"),
3156					this_h = ($(this).height() > $(this).get(0).getAttribute("height")) ? $(this).height() : $(this).get(0).getAttribute("height");
3157				
3158				
3159				this_w = parseInt(this_w);
3160				this_h = parseInt(this_h);
3161				
3162				if(this_w > Data.slidewidth_largest[i] || !Data.slidewidth_largest[i]) {
3163					Data.slidewidth_largest[i] = this_w; 
3164				}
3165				
3166				// Get the highest if we're on a special design
3167				if(this_h > Data.slideheight_largest[i] || !Data.slideheight_largest[i]) {
3168					Data.slideheight_largest[i] = this_h; 
3169				}
3170				
3171				// Check for caption
3172				if( !has_caption && $(this).attr("caption") && $(this).attr("caption") != "") {
3173					has_caption = true;
3174				}
3175				
3176				
3177			});
3178						
3179			// Set the first width
3180			$(".slideshow_wrapper", this).width( Data.slidewidth_largest[i] );
3181			
3182			// Set the default width of the container on certain designs
3183			if(Data.oneFail) {
3184				$(".slideshow_wrapper", this).height( Data.slideheight_largest[i] );
3185				$(".slideshow_container", this).height( Data.slideheight_largest[i] );
3186				Data.slideheight_first[i] = Data.slideheight_largest[i];
3187			} else {
3188				//$(".slideshow_wrapper", this).height( Data.slideheight_first[i] );
3189				$(".slideshow_container", this).height( Data.slideheight_first[i] );
3190			}
3191			
3192			
3193			
3194			// If the slide w > 560, set the caption with to be 560
3195			var caption_w = (Data.slidewidth_largest[i] > 560) ? 560 : Data.slidewidth_largest[i];
3196			$('.slideshow_caption', this).css("width",caption_w+"px");
3197			
3198			// Remove additional breaks
3199			$('.slideshow_container br', this).each(function() { $(this).remove(); });
3200			
3201			// If there is no captions, remove the caption container
3202			if( !has_caption ) {
3203				$(".slideshow_caption", this).remove();
3204			}
3205			
3206			
3207			
3208			/*
3209			 *	Check and set thumbails
3210			 */
3211			Projects.Slideshow.SetThumbs(pid, i, Data.slidewidth_largest[i]);
3212			
3213			
3214			// Get the count of images
3215			var img_count = $(".slideshow_container img", this).length;
3216			
3217			// Set the count
3218			if(Config.count_style == "parenth" && img_count > 0) {
3219				var count_nav = '(1 of '+img_count+')';
3220			
3221			} else if(Config.count_style == "no_parenth" && img_count > 0) {
3222				var count_nav = '1 of '+img_count;
3223			}
3224			
3225			// Show the count
3226			$("#slideshow_count_"+pid+"_"+i, this).html(count_nav);
3227			
3228			
3229			/*
3230			 *	Instantiate this slideshow
3231			 */
3232			if( Projects.Slideshow.Data.do_placeholder ) {
3233				Projects.Slideshow.SetPlaceholder(pid, i);
3234			
3235			} else {
3236				Projects.Slideshow.InitSingleSlideshow(pid, i);
3237			}
3238			
3239			
3240		});
3241			
3242		
3243		if(typeof shiftPadding == "function") {
3244			shiftPadding();
3245		}
3246	},
3247	
3248	/*
3249	 *	First checks, then sets the thumbnails if there are any
3250	 */
3251	SetThumbs : function(pid, i, slidewidth) {
3252		/*	If there are slideshow thumbs
3253		 */
3254		if(this.Config.has_thumbs == "yes") {
3255			// The position is on top
3256			if( this.Config.thumb_position == "top" ) {
3257			
3258				$('#slideshow_wrapper_'+pid+'_'+i)
3259					.before('<ul class="slideshow_thumbs" id="slideshow_thumbs_'+pid+'_'+i+'">');
3260			
3261			// Position is below
3262			} else if( this.Config.thumb_position == "bottom" ) {
3263				// If there is a nav below
3264				if( this.Config.nav_position == "bottom" && this.Config.has_nav == "yes" ) {
3265					$('#slideshow_nav_'+pid+'_'+i)
3266						.before('<ul class="slideshow_thumbs" id="slideshow_thumbs_'+pid+'_'+i+'">')
3267						.css("clear","both");
3268				
3269				// Default, attach it to the bottom of the wrapper
3270				} else {
3271					$('#slideshow_wrapper_'+pid+'_'+i)
3272						.after('<ul class="slideshow_thumbs" id="slideshow_thumbs_'+pid+'_'+i+'">');
3273				}
3274			}
3275			
3276			// Restrict the width
3277			$('#slideshow_thumbs_'+pid+'_'+i).css("width",slidewidth+"px");
3278			
3279			// Add the thumbs into the container, only for live
3280			if( !Projects.Slideshow.Data.do_placeholder ) {
3281				var t_hold = $('#slideshow_container_'+pid+'_'+i).html();
3282				$('#slideshow_thumbs_'+pid+'_'+i).html( t_hold );
3283			}
3284			
3285			// Remove the width and height attributes
3286			$('#slideshow_thumbs_'+pid+'_'+i+' img')
3287				.removeAttr("width")
3288				.removeAttr("height")
3289				.wrap('<li class="slideshow_thumb"><a href="#">');
3290		}
3291	},
3292	
3293	/*
3294	 *	Instantiates one instance of the slideshow
3295	 *	Can be used standalone, or with the Start slideshow method
3296	 */
3297	InitSingleSlideshow : function(pid, i) {
3298		
3299		// First, empty the contents of the thumbnails
3300		$('#slideshow_thumbs_'+pid+'_'+i).empty();
3301		
3302		$('#slideshow_container_'+pid+'_'+i).cycle({
3303			fx: 		Projects.Slideshow.Config.transition, 
3304			pager:  	'#slideshow_thumbs_'+pid+'_'+i,
3305			height: 	Projects.Slideshow.Data.slideheight_first[i],
3306			width:  	Projects.Slideshow.Data.slidewidth_largest[i],
3307			next:		'#next_'+pid+'_'+i,
3308			prev:		'#prev_'+pid+'_'+i,
3309			contain:	'#slideclick_'+pid+'_'+i,
3310			timeout:  	Projects.Slideshow.Config.timeout,
3311			speed: 		Projects.Slideshow.Config.transition_speed,
3312			this_i: 	i,
3313			
3314			// callback fn that adjusts the slideshow's height 
3315			before:	function(currSlideElement, nextSlideElement, options, forwardFlag){ 
3316				var sh = ($(this).get(0).getAttribute("height")) ? $(this).get(0).getAttribute("height") : $(this).height();
3317					sh = parseInt(sh);
3318
3319				var sw = ($(this).get(0).getAttribute("width")) ? $(this).get(0).getAttribute("width") : $(this).width();
3320					sw = parseInt(sw);
3321				
3322				if(
3323					sh > 0 && 
3324					!Projects.Slideshow.Data.isSC && 
3325					!Projects.Slideshow.Data.isOz && 
3326					!Projects.Slideshow.Data.isRunyon && 
3327					!Projects.Slideshow.Data.isWarhol
3328				) {
3329					if(Projects.Slideshow.Config.transition == "scrollRight") {
3330						$(this).parent().animate({ height: sh, width: sw }, Projects.Slideshow.Config.delay);
3331						$(this).siblings().css("z-index",0);
3332						$(this).css("z-index",($(this).index()+1))
3333					} else {
3334						$(this).parent().animate({ height: sh }, Projects.Slideshow.Config.delay);
3335					}
3336					
3337				}
3338				
3339				$(document).trigger("slideshowTransitionStart", [nextSlideElement]);
3340			},
3341			
3342			after: function(currSlideElement, nextSlideElement, options, forwardFlag) {
3343				if(parseInt(nextSlideElement) >= 0) {
3344					nextSlide = $("#"+$(currSlideElement).parent().attr("id")+" img:nth-child("+parseInt(nextSlideElement)+")");
3345				} else {
3346					nextSlide = nextSlideElement;
3347				}
3348				
3349				$(document).trigger("slideshowTransitionFinish", [nextSlide]);
3350			},
3351			
3352			// callback fn that creates a thumbnail to use as pager anchor 
3353			pagerAnchorBuilder: function(idx, slide) { 
3354				return '<li class="slideshow_thumb"><a href="#"><img src="' + slide.src + '" /></a></li>'; 
3355			}
3356			
3357		});
3358		
3359		// Get the thumbnail height (used in the placeholder)
3360		this.GetThumbnailHeight(pid, i);
3361		
3362		// Update the complete state of this
3363		$(document).trigger("slideshowLoadComplete", [ $('#slideshow_container_'+pid+'_'+i) ]);
3364	},
3365	
3366	/*
3367	 *	Set's the slideshow to display placeholder content
3368	 *		by showing only the first image in the slideshow
3369	 */
3370	SetPlaceholder : function(pid, i) {
3371		// Dump all of the image except for the first one
3372		$("#slideshow_container_"+pid+"_"+i+" img:first ~img").remove();
3373		
3374		// Make a position for the container and give it a height
3375		$("#slideshow_container_"+pid+"_"+i).css({
3376			"position"	: "relative",
3377			"height"	: $("#slideshow_container_"+pid+"_"+i+" img:first").height()
3378		});
3379		
3380		// Fake the thumbs by adding in holders
3381		for(var n in this.Data.thumbs_height[i]) {
3382			var img = '<img src="/_gfx/spacer.gif" height="'+
3383				this.Data.thumbs_height[i][n].h+'" width="'+
3384				this.Data.thumbs_height[i][n].w+'" />';
3385				
3386			var fake_thumb = '<li class="slideshow_thumb fake"><a href="#">'+img+'</a></li>';
3387			$("#slideshow_thumbs_"+pid+"_"+i).append(fake_thumb);
3388		}
3389		
3390		$("#slideshow_thumbs_"+pid+"_"+i).css("clear", "both");
3391	},
3392	
3393	/*
3394	 *	Destroys all slideshow sessions by removeing them and re-adding them
3395	 *	This is used by the inspector
3396	 */
3397	DestroyAll : function() {
3398		$(".slideshow_component").each(function() {
3399			// Remove and re-add everything
3400		    $(this).after('<div class="slideshow_component" id="'+$(this).attr("id")+'">'+$(this).html()+'</div>').remove();
3401		});
3402		
3403	},
3404	
3405	/*
3406	 *	Re-checks the page for slideshows
3407	 *	This is used when reactivating them after inspector closes
3408	 *	The assumption is they have already been activated once
3409	 */
3410	ReCheckAndInit : function() {
3411		// Get rid of all the plugin control
3412		this.DestroyAll();
3413		
3414		$(".slideshow_component").each(function() { 
3415			var id 	= $(".slideshow_wrapper", this).attr("id").replace("slideshow_wrapper_", ""),
3416				pid = id.split("_")[0],
3417				i 	= id.split("_")[1];
3418			
3419			// Remove the slide thumbs, they will be re-added
3420			$(".slideshow_thumbs", this)
3421				.after('<ul class="slideshow_thumbs" id="slideshow_thumbs_'+pid+'_'+i+'">')
3422				.remove();
3423			
3424			// Re-init the slides		
3425			Projects.Slideshow.InitSingleSlideshow(pid, i);
3426					
3427		});
3428		
3429	},
3430	
3431	/**
3432	 *	Get the thumbnail container height
3433	 *	Store the value
3434	 *	To do this, we add a clear:both div, grab height, then remove
3435	 */
3436	GetThumbnailHeight : function(pid, i) {
3437		var size_array = [ ];
3438		
3439		$("#slideshow_container_"+pid+"_"+i+" img").each(function(index) {
3440			var h = parseInt($(".slideshow_thumb img").css("height"));
3441			var og_w = $(this).attr("width");
3442			var og_h = $(this).attr("height");
3443			size_array[ index ] = getScaleSize(og_w, og_h, h);
3444		});
3445		
3446		this.Data.thumbs_height[i] = size_array;
3447		
3448	}
3449	
3450}
3451/////////////////////////////////////////////////////////////////////////////////////////////////
3452// Leaving this stub in for legacy purposes
3453// @todo: remove all refs to legacy function
3454// @todo: utilize the "CheckForSlideshows" method
3455function startSlideshow(pid) {
3456	Projects.Slideshow.StartSlideshow( pid );
3457}
3458
3459
3460/*!
3461 * The "reverse fallback" -- Flash object and HTML5 video tags are both housed
3462 * within a div.video_component. The CheckForVideo() method determines who gets
3463 * to stay, in essence, and removes the unused tags.
3464 */
3465/* !Projects.Video */
3466Projects.Video = {
3467	Config: {
3468		DEBUG: false,
3469		dependencies: [
3470			'/_css/mediaplayer.css',
3471			'/_js/jquery-ui-1.8.18.custom.min.js',
3472			'/_js/cargo.video.package.js'
3473		],
3474		volume_default: 0.75,
3475		volume: 1,
3476		muted: false
3477	},
3478
3479/**
3480 * DEBUG
3481 *
3482 * Controlled by Config.DEBUG, MightForceHTML5() and IsForcingHTML5() modify,
3483 * dependent upon the presence of the cargo.video.forcedHTML5 cookie, the
3484 * behavior of DetectPlugin() and DestroyFallbackTags() - always displaying
3485 * the video elements.
3486 *
3487 * ForceHTML5() controls the cargo.video.forcedHTML5 cookie and enables video
3488 * elements accordingly.
3489 */
3490	MightForceHTML5: function() {
3491		return this.Config.DEBUG;
3492	},
3493
3494	IsForcingHTML5: function() {
3495		if (this.Config.is_forcing_HTML5 !== undefined)
3496			return this.Config.is_forcing_HTML5;
3497
3498		var forcing_HTML5 = $.cookie('cargo.video.forcedHTML5') || false;
3499		if (forcing_HTML5)
3500			this.Config.has_flash_plugin = false;
3501
3502		this.Config.is_forcing_HTML5 = forcing_HTML5;
3503		return forcing_HTML5;
3504	},
3505
3506	ForceHTML5: function() {
3507		var should_force_HTML5 = $.cookie('cargo.video.forcedHTML5') || false;
3508		this.Config.force_HTML5 = ! should_force_HTML5;
3509		if (this.Config.force_HTML5) {
3510			$.cookie('cargo.video.forcedHTML5', true, {expires: 30, path: '/'});
3511			this.Config.has_flash_plugin = false;
3512			this.CheckForVideo();
3513		} else {
3514			$.cookie('cargo.video.forcedHTML5', null, {path: '/'});
3515			window.location.reload();
3516		}
3517	},
3518
3519/**
3520 * Primary method, determines if there are videos present and, if so, if there
3521 * is a need to "reverse fallback" to an HTML5 player. Upon fallback, loads the
3522 * related CSS and javascript should they not already exist, calling back to
3523 * itself recursively, rearranging and removing Flash and HTML5 elements, and 
3524 * finally applying the HTML5 player controls.
3525 *
3526 * @param	video_js_has_loaded	Boolean, true on recursive call after load of external CSS and javascript files
3527 */
3528	CheckForVideo: function(video_js_has_loaded) {
3529		if (!this.DetectVideos())
3530			return;
3531
3532		if (this.DetectPlugin()) {
3533			this.DestroyFallbackTags();
3534			return;
3535		}
3536
3537		// Load video-related javascript here, but only once
3538		if (this.Config.has_video_js === undefined) {
3539			if (video_js_has_loaded) {
3540				this.Config.has_video_js = true;
3541			} else {
3542				if (this.Config.is_loading_video_js !== undefined)
3543					return;
3544
3545				this.Config.is_loading_video_js = true;
3546
3547				// Actual loading of external dependencies
3548				$.loadFiles(this.Config.dependencies).done(function() {
3549					Projects.Video.CheckForVideo(true);
3550				});
3551
3552				return;
3553			}
3554		}
3555
3556		// Culling of the object tags, displaying of the video tags
3557		$('.video_component').each(function() {
3558			$(this).children('object').remove();
3559
3560			var video_tag = $(this).children('.video_tag');
3561			var player = video_tag.children();
3562			video_tag.css({
3563				display: 'inline-block',
3564				width: player.attr('data-video-width'),
3565				height: player.attr('data-video-height')
3566			});
3567
3568			// Apply jMediaelement controls after javascript has loaded
3569			if (Projects.Video.Config.has_video_js)
3570				Projects.Video.ConfigureMediaPlayer(player);
3571		});
3572	},
3573
3574/**
3575 * Application of jMediaelement controls to video tags
3576 */
3577	ConfigureMediaPlayer: function(player) {
3578		// Don't call video player methods more than once
3579		if (player.attr('data-video-configured') !== undefined)
3580			return;
3581
3582		player.attr('data-video-configured', 'true');
3583
3584		// Grab volume settings from cookies or defaults
3585		this.Config.volume = $.cookie('cargo.video.volume') || this.Config.volume_default;
3586		this.Config.muted = ($.cookie('cargo.video.muted')) ? true : false;
3587
3588		// Apply jMediaelement controls, custom volume logic
3589		player.jmeInit().jmeProp('controlbar', true);
3590		player.children('video').each(function(index, video) {
3591			$(video).bind('volumechange', function() {
3592				var control = $('.mute-unmute');
3593				var volume = Number($(this).jmeValue('volume'));
3594				var muted = $(this).jmeValue('muted');
3595
3596				if (volume > 0.66) {
3597					control.removeClass('volume-medium volume-low').addClass('volume-high');
3598				} else if (volume <= 0.66 && volume > 0.33) {
3599					control.removeClass('volume-high volume-low state-mute state-unmute').addClass('volume-medium');
3600				} else if (volume <= 0.33 && volume > 0.01) {
3601					control.removeClass('volume-high volume-medium state-mute state-unmute').addClass('volume-low');
3602				} else {
3603					control.removeClass('volume-high volume-medium volume-low').addClass('state-unmute');
3604				}
3605			
3606				if (muted) {
3607					control.addClass('state-unmute');
3608					$.cookie('cargo.video.muted', true, {expires: 30, path: '/'});
3609				} else {
3610					$.cookie('cargo.video.muted', null, {path: '/'});
3611				}
3612			
3613				$.cookie('cargo.video.volume', volume, {expires: 30, path: '/'});
3614			});
3615
3616			video.volume = Projects.Video.Config.volume;
3617			video.muted = Projects.Video.Config.muted;
3618		});
3619	},
3620
3621/**
3622 * Determine if the browser supports and has the Flash plugin installed
3623 *
3624 * @return	Boolean, whether detected
3625 */
3626	DetectPlugin: function() {
3627		// Only check for Flash once
3628		if (this.Config.has_flash_plugin !== undefined)
3629			return this.Config.has_flash_plugin;
3630
3631		// During debug, always report a lack of Flash
3632		if (this.MightForceHTML5()) {
3633			if (this.IsForcingHTML5())
3634				return false;
3635		}
3636
3637		var flash_was_detected = false;
3638		if (typeof navigator.plugins != 'undefined' && typeof navigator.plugins['Shockwave Flash'] == 'object') {
3639			var d = navigator.plugins['Shockwave Flash'].description;
3640			if (d && !(typeof navigator.mimeTypes != 'undefined' && navigator.mimeTypes['application/x-shockwave-flash'] && !navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin))
3641				flash_was_detected = true;
3642		} else if (typeof window.ActiveXObject != 'undefined') {
3643			try {
3644				if ((new ActiveXObject('ShockwaveFlash.ShockwaveFlash')))
3645					flash_was_detected = true;
3646			} catch(e) {}
3647		}
3648
3649		this.Config.has_flash_plugin = flash_was_detected;
3650		return flash_was_detected;
3651	},
3652
3653/**
3654 * Get a count of the div.video_component elements, confirm if there is more
3655 * than one present
3656 *
3657 * @return	Boolean, true if one or more
3658 */
3659	DetectVideos: function() {
3660		return ($('.video_component').length > 0);
3661	},
3662
3663/**
3664 * Remove the video tag parent div, even though it is not displayed, just to be
3665 * extra, extra safe
3666 */
3667	DestroyFallbackTags: function() {
3668		// During debug, do not remove the video tags
3669		if (this.MightForceHTML5())
3670			return;
3671
3672		if (this.Config.was_destroyed !== undefined)
3673			return;
3674
3675		this.Config.was_destroyed = true;
3676		$('.video_component .video_tag').each(function(index, value) {
3677			$(this).remove();
3678		});
3679	}
3680}
3681/*-
3682 * End Projects.Video
3683 */
3684
3685 Cargo.ReplaceLoadingAnims = function(specificSelection) {
3686
3687 	$(".retinaSpinner").each(function() {
3688		if (window.devicePixelRatio > 1 ){
3689			$(this).addClass('rotating');
3690		}
3691	});
3692 	
3693 	if(!Cargo.Config.isOldIE()){
3694	 	var spinnerEl = $('<div></div>');
3695
3696		for(var i = 0; i < 8; i++){
3697			spinnerEl.append(
3698				'<div style="position: absolute; top: -2px;">' +
3699					'<div class="spinner_circle part' + (i + 1) + '" style="-webkit-transform: rotate(' + (i * 45) +'deg) translate(6px, 0px); transform: rotate(' + (i * 45) +'deg) translate(6px, 0px);"></div>' +
3700				'</div>');
3701		}
3702
3703		if(typeof specificSelection == "undefined"){
3704			$('img[src$="/loadingAnim.gif"]').each(function(){
3705				replace(this);
3706			});
3707		} else {
3708			specificSelection.each(function(){
3709				replace(this);
3710			});
3711		}
3712	}
3713
3714	function replace(self){
3715		var thisSpinner = spinnerEl.clone();
3716
3717		thisSpinner.attr('class', 'retinaSpinner ' + $(self).attr('class'));
3718		thisSpinner.attr('id', $(self).attr('id'));
3719		thisSpinner.attr('style', $(self).attr('style'));
3720
3721		if (window.devicePixelRatio > 1 ){
3722			thisSpinner.addClass('rotating');
3723		}
3724
3725		// replace the old GIF
3726		$(self).replaceWith(thisSpinner);
3727	}
3728 }
3729
3730
3731/////////////////////////////////////////////////////////////////////////////////////////////////
3732/**
3733 *	  Social media class
3734 *
3735 *	  This is the main social media function
3736 *    It will init the rest of the application
3737 *
3738 * 	Cargo.IncludeSocialMedia( {
3739 *		element     : ".project_footer",
3740 *  	show_count  : true,
3741 *
3742 *		facebook    : true,
3743 *		twitter     : true,
3744 *		stumbleupon : false,
3745 *		pintrest    : true
3746 *	} );
3747 *
3748 *
3749 *  .social_media {
3750 *   	margin: 30px 0 100px 0; height: 20px;
3751 *   }
3752 *
3753 */
3754/* !Cargo.IncludeSocialMedia */
3755Cargo.IncludeSocialMedia = function( dataObj ) {
3756    // Loop through each to set the default options
3757    $.each(dataObj, function(key, value) {
3758        Cargo.SocialMedia.SetDefaults(key, value);
3759    });
3760
3761    // Set the project open/ready states
3762    $(document).ready(function() { Cargo.SocialMedia.Init(); });
3763    
3764    // Cover the bases on the events that fire
3765    $(document).bind("projectLoadComplete", function(e, pid) { Cargo.SocialMedia.Init(); });
3766    $(document).bind("directLinkLoaded", function(e, path) { Cargo.SocialMedia.Init(); });
3767    $(document).bind("startProjectLoaded", function(e) { Cargo.SocialMedia.Init(); });
3768    $(document).bind("paginationComplete", function(e) { Cargo.SocialMedia.Init(); });
3769
3770};
3771
3772
3773/**
3774 *	  This is the main social media app
3775 *    It will contain the various services
3776 *	NOTE:
3777 *		The var "Services" sits at the bottom of this method
3778 *		this defines each socail network and their dependencies
3779 *		it must sit at the bottom, not the top
3780 */
3781/* !Cargo.SocialMedia */
3782Cargo.SocialMedia = {
3783    
3784    /*
3785     *	Pre-define the services and their respective scripts that need loading
3786     */
3787    "Services"   : { 
3788    	"facebook"   : {
3789    		"script" : false,	// script url for inclusion at write time
3790    		"inuse"	 : false	// if this is in use or not, always default false
3791    	},
3792    	
3793    	"twitter"    : {
3794    		"script" : "http://platform.twitter.com/widgets.js",
3795    		"inuse"	 : false
3796    	},
3797    	
3798    	"pinterest"  : {
3799    		"script" : false,
3800    		"inuse"	 : false
3801    	},
3802    	
3803    	"googleplus" : {
3804    		"script" : "https://apis.google.com/js/plusone.js",
3805    		"inuse"	 : false
3806    	},
3807    	
3808    	"stumbleupon": {
3809    		"script" : "http://platform.stumbleupon.com/1/widgets.js",
3810    		"inuse"	 : false
3811    	},
3812    	
3813    	"reddit"     : {
3814    		"script" : "http://www.reddit.com/buttonlite.js?i=5",
3815    		"inuse"	 : false
3816    	}
3817    
3818    
3819    },
3820    
3821    "Options"       	   : { 
3822    	"element"   	   : ".project_footer",	// The selector element to bind the html to
3823    	"show_count"       : false,				// Show the "like" count or not
3824    	"twitter_username" : false				// Twitter username for @reply
3825    },
3826    
3827    "OutputHTML" : "",						// The HTML that will be printed to the element
3828    
3829	
3830	
3831	/*
3832	 *	Set the defaults of the socail media elements
3833	 */
3834    SetDefaults : function( which, value ) {
3835        if(which == "element" || which == "show_count" || which == "twitter_username") {
3836            this.Options[which] = value;
3837        } else {
3838        	// set the "inuse" value for the default 
3839            this.Services[which].inuse = value;
3840        }
3841    },
3842    
3843    /*
3844     *	Initialize the services
3845     */
3846    Init : function() {
3847    	// Reset the output values
3848    	this.OutputHTML = "";
3849    	
3850    	// Create the HTML
3851        this.CreateHTML();
3852        
3853        // Write the HTML
3854        this.WriteHTML();
3855    },
3856    
3857    /*
3858	 *	Gets a project title
3859	 */
3860    AddHTML : function( html ) {
3861    	this.OutputHTML += html;
3862    },
3863    
3864    /*
3865     *	Takes the HTML that was created by the methods below
3866     *	Replaces the stubs with real content
3867     *	Stubs are for direct link / encoded direct link / title
3868     *	Input is a PID of the element we are binding
3869     *	If no PID is passed, it will default to site link / html title
3870     */
3871    GetFormattedHTML : function( pid ) {
3872    	var final_output = this.OutputHTML;
3873    	
3874    	// Direct link
3875    	final_output = final_output.replace(/CARGO_DIRECT_LINK/g, this.GetDirectSocialLink( pid ) );
3876    	
3877    	// Encoded direct link
3878    	final_output = final_output.replace(/CARGO_ENCODED_DIRECT_LINK/g, encodeURIComponent(this.GetDirectSocialLink( pid ) ) );
3879    	
3880    	// Title
3881    	final_output = final_output.replace(/CARGO_PROJECT_TITLE/g, this.GetSocialProjectTitle( pid ) );
3882    	
3883    	// Return the results
3884    	return final_output;
3885    },
3886    
3887     /*
3888     *	Write the buttons to the choosen element
3889     */
3890    WriteHTML : function() {
3891    	
3892    	// Attach the content to the choosen element/selector
3893    	$(this.Options.element)
3894	    	.each(function() {
3895	    		// Add to reclusive elements. Make them social, but skip ones that already are social.
3896	    		if($(this).data("has_social") !== true) {
3897		    		$(this)
3898		    			.append('<div class="social_media">' + Cargo.SocialMedia.GetFormattedHTML( Cargo.SocialMedia.GetNearestPid( $(this) ) ) + '</div>')
3899		    			.data("has_social", true);
3900		    	}
3901	    	});
3902    	
3903    	
3904    	// Loop one more time, this time include scripts
3905		$.each(this.Services, function(service, options) {
3906			if( options.inuse === true && options.script !== false ) {
3907				// Remove any old scripts
3908				$("script#"+service).remove();
3909				
3910				// Add the new script
3911				addScript( options.script, service );
3912			}
3913		});
3914    
3915    },
3916    
3917    /*
3918	 *	Helper method gets a project title
3919	 */
3920    GetSocialProjectTitle : function( pid ) {
3921    	// Feed
3922    	if( Cargo.Config.GetTemplate().indexOf("feed") >= 0 ) {
3923    		return $("#entry_"+pid+" .project_title").text();
3924    		
3925    	} else {
3926    		return $(".project_title").text();
3927    	}
3928		
3929    },
3930    
3931    /*
3932	 *	Helper method gets a direct link
3933	 */
3934    GetDirectSocialLink : function( pid ) {
3935    	return Cargo.Location.GetDirectLink( pid );
3936    },
3937    
3938    /*
3939	 *	Quick and dirty. 
3940	 *	Finds the pid of the most active element
3941	 *	On feed design, that is probably it's parent. Find the entry
3942	 */
3943	GetNearestPid : function( this_elem ) {
3944		if( Cargo.Config.GetTemplate().indexOf("feed") >= 0 ) {
3945			if( $(this_elem).prevAll(".entry:first").length > 0) {
3946				return $(this_elem).prevAll(".entry:first").attr("id").replace("entry_", "");
3947			} else if($(this_elem).parents(".entry:first").length > 0) {
3948				return $(this_elem).parents(".entry:first").attr("id").replace("entry_", "");
3949			} else {
3950				return $(this_elem).parent().attr("id").replace("entry_", "");
3951			}
3952		} else {
3953			return $("#current_open").val();
3954		}
3955	},
3956    
3957    /*
3958     *	Create the final output HTML by adding individual services
3959     */
3960    CreateHTML : function() { 
3961    	// Loop through and add each to the selector
3962       for (var service in this.Services) {
3963            // Facebook
3964            if(service == "facebook" && this.Services[service].inuse ) {
3965               this.AddHTML( this.Facebook() );
3966            }
3967            // Twitter
3968            else if(service == "twitter" && this.Services[service].inuse ) {
3969               this.AddHTML( this.Twitter() );
3970            }
3971            // Pinterest
3972            else if(service == "pinterest" && this.Services[service].inuse ) {
3973               this.AddHTML( this.Pinterest() );
3974            }
3975            // Google Plus
3976            else if(service == "googleplus" && this.Services[service].inuse ) {
3977               this.AddHTML( this.GooglePlus() );
3978            }
3979            // StumbleUpon
3980            else if(service == "stumbleupon" && this.Services[service].inuse ) {
3981               this.AddHTML( this.StumbleUpon() );
3982            }
3983            // Reddit
3984            else if(service == "reddit" && this.Services[service].inuse ) {
3985               this.AddHTML( this.Reddit() );
3986            }
3987            
3988        }
3989    },
3990    
3991    
3992    /*
3993     *    All services below here
3994     *	Note, string replacements are made for the following:
3995     *		CARGO_DIRECT_LINK
3996     *		CARGO_ENCODED_DIRECT_LINK
3997     *		CARGO_PROJECT_TITLE
3998     */
3999    Facebook : function() {
4000    
4001        // Cargo.log("Should we show comments? "+this.Options.show_count);
4002        var w = (this.Options.show_count) ? '90' : '47';
4003        
4004        return '<div class="facebook_like" style="float: left; margin-right: 8px;"><iframe src="http://www.facebook.com/plugins/like.php?href=CARGO_ENCODED_DIRECT_LINK&amp;send=false&amp;layout=button_count&amp;width=50&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font=arial&amp;height=21&amp;appId=150492405019861" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:'+w+'px; height:21px;" allowTransparency="true"></iframe></div>';
4005        
4006    },
4007    
4008    Twitter : function() {
4009        
4010        var output = '<div class="tweet_this" style="float: left; margin-right: 8px;"><a href="https://twitter.com/share" class="twitter-share-button"';
4011        
4012        if (this.Options.twitter_username !== false) {
4013        	output += ' data-via="'+ this.Options.twitter_username +'"';
4014        }
4015        
4016        output += ' data-url="CARGO_ENCODED_DIRECT_LINK" data-text="CARGO_PROJECT_TITLE: CARGO_DIRECT_LINK" data-count="none">Tweet</a></div>';
4017        
4018        return output;
4019
4020    },
4021    
4022    Pinterest : function() {
4023    	
4024    	$("a.pin_it_link")
4025    		.live("click", function() {
4026    			addScript("http://assets.pinterest.com/js/pinmarklet.js?r=" + Math.random()*99999999);
4027    			return false;
4028    		});
4029    
4030    	return '<div class="pin_it" style="float: left; margin-right: 8px;"><a href="#" class="pin_it_link" style="background: none; border: 0;"><img src="/_gfx/pinit.png" /></a></div>';
4031    	
4032    },
4033    
4034    GooglePlus : function() {
4035    	
4036		return '<div class="google_plus" style="float: left; margin-right: 8px;"><g:plusone size="medium" annotation="none" href="CARGO_DIRECT_LINK"></g:plusone></div>';
4037    	
4038    },
4039    
4040    StumbleUpon : function() {
4041    
4042		return '<div class="stumbleupon" style="float: left; margin-right: 8px;"><su:badge layout="4" location ="CARGO_DIRECT_LINK"></su:badge></div>';
4043    	
4044    },
4045    
4046    Reddit : function() {
4047    	
4048    	return '<div class="reddit" style="float: left; margin-right: 8px;"><a href="http://www.reddit.com/submit?url=CARGO_ENCODED_DIRECT_LINK" target="_blank"><img src="http://www.reddit.com/static/spreddit5.gif" alt="submit to reddit" border="0" /></a></div>';
4049    	
4050    }
4051    
4052    
4053}; // End SocialMedia
4054
4055
4056/*!
4057 * Usage:
4058 * $.loadFiles('/this.js', '/that.js', '/other.js').done(function(data) {
4059 * 	console.log('Multiple files have finished loading.');
4060 * }).fail(function(xhr, text_status) {
4061 * 	console.log('One of the files could not be loaded.');
4062 * });
4063 */
4064/* !jQuery loadFiles Plugin */
4065(function($) {
4066/**
4067 * Constructor for Filer class; creates Deferred object in order to provide
4068 * jQuery done() and fail() event handling and initializes files array to track
4069 * and hold constructs created by trackFileState().
4070 */
4071	var Filer = function(files_to_load) {
4072		this.init();
4073		this.addFilesFromConstructor(files_to_load);
4074
4075		return this;
4076	}; $.extend(Filer.prototype, {
4077		init: function(files_to_load) {
4078			this.Data = {
4079				files: [],
4080				done_callback: null,
4081				fail_callback: null
4082			};
4083		},
4084
4085/**
4086 * Traverses the arguments passed by the constructor, recursively so should one
4087 * an array, passing files individually to the addFile method.
4088 *
4089 * @param	files	Mixed
4090 */
4091		addFilesFromConstructor: function(files) {
4092			$.each(files, $.proxy(function(index, value) {
4093				if ($.isArray(value)) {
4094					this.addFilesFromConstructor(value);
4095				} else {
4096					this.addFile(this.Data.files.length, value);
4097				}
4098			}, this));
4099		},
4100
4101/**
4102 * Creates jQuery $.ajax options object and events, performs $.ajax load, and
4103 * sends XHR reference to trackFileState() method.
4104 *
4105 * @param	index	Number, order the file reference is to be placed within the files array
4106 * @param	value	Object or String, object for jQuery $.ajax call or string path to file URL
4107 */
4108		addFile: function(index, value) {
4109			var base = (typeof value === 'object') ? value : {url: value};
4110			var options = $.extend(base, {
4111				cache: true,
4112				dataType: this.dataTypeForFile(base.url),
4113				success: $.proxy(function(data, text_status, xhr) {
4114					this.handleFileLoad(index, data);
4115				}, this),
4116				error: $.proxy(function(xhr, text_status, error_thrown) {
4117					this.handleFileError(index, xhr, text_status);
4118				}, this)
4119			});
4120
4121			this.trackFileState(index, value, $.ajax(options));
4122		},
4123
4124/**
4125 * @param	url		String, file URL
4126 * @return	String, dataType for $.ajax options object
4127 */
4128		dataTypeForFile: function(url) {
4129			return /\.js$/.test(url) ? 'script' : 'text';
4130		},
4131
4132/**
4133 * Places file information into files array for load and error event handling.
4134 *
4135 * @param	index	Number, order the file reference is to be placed within the files array
4136 * @param	url		String, file URL
4137 * @param	xhr		Object, returned by jQuery $.ajax()
4138 */
4139		trackFileState: function(index, url, xhr) {
4140			this.Data.files[index] = {
4141				complete: false,
4142				index: index,
4143				url: url,
4144				xhr: xhr
4145			};
4146		},
4147
4148/**
4149 * Called by $.ajax done event, forwards done message to the Filer done handler
4150 * in the event all files have completed. Handles special case for CSS files,
4151 * injecting their content in to the document head.
4152 *
4153 * @param	index	Number
4154 * @param	data	Mixed
4155 */
4156		handleFileLoad: function(index, data) {
4157			// A jQuery 1.4.2 bug has $.ajax success firing on $.ajax abort() - don't handle files mistakenly called by this
4158			// See http://bugs.jquery.com/ticket/6060 and https://github.com/jquery/jquery/commit/ba9e0fc177841bd74cc5ea4e52f09cd87d747bf5
4159			if (this.has_exited_on_error !== undefined)
4160				return;
4161
4162			this.Data.files[index].complete = true;
4163
4164			// Manually add CSS to the document head
4165			if (/\.css$/.test(this.Data.files[index].url))
4166				$('head').append('<style>' + data + '</style>');
4167
4168			var completed = 0;
4169			$.each(this.Data.files, function(index, file) {
4170				if (file.complete)
4171					completed++;
4172			});
4173
4174			if (this.Data.files.length == completed)
4175				this.complete(data);
4176		},
4177
4178/**
4179 * Called by $.ajax fail event, forwards fail message to the Filer fail handler
4180 * and aborts any remaining $.ajax loads.
4181 */
4182		handleFileError: function(index, xhr, text_status) {
4183			this.error(xhr, text_status);
4184
4185			this.Data.files[index].complete = true;
4186			$.each(this.Data.files, function(index, file) {
4187				if ( ! file.complete)
4188					file.xhr.abort();
4189			});
4190		},
4191
4192/**
4193 * Sends message to Deferred object that all file loads were successful.
4194 */
4195		complete: function(data) {
4196			if ($.isFunction(this.Data.done_callback))
4197				this.Data.done_callback.apply(this, [data]);
4198		},
4199
4200/**
4201 * Sends message to Deferred object that one or more file loads could not be
4202 * completed. Prevents itself from sending such message more than once.
4203 */
4204		error: function(xhr, text_status) {
4205			// $.ajax abort() results in numerous calls here, prevent such events
4206			if (this.has_exited_on_error !== undefined)
4207				return;
4208
4209			this.has_exited_on_error = true;
4210
4211			if ($.isFunction(this.Data.fail_callback))
4212				this.Data.fail_callback.apply(this, [xhr, text_status]);
4213		},
4214
4215		done: function(callback) {
4216			this.Data.done_callback = callback;
4217			return this;
4218		},
4219
4220		fail: function(callback) {
4221			this.Data.fail_callback = callback;
4222			return this;
4223		}
4224	});
4225
4226/**
4227 * @return	Filer instance
4228 */
4229	$.extend({
4230		loadFiles: function() {
4231			return new Filer($.makeArray(arguments));
4232		}
4233	});
4234})(jQuery);
4235/*-
4236 * End jQuery loadFiles Plugin
4237 */
4238
4239
4240/**
4241 * FreshBox
4242 */
4243/* !jQuery Freshbox aka Fullscreen plugin */
4244(function($) {
4245
4246	$.fn.FreshBox = function(options) {
4247	
4248		var defaults = {
4249			fill	: "fit",	// How is the image resized
4250			element : "img",	// What element are we targeting?
4251			parent  : ".project_content"
4252		};
4253	
4254		// Update any options passed in with the defaults
4255		this.options = $.extend(defaults, options);
4256		var self = this;
4257		
4258		this.Data = {
4259			overflow		: null,			// The overflow of body before opening the lightbox
4260			scroll_x		: 0,			// Starting scroll position
4261			scroll_y		: 0,			// Starting scroll position
4262			window_height	: 0,			// Window height
4263			window_width	: 0,			// Window width
4264			iOS 			: undefined,	// Data store for cached UI element sizes on iOS
4265			allowZoom		: true,			// allow zooming into images that are bigger than the window.
4266			zoomedImage		: undefined,
4267			zoomEnabled		: false,
4268			zoomActive		: false
4269		};
4270		
4271		/**
4272		 * Override the parent element
4273		 */
4274		if (typeof freshbox_parent_element !== 'undefined') self.options.parent = freshbox_parent_element;
4275		
4276		/**
4277		 * Init
4278		 *	  Sets up the click events for both fullscreen and lightbox
4279		 */
4280		this.Init = function() {
4281		
4282			var element;
4283			
4284			// Initialize fullscreen when clicking fullscreen button
4285			$("#fullscreen", self).die().unbind("click").click( function(e) {
4286				// If we're using a modern browser
4287				if( !self.CheckOldBrowsers() ) {
4288					self.InitFullscreen(e, $(this).parents(".entry").attr("id"));
4289				} else {
4290					self.InitLightbox(e, $(this).attr("data-mid"), $(this).parents(".entry").attr("id"));
4291				}
4292				return false;
4293			});
4294			
4295			// Only inititilize the lightbox when that display option is checked
4296			if($("fullscreen_option").attr("data") == "lightbox" ) {
4297				// Find the parent
4298				// Initialize lightbox when clicking project_content img
4299				$(self.options.parent+" "+self.options.element, self).each(function() {
4300					// If this is a Cargo uploaded image or not in an anchor tag
4301					if ( $(this).is("[src_o]") && !$(this).parent("a").length > 0 ) {
4302					
4303						// Cursor style
4304						$(this).css("cursor", function() {
4305							if ($.browser.mozilla) {
4306							  	return '-moz-zoom-in';
4307							} else if ($.browser.webkit) {
4308								return '-webkit-zoom-in';
4309							} else {
4310								return 'pointer'; 
4311							}
4312						});
4313					
4314						// Setup
4315						$(this).die().unbind("click").click( function(e) {
4316							self.InitLightbox(e, $(this).attr("data-mid"), $(this).parents(".entry").attr("id"));
4317							return false;
4318						});
4319					};
4320				});
4321			} // end if lightbox
4322
4323		};
4324		
4325		/**
4326		 * Fullscreen
4327		 *	Opened by clicking the fulllscreen button
4328		 *	Opens images fullscreen via HTML5
4329		 *	Falls back to flash if HTML5 isn't supported
4330		 */
4331		this.InitFullscreen = function(e, element) {
4332		
4333			self.Construct();
4334			
4335			// Get the active container, based on the element that was clicked
4336
4337			var active_container;
4338			if( self.options.parent !== ".project_content" ) {
4339				active_container = self.options.parent;
4340			} else {
4341				active_container = $(e.currentTarget).parents(self.options.parent);
4342			}
4343			
4344			// Hide until open if not IE or iOS or an old browser
4345			if( ! Cargo.Config.isIE() && ! self.CheckIOS() || ! self.CheckOldBrowsers() )
4346				$("#freshbox").css("visibility", "hidden");
4347			
4348			// Write the container and hide the scrollbar
4349			$("#freshbox").data("state", "fullscreen").append($("#fullscreen_src").html());
4350			
4351			// If we're in the older IE, add the related class
4352			if ($.browser.msie && $.browser.version.substr(0,1) < 9)
4353				$("#freshbox").addClass("ie");
4354			
4355			// Append all of the images in freshbar content
4356			$(self.options.element, active_container).each(function() {
4357				// If it's a Cargo uploaded image
4358				if ( $(this).is("[src_o]") ) {
4359					$(this).clone()
4360							 .appendTo("#freshbox #fullscreen_imgs")
4361							 .attr("style", "");
4362				}
4363			});
4364			
4365			// Click to progress
4366			$("#freshbox").click(function() {
4367				self.NewElement("next");
4368				  return false;
4369			});
4370								
4371			// Trigger next functions
4372			self.ConfigureSlideshow();
4373			self.OpenFullscreen();
4374			self.Navigation();
4375		};
4376		
4377		this.InitLightbox = function(e, mid, element) {
4378			
4379			self.Construct();
4380			
4381			// Get the active container, based on the element that was clicked
4382			var active_container = $(e.currentTarget).parents(self.options.parent);
4383			
4384			// Write the container and hide the scrollbar
4385			$("#freshbox").data("state", "lightbox").append($("#fullscreen_src").html());
4386			
4387			// Append all of the images in freshbar content
4388			$(self.options.element, active_container).each(function() {
4389			
4390				// If it's a Cargo uploaded image
4391				if ( $(this).is("[src_o]") ) {
4392					$(this).clone()
4393							 .appendTo("#freshbox #fullscreen_imgs")
4394							 .attr("style", "");
4395				}
4396			});
4397			
4398			/**
4399			 * Loop through each of those images and append them to the
4400			 * image container, until we match the ids with the clicked img
4401			 */
4402			var mid_match = false;
4403			
4404			$("#freshbox #fullscreen_imgs img").each(function() {
4405				if( mid_match == false && $(this).attr("data-mid") != mid ) {
4406					$(this).appendTo("#freshbox #fullscreen_imgs");
4407				} else if( mid_match == false && $(this).attr("data-mid") == mid ) {
4408					mid_match = true;
4409				}
4410			});
4411			
4412			// Click to close
4413			$("#freshbox").click(function() {
4414				self.Close();
4415				
4416				return false;
4417			});
4418
4419			// Trigger next functions
4420			self.ConfigureSlideshow();
4421			self.Navigation();
4422
4423			$(document).trigger("freshboxOpen");
4424
4425			
4426		};
4427		
4428		/**
4429		 * Construct
4430		 *	  Shared between both functions
4431		 */
4432		this.Construct = function() {
4433			// Grab the overflow of body
4434			this.Data.overflow = $("body").css("overflow");
4435			this.Data.scroll_x = $(window).scrollLeft();
4436			this.Data.scroll_y = $(window).scrollTop();
4437		
4438			// Close previous instances
4439			self.Close();
4440
4441			this.Data.zoomEnabled = false;
4442			this.Data.zoomActive = false;
4443
4444			if(Cargo.Config.isMobile()){
4445				var viewport = document.querySelector("meta[name=viewport]"),
4446					zoomLevel = this.getViewportScale();
4447
4448				if(viewport === null) {
4449					// add viewport tag
4450					var viewport = document.createElement('meta');
4451						viewport.setAttribute('name', 'viewport');
4452	 
4453					document.getElementsByTagName('head')[0].appendChild(viewport);
4454					this.Data.oldViewPortContent = '';
4455					
4456				} else {
4457					// store current content attribute value
4458					this.Data.oldViewPortContent = viewport.getAttribute('content');
4459				}
4460	 
4461				viewport.setAttribute('content', 'width=device-width, initial-scale='+ zoomLevel +', minimum-scale='+ zoomLevel +', maximum-scale='+ zoomLevel);
4462
4463			}
4464
4465
4466			// Create the freshbox element
4467			$("body").append('<div id="freshbox" />');
4468			
4469			// If the body isn't already hidden, then hide it
4470			if( this.Data.overflow != "hidden" ) $("body").css("overflow", "hidden");
4471			
4472			// IE class for IE and older browsers
4473			if( Cargo.Config.isIE() || self.CheckOldBrowsers() ) $("#freshbox").addClass("ie");
4474			
4475		 	// Disable scaling and scrolling in iOS
4476		 	this.PreventIOSEvents(true);
4477
4478			$(window).resize(function() {
4479				self.Resize();
4480			});
4481			
4482			window.onorientationchange = function() {
4483				self.Resize();
4484			};
4485
4486		};
4487		 
4488		 
4489		 /**
4490			*	Create the slideshow and set the key commands
4491			*/
4492		this.ConfigureSlideshow = function() {
4493			/**
4494		 	 * If there is a single image in the project,
4495		 	 *		hide the prev/next buttons.
4496		 	 */
4497			if( $("#freshbox img").length == 1 ) {
4498				$("#freshbox").addClass("single");
4499				$("#fullscreen_next, #fullscreen_prev").remove();
4500			}
4501
4502			// Configure the nav
4503			$("#fullscreen_next").click(function(e) {
4504				self.NewElement("next");
4505				return false;
4506			});
4507			
4508			$("#fullscreen_close").click(function(e) {
4509				self.Close();
4510				self.CloseFullscreen();
4511				return false;
4512			});
4513			
4514			$("#fullscreen_prev").click(function(e) {
4515				self.NewElement("prev");
4516				return false;
4517			});
4518
4519			$("#fullscreen_zoom").click(function(e) {
4520				self.toggleZoom();
4521				self.Data.zoomEnabled =! self.Data.zoomEnabled;
4522				return false;
4523			});
4524
4525			  /**
4526			   * Keyboard nav
4527			   */
4528			   
4529			  // Unbind previous instances
4530		 	shortcut.remove("Up");
4531		 	shortcut.remove("Down"); 
4532		 	shortcut.remove("Left"); 
4533		 	shortcut.remove("Right"); 
4534		 	// shortcut.remove("Esc"); 
4535			   
4536			  shortcut.add("Up",function() { 
4537			  	self.NewElement("prev");
4538			  },{ 
4539			  	'type'				: 'keydown', 
4540			  	'disable_in_input'  : true, 
4541			  	'keycode'			: 38 
4542			  });  
4543			  
4544			  shortcut.add("Down",function() { 
4545			  	self.NewElement("next");
4546			  },{ 
4547			  	'type'				: 'keydown', 
4548			  	'disable_in_input'  : true, 
4549			  	'keycode'			: 36 
4550			  });
4551			  
4552			  shortcut.add("Left",function() { 
4553			  	self.NewElement("prev");
4554			  },{ 
4555			  	'type'				: 'keydown', 
4556			  	'disable_in_input'  : true, 
4557			  	'keycode'			: 37 
4558			  });
4559			  
4560			  shortcut.add("Right",function() { 
4561			  	self.NewElement("next");
4562			  },{ 
4563			  	'type'				: 'keydown', 
4564			  	'disable_in_input'	: true, 
4565			  	'keycode'			: 39 
4566			  });
4567			  
4568			  shortcut.add("Esc",function() {
4569			  	self.Close();
4570				self.CloseFullscreen();
4571			}, {
4572				'type'				: 'keydown',
4573				'keycode'			: 27
4574			});
4575			
4576			 // Assign the first image as active and format
4577			 self.NewElement("next");
4578
4579			 if(Cargo.Config.isMobile()){
4580				$('.freshbox_navigation').remove();
4581				$("#freshbox").unbind();
4582
4583				this.Data.freshboxHammer = Hammer($('#freshbox')[0], {
4584					prevent_default: true,
4585					swipe_velocity: 0.4,
4586					tap_always: false
4587				});
4588
4589				this.Data.freshboxHammer.on('swipeleft', function(){
4590					self.NewElement("next");
4591				});
4592
4593				this.Data.freshboxHammer.on('swiperight', function(){
4594					self.NewElement("prev");
4595				});
4596
4597				this.Data.freshboxHammer.on('tap', function(e){
4598					clearTimeout(self.Data.tapCloseTimeout);
4599
4600					self.Data.tapCloseTimeout = setTimeout(function(){
4601						self.Close();
4602						self.CloseFullscreen();
4603					}, 250);
4604
4605				});
4606
4607				this.Data.freshboxHammer.on('doubletap', function(e){
4608					clearTimeout(self.Data.tapCloseTimeout);
4609					self.toggleZoom();
4610					self.Data.zoomEnabled =! self.Data.zoomEnabled;
4611				});
4612
4613				this.Data.freshboxHammer.on('pinchin', function(e){
4614					clearTimeout(self.Data.tapCloseTimeout);
4615					if(self.Data.zoomActive){
4616						self.toggleZoom();
4617						self.Data.zoomEnabled =! self.Data.zoomEnabled;
4618					}
4619					e.gesture.stopDetect();
4620				});
4621
4622				this.Data.freshboxHammer.on('pinchout', function(e){
4623					clearTimeout(self.Data.tapCloseTimeout);
4624					if(!self.Data.zoomActive){
4625						self.toggleZoom();
4626						self.Data.zoomEnabled =! self.Data.zoomEnabled;
4627					}
4628					e.gesture.stopDetect();
4629				});
4630			}
4631			 
4632		 };
4633		 
4634		 /**
4635		  *	For slideshows, what the next element will be
4636		  */
4637		 this.NewElement = function(direction) {
4638		 
4639		 	// Remove preload image and spinner
4640		 	$("#freshbox img.preload, #freshbox_loading").remove();
4641		 	
4642		 	// Previous
4643		 	if( direction == "prev") {
4644		 		// Prepend the active image to the begining of the container
4645		 		$("#freshbox img.active").removeClass("active").prependTo($("#fullscreen_imgs"));
4646		 		$("#fullscreen_imgs img:last").addClass("active");
4647		 		
4648		 	// Next
4649		 	} else {
4650		 		// Append the active image to the end of the container
4651		 		$("#freshbox img.active").removeClass("active").appendTo($("#fullscreen_imgs"));
4652		 		$("#fullscreen_imgs img:first").addClass("active");
4653		 	};
4654		 	
4655		 	// Move the active image and preload
4656			 $("#freshbox img.active").prependTo($("#freshbox"));
4657			 
4658			 self.LoadIMG($("#freshbox img.active"));
4659		 	self.Resize();
4660		 	
4661		 };
4662
4663		 this.toggleZoom = function(){
4664
4665			function constrain(val, min, max) {
4666				return Math.min(Math.max(val, min), max);
4667			}
4668
4669			var activeImage = $('#freshbox img.active.zoomable'),
4670				transformFallback = Cargo.Config.isOldIE(),
4671				oldMaxWidth,
4672				oldMaxHeight;
4673
4674			if(activeImage.length > 0) {
4675
4676				this.Data.zoomedImage = activeImage;
4677
4678				if(activeImage.hasClass('zoomed')){
4679
4680					activeImage.removeClass('zoomed');
4681
4682					$('a.freshbox_nav_button#fullscreen_zoom').removeClass('active');
4683
4684					this.clearZoomEvents();
4685
4686				} else {
4687
4688					this.Data.oldMaxHeight = activeImage[0].style.maxHeight,
4689					this.Data.oldMaxWidth = activeImage[0].style.maxWidth;
4690
4691					activeImage.addClass('zoomed');
4692					$('a.freshbox_nav_button#fullscreen_zoom').addClass('active');
4693
4694					this.Data.zoomActive = true;
4695
4696					activeImage.css({
4697						'maxWidth'		: 'none',
4698						'maxHeight'		: 'none',
4699						'cursor'		: function(){
4700							if ($.browser.mozilla) {
4701								return '-moz-grab';
4702							} else if ($.browser.webkit) {
4703								return '-webkit-grab';
4704							} else {
4705								return 'move'; 
4706							}
4707						}
4708					});
4709
4710					// make drag work outside of the browser window.
4711					if(activeImage[0].setCapture) { 
4712						activeImage[0].setCapture(); 
4713					}
4714
4715					var isDragging 		= false,
4716						imageHeight 	= parseInt(activeImage.attr('height_o')),
4717						imageWidth		= parseInt(activeImage.attr('width_o')),
4718						windowHeight 	= window.innerHeight,
4719						windowWidth 	= window.innerWidth,
4720						offsetX 		= 0,
4721						offsetY 		= 0,
4722						maxXoffset		= 9e9,
4723						maxYoffset		= 9e9,
4724						dragXMultiplier = 1.0,
4725						dragYMultiplier = 1.0,
4726						dragTimeout,
4727						pageX,
4728						pageY;
4729
4730					$(window).bind('resize.freshboxZoom', function(){
4731						windowWidth	 = window.innerWidth;
4732						windowHeight = window.innerHeight;
4733
4734						activeImage.css({
4735							'marginLeft' : ((windowWidth - imageWidth) / 2) + 'px',
4736							'marginTop' : ((windowHeight - imageHeight) / 2) + 'px'
4737						});
4738
4739						// calculate offset bounds from image center
4740						maxXoffset = constrain(((imageWidth - windowWidth) / 2), 0, 9e9);
4741						maxYoffset = constrain(((imageHeight - windowHeight) / 2), 0, 9e9);
4742
4743						// calculate drag multipliers for really big images
4744						dragXMultiplier = constrain(imageWidth / windowWidth, 1, 2);
4745						dragYMultiplier = constrain(imageHeight / windowHeight, 1, 2);
4746					});
4747
4748					$(window).trigger('resize.freshboxZoom');
4749
4750					if(Cargo.Config.isMobile()){
4751						
4752						this.Data.zoomHammer = Hammer(activeImage[0], {
4753							tap_always: false,
4754							prevent_default: true
4755						}).on("dragstart", function(e){
4756							if(e.gesture.touches.length > 0){
4757								pageX = e.gesture.touches[0].pageX;
4758								pageY = e.gesture.touches[0].pageY;
4759							}
4760						}).on("drag", function(e){
4761							if(e.gesture.touches.length > 0){
4762
4763								if(!isNaN(pageX) && !isNaN(pageY)){
4764
4765									offsetX -= (pageX - e.gesture.touches[0].pageX) * dragXMultiplier;
4766									offsetY -= (pageY - e.gesture.touches[0].pageY) * dragYMultiplier;
4767
4768									offsetX = constrain(offsetX, -maxXoffset, maxXoffset);
4769									offsetY = constrain(offsetY, -maxYoffset, maxYoffset);
4770
4771									activeImage.css('-webkit-transform', 'translate3d(' + offsetX + 'px, ' + offsetY + 'px, 0)');
4772
4773								}
4774
4775								pageX = e.gesture.touches[0].pageX;
4776								pageY = e.gesture.touches[0].pageY;
4777							}
4778
4779							return false;
4780						});
4781
4782					} else {
4783						// desktop drag behavior
4784						activeImage.bind('mousedown.freshboxZoom', function(e){
4785
4786							// only left mouse button
4787							if(e.button === 0) {
4788								pageX = e.pageX;
4789								pageY = e.pageY;
4790
4791								dragTimeout = setTimeout(function(){
4792									isDragging = true;
4793
4794									activeImage.css({
4795										'cursor' : function(){
4796											if ($.browser.mozilla) {
4797												return '-moz-grabbing';
4798											} else if ($.browser.webkit) {
4799												return '-webkit-grabbing';
4800											} else {
4801												return 'move'; 
4802											}
4803										}
4804									});
4805
4806									$(document).bind('mouseup.freshboxZoom', function(){
4807
4808										clearTimeout(dragTimeout);
4809
4810										$(document).unbind('mousemove.freshboxZoom');
4811										$(document).unbind('mouseup.freshboxZoom');
4812
4813										if(activeImage[0].releaseCapture) { 
4814											activeImage[0].releaseCapture(); 
4815										}
4816
4817										// make sure the click event fires first;
4818										setTimeout(function(){
4819											isDragging = false;
4820										});
4821
4822									});
4823								}, 150);
4824
4825								$(document).bind('mousemove.freshboxZoom', function(e){
4826
4827									offsetX -= (pageX - e.pageX) * dragXMultiplier;
4828									offsetY -= (pageY - e.pageY) * dragYMultiplier;
4829
4830									offsetX = constrain(offsetX, -maxXoffset, maxXoffset);
4831									offsetY = constrain(offsetY, -maxYoffset, maxYoffset);
4832
4833									activeImage.css({
4834										left: offsetX + 'px',
4835										top: offsetY + 'px'
4836									});
4837									
4838									pageX = e.pageX;
4839									pageY = e.pageY;
4840
4841								});
4842							}
4843
4844							return false;
4845
4846						});
4847
4848						activeImage.bind('click.freshboxZoom', function(e){
4849
4850							activeImage.css({
4851								'cursor' : function(){
4852									if ($.browser.mozilla) {
4853										return '-moz-grab';
4854									} else if ($.browser.webkit) {
4855										return '-webkit-grab';
4856									} else {
4857										return 'move'; 
4858									}
4859								}
4860							});
4861
4862							clearTimeout(dragTimeout);
4863							
4864							if(isDragging) {
4865								return false;
4866							}
4867						});
4868
4869					}
4870				}
4871			}
4872		};
4873
4874		this.clearZoomEvents = function(){
4875			$(document).unbind('mousemove.freshboxZoom');
4876			$(document).unbind('mouseup.freshboxZoom');
4877
4878			$(window).unbind('resize.freshboxZoom');
4879
4880			if(this.Data.zoomedImage !== undefined) {
4881				this.Data.zoomedImage.unbind('mousedown.freshboxZoom');
4882				this.Data.zoomedImage.unbind('click.freshboxZoom');
4883
4884				if(this.Data.zoomedImage[0].releaseCapture) { 
4885					this.Data.zoomedImage[0].releaseCapture(); 
4886				}
4887
4888				if(Cargo.Config.isMobile()){
4889					// clear Hammer events
4890					this.Data.zoomHammer.dispose();
4891				}
4892
4893				this.Data.zoomedImage.css({
4894					'transform'		: '',
4895					'-webkit-transform'		: '',
4896					'left'			: '0',
4897					'top'			: '0',
4898					'marginTop'		: 'auto',
4899					'marginLeft'	: 'auto',
4900					'maxWidth'		: (this.Data.oldMaxWidth === undefined ? '100%' : this.Data.oldMaxWidth),
4901					'maxHeight'		: (this.Data.oldMaxHeight === undefined ? '100%' : this.Data.oldMaxHeight),
4902					'cursor'		: function(){
4903						return 'pointer'; 
4904					}
4905				});
4906			}	
4907
4908			this.Data.zoomActive = false;
4909
4910			this.Resize({
4911				type: 'orientationchange'
4912			});
4913		};
4914		 
4915		/**
4916		 * Load an image
4917		 */
4918		this.LoadIMG = function($image) {
4919
4920			var activeImage = $image[0],
4921				self 		= this;
4922
4923			if(activeImage === undefined) {
4924				return;
4925			}
4926
4927			var loadOriginal = parseInt(activeImage.getAttribute('width_o')) > parseInt(activeImage.getAttribute('width'));
4928
4929			activeImage.removeAttribute('style');
4930			activeImage.setAttribute('class', 'active');
4931
4932			$(activeImage).css({
4933				'maxHeight'	: '100%',
4934				'maxWidth'	: '100%',
4935				'width'		: 'auto',
4936				'height'	: 'auto',
4937				'margin'	: 'auto',
4938				'top'		: '0',
4939				'bottom'	: '0',
4940				'left'		: '0',
4941				'right'		: '0'
4942			});
4943
4944			$(activeImage).css('cursor', 'pointer');
4945
4946			$('a.freshbox_nav_button#fullscreen_zoom').hide();
4947
4948			if( loadOriginal === true ){
4949
4950				// there's a bigger image available. If we're on retina we want to show higher pixel
4951				// densities. If the image @ 75% is still bigger than the active image, scale it down.
4952				// 
4953				var maxWidthAt75Percent = (parseInt(activeImage.getAttribute('width_o')) / 100.0) * 75;
4954				
4955				if(window.devicePixelRatio >= 1.5 && maxWidthAt75Percent > parseInt(activeImage.getAttribute('width'))){
4956
4957					if(maxWidthAt75Percent > window.innerWidth) {
4958						maxWidthAt75Percent = window.innerWidth;
4959					}
4960
4961					$(activeImage).css({
4962						'maxWidth' : maxWidthAt75Percent + 'px'
4963					}).attr('data-restrict-width', maxWidthAt75Percent);
4964				}
4965
4966				// mark the currently active image as preloader for the original image that's gonna be loaded.
4967				activeImage.setAttribute('class', 'preload');
4968
4969				// create new image container for the original.
4970				var originalImage = new Image(),
4971					i;
4972
4973				// clone attributes
4974				for( i = 0; i < activeImage.attributes.length; i++ ) {
4975					if(activeImage.attributes[i].name !== "src") {
4976						originalImage.setAttribute(activeImage.attributes[i].name, activeImage.attributes[i].value);
4977					}
4978				}
4979
4980				// set original source
4981				originalImage.src = activeImage.getAttribute('src_o');
4982
4983				// mark as active
4984				originalImage.setAttribute('class', 'active');
4985
4986				// add to DOM
4987				activeImage.parentNode.appendChild(originalImage);
4988
4989				// original is not cached, show loading anim.
4990				if(originalImage.complete === false) {
4991
4992					spinner = $("<img />").attr("src", "/_gfx/loadingAnim.gif").attr("id", "freshbox_loading").appendTo("#freshbox");
4993
4994				 	// overwrite design.css for older designs to force the loader on top.
4995				 	if(spinner.css('zIndex') === "101") {
4996						spinner.css('zIndex', '115');
4997						spinner.css('opacity', '0.4');
4998					}
4999
5000					originalImage.onload = function(){
5001						$('#freshbox_loading').remove();
5002						
5003						if(activeImage !== null && activeImage.parentNode !== null){
5004							activeImage.parentNode.removeChild(activeImage);
5005						}
5006						
5007						self.Resize();
5008					}
5009
5010				} else {
5011					activeImage.parentNode.removeChild(activeImage);
5012				}
5013			}
5014
5015			Cargo.ReplaceLoadingAnims($("#freshbox img[src$='/loadingAnim.g
5015if']"));
5016
5017
5018			this.Resize();
5019
5020
5021			if(this.Data.zoomEnabled === true){
5022				this.toggleZoom();
5023			} 
5024		
5025		};
5026		 
5027		/**
5028		 * Set the navigation
5029		 */
5030		this.Navigation = function() {
5031		 	var transition_time = 200,
5032		 		hover		   = false,
5033		 		nav_fadeout	   = null,
5034		 		nav_timeout	   = 650,
5035		 		nav_track 		  = {};
5036		 		
5037		 	nav_fadeout = setTimeout('$(".freshbox_navigation").stop().fadeOut(200)', nav_timeout);
5038
5039		 	$(".freshbox_navigation").mouseenter(function() {
5040		 		hover = true;
5041		 	});
5042		 	
5043		 	$(".freshbox_navigation").mouseleave(function() {
5044		 		hover = false;
5045		 	});
5046			  
5047			  $("#freshbox").mousemove(function(e) {
5048				  
5049				  // Show the project nav if you're on a project
5050				  if(nav_track.x != e.clientX && nav_track.y != e.clientY) {
5051				  	$(".freshbox_navigation").fadeIn(transition_time);
5052				  }
5053				  
5054				  nav_track = {
5055				  	"x" : e.clientX,
5056				  	"y" : e.clientY
5057				  };
5058				  
5059				  // If the text is visible, or if you're hovering over the top
5060				  // always show the header/toolbar
5061				  if (hover == true) {
5062					  clearTimeout(nav_fadeout);
5063					  
5064				  // Otherwise, fade the project nav / header out after a second or so
5065				  } else {
5066					  if(nav_fadeout != null) { clearTimeout(nav_fadeout) };
5067					  nav_fadeout = setTimeout('$(".freshbox_navigation").stop().fadeOut(200)', nav_timeout);
5068				  }
5069					  
5070			  });
5071		 };
5072		 
5073		/**
5074		 * What happens when the window is resized
5075		 */
5076		this.Resize = function(e) {
5077
5078			var preload = $('#freshbox img.preload'),
5079				active 	= $('#freshbox img.active');
5080
5081			if(this.Data.allowZoom === true) {
5082				if(parseInt(active.attr('width_o')) > window.innerWidth || parseInt(active.attr('height_o')) > window.innerHeight){
5083					active.addClass('zoomable');
5084					$('a.freshbox_nav_button#fullscreen_zoom').show();
5085
5086				} else {
5087
5088					if(active.hasClass('zoomable')) {
5089
5090						if(this.Data.zoomActive === true){
5091
5092							var self = this;
5093
5094							setTimeout(function(){
5095								self.toggleZoom();
5096								active.removeClass('zoomable');
5097								$('a.freshbox_nav_button#fullscreen_zoom').hide();
5098								active.css('cursor', '');
5099							}, 50);
5100
5101						} else {
5102
5103							active.removeClass('zoomable');
5104							$('a.freshbox_nav_button#fullscreen_zoom').hide();
5105							active.css('cursor', '');
5106
5107						}
5108					}
5109				}
5110			}
5111
5112			if(this.Data.zoomActive === true){
5113				return false;
5114			}
5115
5116			if(e !== undefined) {
5117
5118				if(e.type === "orientationchange" || e.type === "resize") {
5119					// recalculate
5120					$('#freshbox [data-restrict-width]').each(function(){
5121
5122						var maxWidthAt75Percent = (parseInt(this.getAttribute('width_o')) / 100.0) * 75;
5123						
5124						if(window.devicePixelRatio >= 1.5 && maxWidthAt75Percent > parseInt(this.getAttribute('width'))){
5125
5126							if(maxWidthAt75Percent > window.innerWidth) {
5127								maxWidthAt75Percent = window.innerWidth;
5128							}
5129
5130							$(this).css({
5131								'maxWidth' : maxWidthAt75Percent + 'px'
5132							}).attr('data-restrict-width', maxWidthAt75Percent);
5133						}
5134
5135					});
5136
5137				}
5138
5139			}
5140
5141			if(preload.length > 0){
5142
5143				var parent 			= preload.parent(),
5144					parent_ratio 	= parent.width() / parent.height();
5145					preload_ratio 	= parseInt(preload.attr('width')) / parseInt(preload.attr('height')),
5146					maxWidth 		= preload.attr('width_o');
5147
5148
5149				if(preload.attr('data-restrict-width') !== undefined) {
5150					maxWidth = preload.attr('data-restrict-width');
5151				}
5152
5153				preload.css({
5154					'maxWidth'  : maxWidth + 'px',
5155					'maxHeight' : '99999px',
5156					'width'		: preload_ratio > parent_ratio ? parent.width() : parent.height() * (preload_ratio) + 'px'
5157				});
5158			}
5159
5160		 };
5161		 
5162		/**
5163		 *	Opens the site into fullscreen mode
5164		 */
5165		this.OpenFullscreen = function() {
5166			// The element we're opening
5167			var docElem = document.documentElement;
5168			
5169			// Browser checks to open fullscreen
5170			if (docElem.requestFullscreen) {
5171				docElem.requestFullscreen();
5172			} else if (docElem.mozRequestFullScreen) {
5173				docElem.mozRequestFullScreen();
5174			} else if (docElem.webkitRequestFullScreen) {
5175				docElem.webkitRequestFullScreen();
5176			} else if (docElem.msRequestFullscreen) {
5177				docElem.msRequestFullscreen();
5178			} else {
5179				// Fail, except on iOS
5180				if ( ! this.CheckIOS())
5181					return;
5182			}
5183
5184			// When we switch fullscreen states
5185			docElem.addEventListener("mozfullscreenchange",function(){
5186				if ( ! document.webkitIsFullScreen)
5187					self.Close();
5188			}, false);
5189			
5190			docElem.addEventListener("webkitfullscreenchange",function(){
5191				if ( ! document.webkitIsFullScreen)
5192					self.Close();
5193			}, false);
5194
5195			// Show the freshbox
5196			if ( ! Cargo.Config.isIE())
5197				setTimeout('$("#freshbox").css("visibility", "visible")', 100);
5198		};
5199		
5200		/**
5201		 *	Exits fullscreen mode from elsewhere
5202		 */
5203		this.CloseFullscreen = function() {		
5204			if(document.exitFullscreen) {
5205				  document.exitFullscreen();
5206			  } else if(document.mozCancelFullScreen) {
5207				  document.mozCancelFullScreen();
5208			  } else if(document.webkitCancelFullScreen) {
5209				  document.webkitCancelFullScreen();
5210			  } else if(document.msExitFullscreen) {
5211				  document.msExitFullscreen();
5212			  }
5213		};
5214		
5215		/**
5216		 * Checks the window width versus screen width when resizing 
5217		 * to toggle the fullscreen button and toolset
5218		 */
5219		this.CheckFullscreen = function() {
5220			  if( screen.width > $(window).width() + 20 ) {
5221				self.Close();
5222			  }
5223		};
5224		
5225		/**
5226		 * Can we do some more advanced stuff? True / False
5227		 * 	Returns false if your browser is new
5228		 */
5229		this.CheckOldBrowsers = function() {
5230			// If Firefox, and version 3.6 or less
5231			if( $.browser.mozilla && $.browser.version.slice(0,3) >= 1.9 ) {
5232				return false 
5233			// Check webkit, if version 3 or less
5234			} else if ( $.browser.webkit && $.browser.version.substr(0,1) >= 4 ) {
5235				return false
5236			} else {
5237				return true;	
5238			}
5239		};
5240
5241		this.CheckIOS = function() {
5242			if (navigator.userAgent.match(/i(Phone|Pod|Pad)/i)) {
5243				return true;	
5244			} else {
5245				return false;
5246			}
5247		};
5248
5249		this.GetIOSWindowSize = function() {
5250			var width = screen.width;
5251			var height = screen.height;
5252
5253			if (window.orientation !== 0) {
5254				width = screen.height;
5255				height = screen.width;
5256			}
5257
5258			if (navigator.userAgent.match(/i(Phone|Pod)/i)) {
5259				if (window.orientation === 0) {
5260					height -= 44;
5261				} else {
5262					height -= 32;
5263				}
5264			}
5265
5266			if (navigator.userAgent.match(/iPad/i))
5267				height -= 58;
5268
5269			return {
5270				width: width,
5271				height: height
5272			};
5273		};
5274
5275		this.GetIOSViewportSize = function() {
5276			var windowSize = this.GetIOSWindowSize();
5277			var scale = this.GetIOSScale();
5278
5279			return {
5280				width: (windowSize.width * scale),
5281				height: (windowSize.height * scale)
5282			};
5283		};
5284
5285		this.GetIOSScale = function() {
5286			return document.body.offsetWidth / this.GetIOSWindowSize().width;
5287		};
5288
5289		this.GetIOSZoom = function() {
5290			return document.documentElement.clientWidth / window.innerWidth;
5291		};
5292
5293		this.PreventIOSEvents = function(restrict) {
5294			if ( ! this.CheckIOS())
5295				return;
5296
5297			if (restrict) {
5298				$('body').live('touchmove', function(event) {
5299					event.preventDefault();
5300				});
5301			} else {
5302				$('body').die('touchmove');
5303			}
5304		};
5305
5306		this.getOrientation = function(){
5307			var orientation = window.orientation;
5308
5309			if(orientation === undefined) {
5310				// No JavaScript orientation support. Work it out.
5311				if(document.documentElement.clientWidth > document.documentElement.clientHeight) orientation = 'landscape';
5312				else orientation = 'portrait';
5313
5314			}
5315			else if(orientation === 0 || orientation === 180) orientation = 'portrait';
5316			else orientation = 'landscape'; // Assumed default, most laptop and PC screens.
5317
5318			return orientation;
5319		};
5320 
5321		this.getViewportScale = function(){
5322			var viewportScale = undefined;
5323
5324			// Get viewport width
5325			var viewportWidth = document.documentElement.clientWidth;
5326
5327			// Abort. Screen width is greater than the viewport width (not fullscreen).
5328			if(screen.width > viewportWidth) {
5329				return;
5330			}
5331
5332			// Get the orientation corrected screen width
5333			var orientation = this.getOrientation();
5334			var screenWidth = screen.width;
5335
5336			if(orientation === 'portrait') {
5337				// Take smaller of the two dimensions
5338				if(screen.width > screen.height) screenWidth = screen.height;
5339
5340			}
5341			else {
5342				// Take larger of the two dimensions
5343				if(screen.width < screen.height) screenWidth = screen.height;
5344
5345			}
5346
5347			// Calculate viewport scale
5348			var viewportScale = screenWidth / window.innerWidth;
5349			return viewportScale;
5350		};
5351
5352		 /**
5353		  *	Closes the lightbox
5354		  */
5355		this.Close = function() {
5356		
5357			// Reset the overflow on body
5358			if ($("body").attr("style") && this.Data.overflow != "hidden")
5359				$("body").css("overflow", "");
5360			
5361			// Return to the scroll position if IE
5362			if ( Cargo.Config.isIE() ) {
5363				$(window).scrollTop(this.Data.scroll_y);
5364				$(window).scrollLeft(this.Data.scroll_x);
5365			}
5366			
5367			// Remove the freshbox
5368			$("#freshbox").die().unbind().remove();
5369			
5370			// Reenable scaling and scrolling in iOS
5371			this.PreventIOSEvents(false);
5372
5373			shortcut.remove("Up");
5374			shortcut.remove("Down"); 
5375			shortcut.remove("Left"); 
5376			shortcut.remove("Right"); 
5377
5378			// reset viewport
5379			var viewport = document.querySelector("meta[name=viewport]");
5380
5381			if(viewport !== null && this.Data.oldViewPortContent !== undefined) {
5382				viewport.setAttribute('content', this.Data.oldViewPortContent);
5383			}
5384
5385			$(document).trigger("freshboxClose");
5386		};
5387
5388		// Return the data, keep it chaining
5389		return this.each(function() {
5390			// Keep chaining
5391		   var $this = $(this);
5392		   
5393			// Run it
5394			 self.Init();
5395			 
5396		});
5397	   
5398	
5399	};
5400	
5401})(jQuery);
5402/*
5403 *	End freshbox plugin
5404 */
5405
5406
5407/////////////////////////////////////////////////////////////////////////////////////////////////
5408/* !EVENT (document).ready */
5409$(document).ready(function() {
5410	FollowingSniff();
5411	if($("body.blog").length > 0) {
5412		Projects.Slideshow.CheckForSlideshow();
5413		Projects.Video.CheckForVideo();
5414	}
5415	
5416	// Set the project close click
5417	$(".project_index a").live("click", function() {
5418        // Load "this" into a variable
5419        Projects.Data.CloseObj = $(this);
5420        Projects.CloseProject();
5421        return false;
5422    });
5423    
5424    // Sniff for ajax links
5425    Cargo.Ajax.Init();
5426    
5427    // Sniff for fullscreen
5428    $(".entry").FreshBox();
5429    
5430	// Sniff for inspector
5431	if(location.search.replace("?","") == "inspector") {
5432		loadInspector();
5433	}
5434	
5435	// Sniff for password, auto focus
5436	if($(".password_protected").length > 0) {
5437		$(".ajax_post_form input[name='user_password']").focus();
5438	}
5439
5440	// 
5441	Projects.Video.CheckForVideo();
5442
5443	/*
5444	 *	Load the toolset and rail
5445	 *	@todo: Clean this up
5446	 */
5447
5448	if ( (Cargo.Location.GetCargoUrl() || Cargo.Location.IsUserImageGallery()) && !Cargo.Location.IsInFrame()) {
5449		$.getJSON("//"+Cargo.Config.get('CARGO_URL')+"/dispatch/cargosite/cargoToolset/"+Cargo.Location.GetDomainOrUrl()+"?callback=?", { is_following : Cargo.Location.IsFollowing() }, function(data) {
5450			if( data.error == "nocookie") {
5451				/* No cookie found */
5452				return;
5453			} else {
5454				if( data.jdata.url ) {
5455					// Set the cookie URL
5456					Cargo.Config.SetCookieUrl(data.jdata.url);
5457					Cargo.Config.SetCookieUid(data.jdata.uid);
5458
5459					if(Cargo.Location.IsCustomDomain()) {
5460						$.post(
5461							"/dispatch/cargosite/cargoToolsetLocal", 
5462							{ token : data.jdata.token, url : data.jdata.url, muid : data.jdata.muid, cv : data.jdata.cv },
5463							function(dataObj) {
5464								if(Cargo.InspectorLoading === true) {
5465									// Don't show this if we are inspecting
5466									return;
5467								}
5468
5469								if($("#follow_popup").length == 0) {
5470									$("body").append(dataObj.jdata.html);
5471								} else {
5472									$("#follow_popup").replaceWith(dataObj.jdata.html);
5473									if(Cargo.Location.IsFollowing()) {
5474										// Add the light class to this 
5475										$("#follow_popup").attr("class", "light");
5476									}
5477								}
5478							},
5479							"json");	
5480					}
5481					
5482				}
5483
5484				if( data.html ) {
5485					if( Cargo.Location.IsFollowing() ) {
5486						/*
5487						 *	Only for the following page
5488						 */
5489						$("#follow_links").html(data.html);
5490
5491					} else {
5492						$("body").prepend( data.html );
5493					}
5494
5495				}
5496
5497				loadRail(true, data.jdata.url);
5498			}
5499		});
5500	}
5501
5502	/* Always init the following click */
5503	Cargo.Follow.Init();
5504
5505	Cargo.Analytics.Init();
5506
5507	Cargo.EU_cookie_notification();
5508
5509});
5510
5511/////////////////////////////////////////////////////////////////////////////////////////////////
5512
5513/**
5514 *	Toggles the header into hi-res our out
5515 *	Called from the admin frame
5516 */
5517function ToggleHeaderHiRes(which, url) {
5518	if($('img[src$="/'+url+'"]').length > 0) {
5519		if(which == "2x") {
5520			$('img[src$="/'+url+'"]').width( Math.floor($('img[src$="/'+url+'"]').width() / 2) );
5521			$('img[src$="/'+url+'"]').height( Math.floor($('img[src$="/'+url+'"]').height() / 2) );
5522		} else {
5523			$('img[src$="/'+url+'"]').width( Math.floor($('img[src$="/'+url+'"]').width() * 2) );
5524			$('img[src$="/'+url+'"]').height( Math.floor($('img[src$="/'+url+'"]').height() * 2) );
5525		}
5526	}
5527}
5528/*
5529 *	Load the Rail
5530 */
5531function loadRail(show_toolset, cookie_url) {
5532	if(!cookie_url) {
5533		/* if no cookie url is passed, try and get from cookie */
5534		cookie_url = Cargo.Config.GetCookieUrl();
5535	}
5536
5537	$.post('/dispatch/rail/getRail', { url : Cargo.Location.GetCargoUrl(), curl : cookie_url }, function(serverData) {
5538		var data = $.parseJSON(serverData);
5539
5540		/* Write to the page */
5541		$("body").append(data.templates.masterview_tpl);
5542
5543		/* Preload the templates and model */
5544		Cargo.app.Rail.Templates = data.templates;
5545		Cargo.app.Rail.Model.LoadModels(data.models);
5546
5547		Cargo.Rail.Init();
5548		if(show_toolset) {
5549			$(document).trigger("initToolset");
5550			Cargo.app.Rail.Events.trigger("toolset:loaded");
5551		}
5552	});	
5553}
5554
5555/* !EVENT paginationComplete */
5556// Create callbacks for pagination
5557$(document).bind("paginationComplete", function(e) {
5558	if($("#home_container").length == 0){
5559		$(".entry").FreshBox();
5560	}
5561});
5562
5563/////////////////////////////////////////////////////////////////////////////////////////////////
5564/* !EVENT directLinkLoaded */
5565$(document).bind("directLinkLoaded", function(e, path) {
5566	// Any user options set that need to happen
5567	Projects.Helper.UserOptionActions();
5568	
5569	// Set the nav and thumb highlights
5570	Projects.Helper.SetNavHighlight();
5571	Projects.Helper.SetThumbHighlight();
5572	
5573	// Set the current page / paginate
5574	Projects.Helper.SetCurrentPages();
5575});
5576
5577/////////////////////////////////////////////////////////////////////////////////////////////////
5578
5579function hideContextMenu() {
5580	$("#toolset_admin").removeClass("toolset_active");
5581	$("#toolset_menu").hide();
5582
5583	toolsetToggle("on");
5584}
5585
5586/////////////////////////////////////////////////////////////////////////////////////////////////
5587
5588function showContextMenu(which) {
5589	var toolset_top = $("#toolset").css("top");
5590	var toolset_right = $("#toolset").css("right");	
5591	$("#toolset_menu").css({"top" : toolset_top , "right" : toolset_right});
5592	$("#toolset_admin").addClass("toolset_active");
5593	$("#toolset_menu").show();
5594	$("#css_inspector_trigger").live("click", function() {
5595		loadInspector();
5596		return false;
5597	});
5598}
5599
5600/////////////////////////////////////////////////////////////////////////////////////////////////
5601/**
5602 *	This loads the inspector
5603 */
5604function loadInspector() {
5605
5606	loadInspector3();
5607	/*
5608	
5609	if($("#inspector").length > 0) {
5610		// inspector is loaded
5611		
5612	} else {
5613		var dependencies = [
5614			"/_jsapps/inspector/codemirror-2.15/codemirror-package.js",
5615			"/_jsapps/inspector/jquery.mini.colors.js",
5616			"/_jsapps/inspector/jquery-ui-1.8.18.custom.min.js",
5617			"/_jsapps/inspector/inspector.css"
5618		];
5619		$.loadFiles(dependencies).done(function() {
5620			$.post(Cargo.Dispatcher.GetUrl("admin/loadInspector/" + $("#url").val()), {}, function(data) {
5621				if (data.error == "") {
5622					var jdata = $.parseJSON(data.jdata);
5623					$.loadFiles("/_jsapps/inspector/inspector-1.0.js").done(function() {
5624						// Make sure they didn't double click
5625						if( $("#inspector").length <= 0 ) {
5626							CSS.Sheet.ParseAndSet(jdata.css_data); 			// Load the CSS data
5627							Inspector.CustomHTML.SetData(jdata.html_data);	// Load the HTML data
5628							$("body").append(data.html); 					// append the inspector
5629							Inspector.init(jdata.inspector_position);		// Initialize
5630						}
5631					});
5632				} else if (data.error == "Refresh") {
5633					document.location.href = document.location + "?inspector";
5634				} else {
5635					alert("Log in to use the Inspector");
5636				}			
5637			}, "json");
5638		});
5639	}	 */
5640}
5641/////////////////////////////////////////////////////////////////////////////////////////////////
5642
5643function loadInspector3() {
5644
5645	if(window.editor !== undefined){
5646		return false;
5647	}
5648
5649	Cargo.Core = Cargo.Core || {};
5650
5651	var dependencies = [
5652		"/_jsapps/api/_cargo/_core/inspector3.js"
5653	];
5654	
5655	$.loadFiles(dependencies).done(function() {
5656
5657		var oldjQuery = $.noConflict(true);
5658
5659		oldjQuery.loadFiles(['/_jsapps/_libs/jquery/jquery-min.js']).done(function() {
5660
5661			Cargo.Core.Inspector3.load({
5662				onInit: function(inspector){
5663
5664					var $ = inspector.options.coreWindow.$,
5665						Cargo = inspector.options.coreWindow.Cargo;
5666
5667					setTimeout(function(){
5668						$(inspector.options.coreDocument).ready(function() { Cargo.app.Rail.Events.on("toolset:loaded", function() { 
5669							$("#toolset, #toolset *, #toolset_menu, #toolset_menu *, #design_panel, #design_panel *").unbind();
5670							$("#toolset_follow_pair a, #toolset_follow a").unbind();
5671							$("#toolset").fadeTo('fast', 0.3).css('pointer-events', 'none');
5672						}); });
5673
5674						$("#toolset, #toolset *, #toolset_menu, #toolset_menu *, #design_panel, #design_panel *").unbind();
5675						$("#toolset_follow_pair a, #toolset_follow a").unbind();
5676						$("#toolset").fadeTo('fast', 0.3).css('pointer-events', 'none');
5677					}, 500);
5678
5679					$("#toolset").fadeTo('fast', 0.3).css('pointer-events', 'none');
5680
5681					if(inspector.options.coreWindow.hasOwnProperty('Masonry')){
5682						if(typeof inspector.options.coreWindow.doMason === "function"){
5683
5684							var throttledMason = _.throttle(function(){
5685								inspector.options.coreWindow.$(inspector.options.coreDocument).trigger("contentResize");
5686								inspector.options.coreWindow.doMason();
5687							}, 100);
5688
5689							inspector.inspectorCore.eventManager.subscribe('style_changed', function(){
5690								throttledMason();
5691							});
5692
5693							throttledMason();
5694						}
5695					}
5696
5697					if(inspector.options.coreWindow.hasOwnProperty('shiftPosition')){
5698						if(typeof inspector.options.coreWindow.shiftPosition === "function"){
5699
5700							var throttledShiftPosition = _.throttle(inspector.options.coreWindow.shiftPosition, 100);
5701
5702							inspector.inspectorCore.eventManager.subscribe('style_changed', function(){
5703								throttledShiftPosition();
5704							});
5705
5706							throttledShiftPosition();
5707						}
5708					}
5709
5710					function addClickBehavior(){
5711
5712						if(Cargo.ReplaceLoadingAnims === undefined){
5713					 		Cargo.Core.ReplaceLoadingAnims.init();
5714					 	} else {
5715					 		Cargo.ReplaceLoadingAnims();
5716					 	}
5717					 	
5718					 	if(inspector.options.coreWindow.Design !== undefined){
5719					 		if(inspector.options.coreWindow.Design.hasOwnProperty('Resize')){
5720					 			setTimeout(function(){
5721					 				inspector.options.coreWindow.Design.Resize();
5722					 			}, 20);
5723					 		}
5724					 	}
5725
5726					 	$('img').unbind();
5727
5728						$(".slideshow_component").each(function() {
5729							// Remove and re-add everything
5730						    $(this).after('<div class="slideshow_component" id="'+$(this).attr("id")+'">'+$(this).html()+'</div>').remove();
5731						});
5732
5733						$("#mainwrapper, .project_feed_full").removeAttr("onclick").unbind("click dblclick").die("dblclick").dblclick(function(e) {
5734							if( $(this).attr("id") == "mainwrapper") {
5735								$(inspector.options.coreDocument).trigger("closeProject");
5736							
5737							} else if( $(this).attr("id") == "search_term" ) { 
5738								$(this).focus();
5739							
5740							}else if( $(this).attr("href") == "#" ) {
5741								// Don't allow # to be clicked
5742								return;
5743							
5744							} else if(!$(this).attr("rel") && $(this).attr("href") ){
5745								// Follow the link
5746								var win=inspector.options.coreWindow.open($(this).attr("href"), '_blank');
5747  								win.focus();
5748							}
5749										
5750						});
5751
5752						$("a[onclick]").each(function(){
5753							this.setAttribute('ondblclick', this.getAttribute('onclick'));
5754							this.removeAttribute('onclick');
5755						});
5756
5757						$("a[rel='history']").each(function(){
5758							$(this).unbind("click").dblclick(function(e) {
5759								Cargo.History.Load( $(this).data("hash") );
5760								e.preventDefault();
5761							});
5762						});
5763
5764						$('a:not([rel], #splash)').removeAttr("onclick").unbind('click').die('dblclick').click(function(e){
5765							e.preventDefault();
5766						}).live("dblclick", function() {
5767							var href = this.getAttribute('href');
5768
5769							if(href !== '#' && href !== '' && href.indexOf('javascript:') === -1){
5770
5771								var cargoURL				= (Cargo.hasOwnProperty('Helper') ? Cargo.Helper.GetUrl() : Cargo.Config.GetCookieUrl()),
5772									customDomain			= inspector.options.coreWindow.location.hostname.search(/cargocollective\.com/i) === -1,
5773									sameDomain				= (this.hostname.search(/cargocollective\.com/i) !== -1 ? this.pathname.split('/')[1] === cargoURL : this.hostname === inspector.options.coreWindow.location.hostname),
5774									subLocation 			= this.pathname.split('/')[(customDomain ? 1 : 2)],
5775									forbiddenSubLocation	= (subLocation === undefined ? false : subLocation.search(/^(following|admin|images)$/i) !== -1);
5776
5777								//console.log(cargoURL, subLocation, sameDomain, forbiddenSubLocation);
5778
5779								if(sameDomain && !forbiddenSubLocation) {
5780									inspector.options.coreDocument.location.href = this.getAttribute('href');
5781								} else {
5782									var newTab = inspector.options.coreWindow.open(href, '_blank');
5783										newTab.focus();
5784				 				}
5785
5786							}
5787						});
5788
5789						$(".project_next a").unbind().die().click(function(e){
5790							e.preventDefault()
5791						}).live("dblclick", function() {
5792							$(inspector.options.coreDocument).trigger("showNextProject");
5793						});
5794						
5795						// Close project
5796						$(".project_index a").unbind().die().click(function(e){
5797							e.preventDefault()
5798						}).live("dblclick", function() {
5799							$(inspector.options.coreDocument).trigger("closeProject");
5800						});
5801						
5802						// Next page (pagination)
5803						$("a.next_page").unbind().die().click(function(e){
5804							e.preventDefault()
5805						}).live("dblclick", function() {
5806							changePage(parseInt($("#current_page").val())+1);
5807						});
5808						
5809						// Prev page (pagination);
5810						$("a.prev_page").unbind().die().click(function(e){
5811							e.preventDefault()
5812						}).live("dblclick", function() {
5813							changePage(parseInt($("#current_page").val())-1);
5814						});
5815
5816						if( typeof inspector.options.coreWindow.customNavigationDblClick == "function") {
5817							inspector.options.coreWindow.customNavigationDblClick();
5818						}
5819
5820					}
5821
5822					$(inspector.options.coreDocument).bind("projectLoadComplete", function(e, pid) {
5823						addClickBehavior();
5824					});
5825
5826					$(inspector.options.coreDocument).bind("pageChangeComplete", function(e, newpage) {    
5827						addClickBehavior();
5828					});
5829
5830					$(inspector.options.coreDocument).bind("paginationComplete", function(e) {  
5831						addClickBehavior();
5832					});
5833
5834					$(inspector.options.coreDocument).bind("projectIndex", function(e, pid) {
5835						addClickBehavior();
5836					});
5837
5838					addClickBehavior();
5839				}
5840			});
5841		});
5842	});
5843
5844}
5845/////////////////////////////////////////////////////////////////////////////////////////////////
5846
5847
5848function toolsetToggle(which) {
5849	if (which == "on") {
5850		if ($("#toolset_admin a").length > 0 && $("#toolset_admin a").attr("rel").length > 0) {
5851			$("#toolset_admin a").attr("href",$("#toolset_admin a").attr("rel")).removeAttr("rel");
5852		}
5853	} else if (which == "off") {
5854		if ($("#toolset_admin a").length > 0 && $("#toolset_admin a").attr("href").length > 0 && tool_over && mouse_down) {
5855			$("#toolset_admin a").attr("rel",$("#toolset_admin a").attr("href")).removeAttr("href");
5856			mouse_down = false;
5857			showContextMenu();
5858		}
5859	}
5860}
5861
5862/////////////////////////////////////////////////////////////////////////////////////////////////
5863/* !EVENT initToolset */
5864$(document).bind("initToolset", function(e) {
5865	if($("#toolset").length > 0) {
5866		$("#toolset_admin").mousedown(function(e) {
5867			mouse_down = true;
5868			if(e.button == 2){
5869				showContextMenu();
5870			} else{
5871				setTimeout("toolsetToggle('off')", 500);
5872			}
5873			
5874		}).mouseup(function() {
5875			mouse_down = false;
5876			
5877		}).mouseover(function() { 
5878			tool_over = true;
5879			
5880		}).mouseout(function() {
5881			tool_over = false;
5882		
5883		}).click(function() { 
5884			if ($("#toolset_admin a").attr("href").length > 0 && tool_over) {
5885				document.location.href = $("#toolset_admin a").attr("href");
5886				hideContextMenu();
5887			}
5888			return false;
5889		});
5890		
5891		$("#toolset_admin").bind("contextmenu", function(e) {
5892			return false;
5893		});
5894		
5895		$(document).click(function() { 
5896			if(!mouse_down && !tool_over){
5897				hideContextMenu();
5898			}
5899	
5900		}).mouseup(function(e) { 
5901			if(e.button == 2){
5902				mouse_down = false;
5903			}
5904			setTimeout("toolsetToggle('on')", 100);
5905		});
5906		
5907		$("#toolset_menu a").bind("click mouseup mouseover", function(e) {
5908			if(e.type == "mouseover") {
5909				toolsetToggle("on");
5910			} else {
5911				// window.location.href = $(this).attr("href");
5912				hideContextMenu();
5913			}
5914		});
5915		
5916		$("#toolset_admin a").click(function(e) {
5917			if(e.ctrlKey) { 
5918				showContextMenu();
5919				return false;
5920			}
5921		});
5922		
5923		$(document).bind("projectIndex", function(e, pid){
5924			hideContextMenu();
5925		});
5926		
5927		$("#toolset_menu a:first").addClass("toolset_first");
5928		$("#toolset_menu a:last").addClass("toolset_last");
5929		
5930		$("#toolset_network_leave").click(function() { 
5931			if(confirm("Leave this network?")) return true;
5932			else return false;
5933		});
5934		
5935		$("#toolset_network_join").click(function() { 
5936			if(confirm("Join this network?")) return true;
5937			else return false;
5938		});
5939	}
5940});
5941
5942/////////////////////////////////////////////////////////////////////////////////////////////////
5943/* !EVENT networkFilterMenu */
5944$(document).bind("networkFilterMenu", function(e) {
5945	var networkFilterVisible = 0;
5946	
5947	$(".network_filter_menu a:first").addClass("network_filter_menu_first");
5948	$(".network_filter_menu a:last").addClass("network_filter_menu_last");
5949	
5950	$(".show_network_menu").click(function() {
5951		networkFilterVisible = 1;
5952		$(".network_filter_menu").show();
5953	});
5954		
5955	$(document).click(function() { 
5956		if(networkFilterVisible == 1){
5957			networkFilterVisible = 0;
5958		} else {
5959			$(".network_filter_menu").hide();
5960		}
5961	});
5962});
5963/////////////////////////////////////////////////////////////////////////////////////////////////
5964function hideNetworkFilterMenu() {
5965	var networkFilterVisible = 0;
5966	$(".network_filter_menu").hide();
5967}
5968/////////////////////////////////////////////////////////////////////////////////////////////////
5969/* !EVENT projectLoadStart */
5970$(document).bind("projectLoadStart", function(e) {
5971	/* Close toolset menu */
5972	hideContextMenu();
5973	hideNetworkFilterMenu();
5974});
5975/////////////////////////////////////////////////////////////////////////////////////////////////
5976/* !EVENT pageReady */
5977$(document).bind("pageReady", function(e, history_type) {
5978	if(history_type == "follow")  {
5979		Cargo.History.Init("following");
5980	} else if(history_type != "none") {
5981		Cargo.History.Init();
5982	}
5983	$(document).trigger("projectReady", ["first"]);
5984	$(document).trigger("loadSearch");
5985	$(document).trigger("initToolset");
5986	$(document).trigger("networkFilterMenu");
5987	if(history_type != "follow")  {
5988		$(document).trigger("keyboardShortcuts");
5989	}
5990});
5991/////////////////////////////////////////////////////////////////////////////////////////////////
5992/* !EVENT keyboardShortcuts */
5993$(document).bind("keyboardShortcuts", function(e, which) {
5994	var me = Cargo.Location.GetBaseUrl();
5995	
5996	shortcut.add("H",function() { if($(window).scrollTop() > 50) { window.scrollTo(0, 50); doscroll(0,getScrollHeight(),0);}}
5996,{ 'type':'keydown', 'disable_in_input':true, 'keycode':72 });
5997	if(which != "feed") {
5998		shortcut.add("J",function() { $(document).trigger("showNextProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':74 });
5999		shortcut.add("K",function() { $(document).trigger("showPrevProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':75 });
6000		shortcut.add("R",function() { $(document).trigger("showRandomProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':82 });
6001		shortcut.add("X",function() { $(document).trigger("closeProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':88 });
6002		shortcut.add("I",function() { $(document).trigger("closeProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':73 });
6003	} else {
6004		shortcut.add("J",function() { $(document).trigger("showNextFeedProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':74 });
6005		shortcut.add("K",function() { $(document).trigger("showPrevFeedProject"); },{ 'type':'keydown', 'disable_in_input':true, 'keycode'
6005:75 });
6006		shortcut.add("I",function() { top.document.location.href=me+"/index" },{ 'type':'keydown', 'disable_in_input':true, 'keycode':73 });
6007	}
6008	
6009	
6010	shortcut.add("Shift+F",function() { 
6011
6012		if ( ! $("body").hasClass("rail_active") ) {
6013			Cargo.app.Rail.Events.trigger("show_rail_following");
6014		} else {
6015			Cargo.app.Rail.Events.trigger("rail:hide");
6016		}
6017
6018	},{ 
6019		'type'             :'keydown', 
6020		'disable_in_input' :true, 
6021		'keycode'          :70 
6022	});
6023
6024	shortcut.add("Esc",function() { 
6025
6026		// If the freshbox isn't displayed
6027		if ( ! $("#freshbox").length > 0 ) {
6028			Cargo.app.Rail.Events.trigger("rail:hide");
6029		}
6030		
6031	},{ 
6032		'type'             : 'keydown', 
6033		'disable_in_input' : true, 
6034		'keycode'          : 27 
6035	});
6036
6037	shortcut.add("Shift+G",function() { top.document.location.href=me+"/images"; },{ 'type':'keydown', 'disable_in_input':true, 'keycode':71 });
6038
6039	/*
6040	 *	Personal site shortcuts
6041	 */
6042	shortcut.add("Shift+A",function() { top.document.location.href=me+"/admin"; },{ 'type':'keydown', 'disable_in_input':true, 'keycode'
6042:65 });
6043	shortcut.add("Shift+H",function() { top.document.location.href=me+"/admin/html"; },{ 'type':'keydown', 'disable_in_input':true, 'keycode':72 });
6044	shortcut.add("Shift+C",function() { loadInspector3(); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':67 });
6045	shortcut.add("Shift+D",function() { top.document.location.href=me+"/admin/designs"; },{ 'type':'keydown', 'disable_in_input':true, 'keycode':68 });
6046	shortcut.add("Shift+X",function() { top.document.location.href=me; },{ 'type':'keydown', 'disable_in_input':true, 'keycode':88 });
6047	shortcut.add("Shift+I",function() { loadInspector(); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':73 });
6048	shortcut.add("Shift+E",function() { if($(".editlink a").length > 0) { top.document.location.href=$(".editlink a").attr('href'); } },{ 'type':'keydown', 'disable_in_input':true, 'keycode':69 });
6049	//shortcut.add("Ctrl+Shift+I",function() { loadInspector3(); },{ 'type':'keydown', 'disable_in_input':true, 'keycode':73 });
6050	
6051});
6052/////////////////////////////////////////////////////////////////////////////////////////////////
6053/* !EVENT projectReady */
6054$(document).bind("projectReady", function(e, dataObj) {	
6055	checkForSound();
6056	Projects.Slideshow.CheckForSlideshow();
6057	Projects.Video.CheckForVideo();
6058	// Sniff for ajax links
6059    Cargo.Ajax.Init();
6060    // Freshbox
6061    $(".entry").FreshBox();
6062});
6063/////////////////////////////////////////////////////////////////////////////////////////////////
6064/* !EVENT loadSearch */
6065$(document).bind("loadSearch", function(e) {	
6066	$("#search_form_results, #search_form, #rail_search_form").submit(function(te) {
6067		$(document).trigger("doSearch", [ {
6068			"form" : $(this).attr("id"), 
6069			"term" : $('#search_term', this).val() 
6070		} ]);
6071		return false;
6072	}).keypress(function(e) {
6073		if( e.which == 13 ) { // enter key
6074			$(document).trigger("doSearch", [ {
6075				"form" : $(this).attr("id"), 
6076				"term" : $('#search_term', this).val() 
6077			} ]);
6078		}
6079	});
6080	$("#search_form #search_term, #rail_search_form #search_term").focus(function() {
6081        if($(this).val() == $(this).attr("rel")) $(this).val("");
6082    }).blur(function() {
6083        if($(this).val() == "") $(this).val($(this).attr("rel"));
6084    }).blur();
6085
6086    if($("#search_form_results").length > 0) {
6087		shortcut.add("I",function() { top.document.location.href=Cargo.Location.GetBaseUrl() }
6087,{ 'type':'keydown', 'disable_in_input':true, 'keycode':73 });
6088	}
6089});
6090/////////////////////////////////////////////////////////////////////////////////////////////////
6091/* !EVENT doSearch */
6092$(document).bind("doSearch", function(e, data) {
6093	var search_term = data.term;
6094	search_term.replace(" ","-");
6095	
6096	if ($("#following_header").length != 0) {
6097		if(location.host.indexOf("cargocollective.com") >= 0) {
6098			var loc = document.location.pathname.split("/");
6099			var url = (loc[0] != "") ? loc[0] : loc[1];
6100			var me = "//"+location.host+"/"+url;
6101		} else {
6102			var me = "//"+location.host;
6103		}
6104		document.location.href=me+"/following/search/"+search_term;
6105		
6106	} else {
6107		document.location.href=Cargo.Location.GetBaseUrl()+"/search/"+search_term;
6108	}
6109});
6110/////////////////////////////////////////////////////////////////////////////////////////////////
6111function checkForSound() {
6112	// see if there is a sound && see if soundmanager is loaded
6113	// Check for firefox
6114
6115	if(Cargo.Config.isMobile() && $(".audio_component").length > 0){
6116		loadSoundDependencies();
6117	}
6118
6119	$(".audio_component .play_pause").live('click', function() { 
6120	   var force = false;
6121	   if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
6122		  var ffversion=new Number(RegExp.$1); // capture x.x portion and store as a number
6123		  if(ffversion < 3.6) { force = true; }
6124	   } //else if($("#template").val() == "SC") { force = true; } // test for SpaceCollective
6125		
6126		$(document).trigger("audioPlayPause", [$(this).attr("rel"), $(this).attr("class").replace("play_pause ", "") ]);
6127			
6128		if(($(".audio_component").length > 0 || force == true) && typeof soundManager == "undefined") {
6129			$(this).removeClass("play").addClass("pause");
6130				
6131			loadSoundDependencies();
6132		  
6133			start_sound = $(this).parents(".audio_component").attr("id");
6134			this_play = $(this);
6135		}
6136	});
6137	
6138	if(($(".audio_component").length > 0 ) && $("#DroidFont").length <= 0) {
6139		 // Load the external font from the google api
6140		  var droidfont=document.createElement('link');
6141		  droidfont.id='DroidFont';
6142		  droidfont.setAttribute('type','text/css');
6143		  droidfont.setAttribute('rel','stylesheet');
6144		  droidfont.setAttribute('href','https://fonts.googleapis.com/css?family=Droid+Sans+Mono');
6145		  
6146		  var hd=document.getElementsByTagName('head')[0];
6147		  hd.appendChild(droidfont);
6148	};
6149	$(".progress").css("display","none");
6150	initPlayerSize();
6151}
6152
6153function loadSoundDependencies() {
6154	// check, check, doublecheck
6155	if(!soundDependenciesCalled && typeof soundManager == "undefined"){
6156		$.getScript('/_js/jquery-ui-1.8.18.custom.min.js', function(){
6157		});
6158
6159		$.getScript('/_js/soundmanager/soundmanager2-nodebug-jsmin.js', function(){
6160		});
6161		soundDependenciesCalled = true;
6162	}
6163}
6164
6165/////////////////////////////////////////////////////////////////////////////////////////////////
6166function initPlayerSize() {
6167	var total_players = $(".audio_component").length;
6168	var zero_count = 0;
6169	
6170	$(".audio_component").each(function(){
6171		if($(this).width() > 0) {
6172			// Setup playhead/progress width 
6173		   //$('.Href', this).hide();            
6174		   var position = $(".position", this);
6175		   var playhead = $(".playhead", this);
6176		   // This makes the player correctly sized based on the .Sound width property
6177		   var soundWidth = $(this).width();
6178		   var soundBordersWidth = $(".border", this).outerWidth() - $(".border", this).width();
6179		   var controlsWidth = $(".controls", this).width(soundWidth - soundBordersWidth).width();
6180		   var volumeWidth = $(".volume", this).width();
6181		   var playpauseWidth = $(".play_pause", this).width();
6182		   var spacerWidths = $(".vertical_border", this).width() * 2;
6183		   $(".border", this).width(soundWidth - soundBordersWidth);
6184		   $(".info", this).width(controlsWidth - volumeWidth - playpauseWidth - spacerWidths);
6185		  
6186		   var refWidth = $(".info", this).width();
6187		   position.width(refWidth);
6188			 
6189		   playhead
6190			 .css("width", refWidth+"px")
6191			 .css("left", 0);
6192	
6193		   var progressBordersWidth = $(".progress", this).outerWidth() - $(".progress", this).width();
6194		   $(".progress")
6195			 .css("width", (refWidth - progressBordersWidth) +"px")
6196			 .css("left", 0);
6197			
6198			if($("#home_content").length > 0) var prog_left = "35px";
6199			else var prog_left = "0px";
6200			
6201		   $(".progress_clip")
6202			 .css("position", "absolute")
6203			 .css("overflow", "hidden")
6204			 .css("width", refWidth+"px")
6205			 .css("left", prog_left);
6206		   
6207		   $(".position")
6208			 .css("left", prog_left);
6209	
6210		   $(".playhead_container", this)
6211			 .css("position", "relative")
6212			 .css("width", (playhead.outerWidth() * 2) + "px")
6213			 .css("left", ((playhead.outerWidth() * -1)) + "px");
6214	
6215		   $(".progress_container", this)
6216			 .css("position", "absolute")
6217			 .css("z-index", "-1")
6218			 .css("width", (playhead.outerWidth() * 2) + "px")
6219			 .css("left", ((playhead.outerWidth() * -1)) + "px");
6220		
6221		} // end width check
6222		else {
6223			zero_count++;
6224		}
6225	});
6226	
6227	if( zero_count > 0 && zero_count == total_players) {
6228		// This content is not yet loaded because the container is faded out
6229		// Pause for 1 sec, then enable
6230		setTimeout("initPlayerSize()", 500);
6231	}
6232}
6233/////////////////////////////////////////////////////////////////////////////////////////////////
6234// Loop through all sounds on the page and unload them
6235function unloadAudio() {
6236	$(".audio_component").each(function() {
6237		if(typeof soundManager == "object") {
6238			soundManager.unload( $(this).attr("id") );
6239		}
6240	});
6241}
6242
6243/////////////////////////////////////////////////////////////////////////////////////////////////
6244// Deprecated
6245// Wrapper for Projects class, leaving for legacy
6246function openThisPr(pid) {
6247	Projects.AjaxLoadByPid( pid );
6248	return false;
6249}
6250/////////////////////////////////////////////////////////////////////////////////////////////////
6251/* !EVENT closeProject */
6252$(document).bind("closeProject", function(e){
6253	Projects.CloseProject();
6254});
6255/////////////////////////////////////////////////////////////////////////////////////////////////
6256/* !EVENT initNextProject */
6257$(document).bind("initNextProject", function(e){
6258	$(".project_next a").die("click").live("click", function() { 
6259		if(pr_list.length > 1) $(document).trigger("showNextProject");
6260		return false;
6261	});
6262});
6263/////////////////////////////////////////////////////////////////////////////////////////////////
6264/* !EVENT showNextProject */
6265$(document).bind("showNextProject", function(e){
6266	Projects.ShowNextProject();
6267});
6268/////////////////////////////////////////////////////////////////////////////////////////////////
6269/* !EVENT showPrevProject */
6270$(document).bind("showPrevProject", function(e){
6271	Projects.ShowPreviousProject();
6272});
6273/////////////////////////////////////////////////////////////////////////////////////////////////
6274/* !EVENT showNextFeedProject */
6275$(document).bind("showNextFeedProject", function(e){
6276	Projects.ShowNextFeedProject();
6277});
6278/////////////////////////////////////////////////////////////////////////////////////////////////
6279/* !EVENT showPrevFeedProject */
6280$(document).bind("showPrevFeedProject", function(e){
6281	Projects.ShowPreviousFeedProject();
6282});
6283/////////////////////////////////////////////////////////////////////////////////////////////////
6284/* !EVENT showRandomProject */
6285$(document).bind("showRandomProject", function(e){
6286	Projects.ShowRandomProject();
6287});
6288/////////////////////////////////////////////////////////////////////////////////////////////////
6289function makeDetailLink(title) {
6290	var url = title
6291		.replace(/^\s+|\s+$/g, "")	
6292		.replace(/[_|\s]+/g, "-")
6293		.replace(/[^a-zA-Z0-9-]+/g, "")
6294		.replace(/[-]+/g, "-")
6295		.replace(/^-+|-+$/g, "")
6296		; 
6297	return url;
6298}
6299
6300/////////////////////////////////////////////////////////////////////////////////////////////////
6301/* !EVENT slideshowTransitionFinish */
6302$(document).bind("slideshowTransitionFinish", function(e, cur){
6303	var caption = $(cur).attr("caption");
6304	var caption_class = $(cur).parent().parent().parent().nextAll().attr("class");
6305	
6306	if(caption !== undefined){
6307		$(cur).parent().parent().parent().siblings('.slideshow_caption').html(caption);
6308	}
6309	else{
6310		$(cur).parent().parent().parent().siblings('.slideshow_caption').html("");
6311	}
6312				
6313});
6314/////////////////////////////////////////////////////////////////////////////////////////////////
6315function getThumbFile(file_name) {
6316	var ext = file_name.substr(file_name.lastIndexOf('.'));
6317	var name = file_name.substring(0, file_name.lastIndexOf('.'));
6318	return name+"_t"+ext
6319}
6320/////////////////////////////////////////////////////////////////////////////////////////////////
6321function getScaleSize(og_w, og_h, h) {
6322	if(og_h > h) {
6323		var scale_percent = og_h / h;
6324		var out_w = Math.floor(og_w / scale_percent);
6325		var out_h = h;
6326	} else {
6327		var out_w = og_w;
6328		var out_h = og_h;
6329	}
6330	
6331	return { "w" : out_w, "h" : out_h };
6332}
6333/////////////////////////////////////////////////////////////////////////////////////////////////
6334// if no_hostory == false, unload the history
6335// This is just a wrapper for the new method, kept for legacy usage
6336function closeThisPr(no_history) {
6337	Projects.CloseProject( no_history );
6338}
6339/////////////////////////////////////////////////////////////////////////////////////////////////
6340function changePage(newpage,limit) {
6341	$(document).trigger("pageChange", [newpage]);
6342	
6343	var cur = document.getElementById('current_page').value;
6344	var total_pages = document.getElementById('total_pages').value;
6345	var current_page = document.getElementById('page_'+cur);
6346	var current_nav = document.getElementById('nav_page_'+cur);
6347	var new_page = document.getElementById('page_'+newpage);
6348	var new_nav = document.getElementById('nav_page_'+newpage);
6349	var pagination = document.getElementById('pagination');
6350	var pid = $('#current_open').val();
6351	var design = $('#design').val();
6352	var template = $('#template').val();
6353	
6354	
6355	if(document.getElementById('pr_contain_item_'+cur)) {
6356		document.getElementById('pr_contain_item_'+cur).className = "";
6357	}
6358	
6359	// reset nav status
6360	Projects.Helper.RemoveNavHighlight();
6361	
6362	// Remove the thumb highlight
6363	Projects.Helper.RemoveThumbHighlight();
6364	
6365	
6366	// dump the old nav
6367	if(current_nav) current_nav.style.display = "none";
6368	
6369	// show the new nav
6370	if(new_nav) new_nav.style.display = "block";
6371	
6372	// dump prev page thumbs
6373	if(current_page) current_page.style.display = "none";
6374	
6375	// change pagination
6376	var pagout = "";
6377	if(newpage > 1) {
6378		if(design.indexOf("kennedy") >= 0) pagout += "&larr; ";
6379		pagout += "<a href=\"javascript:void(0)\" onclick=\"changePage("+(parseInt(newpage)-1)+","+limit+", true)\" ";
6380		pagout += "class=\"prev_page\">Prev page</a>";
6381	}
6382	
6383	if(newpage > 1 && newpage < total_pages) {
6384		if(design.indexOf("kennedy") >= 0) {
6385			pagout += "&nbsp;<span>("+newpage+" of "+total_pages+")</span>&nbsp;";
6386		
6387		} else if(design.indexOf("amsterdam") < 0 && design.indexOf("kertesz") < 0 && design.indexOf("hegel") < 0) {
6388			pagout += "<span>&nbsp;/&nbsp;</span>";
6389		}
6390	}
6391	
6392	if(design.indexOf("amsterdam") >= 0 || design.indexOf("kertesz") >= 0 || design.indexOf("hegel") >= 0) {
6393		pagout += "&nbsp;<span>"+newpage+" of "+total_pages+"</span>&nbsp;";
6394	}
6395	
6396	if(newpage < total_pages) {
6397		pagout += "<a href=\"javascript:void(0)\" onclick=\"changePage("+(parseInt(newpage)+1)+","+limit+", true)\" ";
6398		pagout += "class=\"next_page\">Next page</a>";
6399		if(design.indexOf("kennedy") >= 0) pagout += " &rarr;";
6400		
6401	}
6402	
6403	if(design.indexOf("amsterdam") < 0 && design.indexOf("kertesz") < 0 && design.indexOf("hegel") < 0) {
6404		if(design.indexOf("kennedy") >= 0 && newpage > 1) { // do nothing 
6405		} else {
6406			pagout += "&nbsp;<span>("+newpage+" of "+total_pages+")</span>";
6407		}
6408	}
6409	
6410	if($(".pagination").length > 0) $(".pagination").each(function() { $(this).html(pagout); });
6411	
6412	
6413	// show next page thumbs
6414	if(new_page) {
6415		showNextPageThumbs( newpage );
6416	}
6417	
6418	if(document.getElementById('menu_'+pid)) {
6419		$("#menu_"+pid).addClass("nav_active");	
6420	}
6421	
6422	// set new page values
6423	document.getElementById('current_page').value = newpage;
6424	curspot = cur < newpage ? (cur*limit)-1 : ((newpage-1)*limit)-1;
6425	document.getElementById('this_spot').value = curspot;
6426	
6427	if(document.getElementById('items') && template.indexOf("network") < 0 && design.indexOf("amsterdam") < 0 && design.indexOf("kertesz") < 0 && design.indexOf("hegel") < 0) shiftPosition(false);
6428	
6429	window.scrollTo(0,0);
6430	
6431	//changeHorizNav(newpage);
6432	$(document).trigger("pageChangeComplete", [newpage]);
6433	
6434}
6435
6436/**
6437 *	Shows the next page of thumbs
6438 *	Unhides the div, swaps the content
6439 */
6440function showNextPageThumbs( new_page ) {
6441	$("#page_"+new_page).show();
6442	
6443	$(".project_thumb, .project_feed_thumb").each(function() {
6444		var pid = $(this).attr("name");
6445		var thumbContainer = $("#cardthumb_"+pid);
6446		if(thumbContainer.length > 0 && thumbContainer.attr("name") != "") {
6447			//thumbContainer.innerHTML = "<img src=\""+thumbContainer.getAttribute("name")+"\" border=\"0\" />";
6448			thisW = thumbContainer.attr("width") ? 'width="'+thumbContainer.attr("width")+'"' : "";
6449			thisH = thumbContainer.attr("height") ? 'height="'+thumbContainer.attr("height")+'"' : "";
6450			thisImg = thumbContainer.attr("name");
6451			thumbContainer.html("<img src=\""+thisImg+"\" border=\"0\" "+thisW+" "+thisH+" />");
6452			thumbContainer.attr("name","");
6453		}
6454	});
6455}
6456/////////////////////////////////////////////////////////////////////////////////////////////////
6457function changeHorizNav(newpage) {
6458	// move pages, pagination and following if nav is horiz
6459	if($(".nav_container").hasClass("horizontal")) {
6460		if($("#pagination").length > 0) $("#nav_page_"+newpage).append($("#pagination"));
6461		if($(".nav_follow").length > 0) $("#nav_page_"+newpage).append($(".nav_follow"));
6462		if(($(".page_link").length > 0 || $(".link_link").length > 0) && $("#sticky_page").val() != "none") {
6463			if($("#sticky_page").val() == "top") $("#nav_page_"+newpage).prepend($(".page_link")).prepend($(".link_link"));
6464			else {
6465				$("#nav_page_"+newpage).append($(".page_link")).append($(".link_link"));
6466				if($("#pagination").length > 0) $("#nav_page_"+newpage).append($("#pagination"));
6467				if($(".nav_follow").length > 0) $("#nav_page_"+newpage).append($(".nav_follow"));
6468			}
6469		}
6470	}
6471}
6472/////////////////////////////////////////////////////////////////////////////////////////////////
6473function FollowingSniff() {
6474	if($("#following_header").length > 0 || $(".follow_container.home").length > 0) {
6475		if($(".follow_container.home").length > 0) {
6476			$.loadFiles("/_js/cargo.following.package.js").done(function() {
6477				Cargo.Following.PreparePagination(); 
6478			});
6479			
6480		} else {
6481			//Cargo.History.InitFollowlist();
6482			Cargo.Following.PreparePagination();
6483		}
6484		$(".recent_following_thumb:odd").addClass("even");
6485	}
6486}
6487/////////////////////////////////////////////////////////////////////////////////////////////////
6488
6489Cargo.Follow = {
6490
6491	Data : {
6492		'el' : false
6493	},
6494
6495	/**
6496	 *	bind all follow/unfollow links	
6497	 */
6498	Init : function() {
6499
6500		$("a[rel='follow']").die('click').live('click', function() {
6501			Cargo.Follow.ShowFollowWindow($(this));
6502			return false;
6503		});
6504
6505		$(".follow_popup_ok").die('click').live('click', function() {
6506			Cargo.Follow.DoFollow($(this).attr('data-my_uid'), $(this).attr('data-my_cv'), $(this).attr('data-their_uid'), $(this).attr('data-type'));
6507			return false;
6508		});
6509
6510		$(".follow_popup_cancel").die('click').live('click', function() {
6511			Cargo.Follow.Hide();
6512			return false;
6513		});
6514
6515	},
6516
6517	Show : function() {
6518		Cargo.ReplaceLoadingAnims();
6519		
6520		$("#follow_popup").show();
6521
6522		if(typeof Cargo.Home == "object") {
6523			Cargo.Home.Personal.RemoveEnterShortcut();
6524		}
6525
6526		// Key bindings
6527		shortcut.add("return",function() {
6528			$("a.follow_popup_ok").click();
6529        },{ 'type':'keydown', 'disable_in_input':true, 'propagate': false, 'keycode':13 });
6530
6531        shortcut.add("esc",function() {
6532			$("a.follow_popup_cancel").click();
6533        },{ 'type':'keydown', 'disable_in_input':true, 'propagate': false, 'keycode':27 });
6534	},
6535
6536	Hide : function() {
6537
6538		// Hide the element
6539		$("#follow_popup").hide();
6540
6541		// Remove the keys
6542		shortcut.remove("return");
6543
6544		if(typeof Cargo.Home == "object") {
6545			Cargo.Home.Personal.AddEnterShortcut();
6546		}
6547
6548	},
6549
6550
6551	ShowFollowWindow : function(el) {
6552		Cargo.Follow.Show();
6553
6554		$("#follow_popup_note").html(ucFirst($(el).attr("data-type"))+" "+$(el).attr('data-displayurl')+"?");
6555		$(".follow_popup_ok").attr({
6556			'data-their_uid': $(el).attr("data-their_uid"),
6557			'data-my_uid' 	: $(el).attr("data-my_uid"),
6558			'data-my_cv' 	: $(el).attr("data-my_cv"),
6559			'data-type'		: $(el).attr("data-type")
6560		});
6561		Cargo.Follow.Data.el = el;
6562
6563	},
6564
6565	DoFollow : function(my_uid, my_cv, their_uid, type) {
6566		$("#following_loadspin").show();
6567		$.post(
6568			Cargo.Dispatcher.GetUrl("user/doFollow"), 
6569			{ my_uid:my_uid, my_cv:my_cv, their_uid:their_uid, type:type }, 
6570			Cargo.Follow.FollowResult,
6571			"json"
6572		);
6573		
6574	},
6575
6576	FollowResult : function(dataObj) {
6577		$("#following_loadspin").hide();
6578
6579		if(typeof Cargo.Home == "object") {
6580			Cargo.Home.Personal.hideProjectAfterUnfollow(Cargo.Follow.Data.el);
6581
6582		} else if(Cargo.Follow.Data.el.attr("id")) {
6583			$("#follow_links").html(dataObj.html);
6584			$("#rail_follow").html(dataObj.html);
6585
6586			// update "template"
6587			if(Cargo.app.Rail.view.following) {
6588				Cargo.app.Rail.Templates.following_tpl = Cargo.app.Rail.view.following.el.innerHTML;
6589			}
6590			
6591		} else {
6592			Cargo.Follow.Data.el.replaceWith(dataObj.jdata.tag_html);
6593		}
6594
6595		Cargo.Follow.Hide();
6596	}
6597
6598	
6599
6600}
6601
6602/////////////////////////////////////////////////////////////////////////////////////////////////
6603function changeFollowPage(newpage) {
6604	if(newpage) {
6605		if(newpage.indexOf("page") >= 0) var ishome = false;
6606		else var ishome = true;
6607		if(!ishome) newpage=parseInt(newpage.replace("page",""));
6608		var cur = document.getElementById('current_page').value;
6609		var limit = parseInt(document.getElementById('total_pages').value);
6610		var current_page = document.getElementById('page_'+cur);
6611		var new_page = document.getElementById('page_'+newpage);
6612		var pagination = document.getElementById('pagination');
6613		
6614		// change pagination
6615		var pagout = "";
6616		if(!ishome) {
6617			var prevlink = "#page"+(parseInt(newpage)-1);
6618			var nextlink = "#page"+(parseInt(newpage)+1);
6619		} else {
6620			var prevlink = "javascript:void(0)\" onclick=\"changeFollowPage('"+(parseInt(newpage)-1)+"')";
6621			var nextlink = "javascript:void(0)\" onclick=\"changeFollowPage('"+(parseInt(newpage)+1)+"')";
6622		}
6623		if(newpage > 1) pagout += "<a href=\""+prevlink+"\" rel=\"history\">Prev page</a>";
6624		if(newpage > 1 && newpage < limit) pagout += "<span>&nbsp;/&nbsp;</span>";
6625		if(newpage < limit) pagout += "<a href=\""+nextlink+"\" rel=\"history\">Next page</a>";
6626		pagout += "&nbsp;<span>("+newpage+" of "+limit+")</span>";
6627		
6628		if($(".follow_pagination").length > 0) $(".follow_pagination").each(function() { $(this).html(pagout); });
6629		$("#page_"+newpage+" img").each(function(){ $(this).attr("src",$(this).attr("name")); });
6630		
6631		// show next page thumbs
6632		if(new_page) {
6633			new_page.style.display = "block";
6634			current_page.style.display = "none";
6635		}
6636		
6637		// set new page values
6638		document.getElementById('current_page').value = newpage;
6639		
6640		window.scrollTo(0,0);
6641	}
6642	
6643}
6644
6645/////////////////////////////////////////////////////////////////////////////////////////////////
6646
6647/////////////////////////////////////////////////////////////////////////////////////////////////
6648	if(!Array.indexOf){
6649	    Array.prototype.indexOf = function(obj){
6650	        for(var i=0; i<this.length; i++){
6651	            if(this[i]==obj){
6652	                return i;
6653	            }
6654	        }
6655	        return -1;
6656	    }
6657	}
6658/////////////////////////////////////////////////////////////////////////////////////////////////
6659function feedAnchor(anchorLink) {
6660	url = "item_"+anchorLink;
6661	setTimeout('scrollto(url)',200);
6662}
6663/////////////////////////////////////////////////////////////////////////////////////////////////
6664function anchorTo(which,amount_above,do_move) {
6665	if(document.getElementById(which)) {
6666		if(do_move) {
6667			$.scrollTo("#"+which, 0, {offset: {top:-amount_above-50}});
6668			$.scrollTo("#"+which, 300, {offset: {top:-amount_above}});
6669		} else {
6670			$.scrollTo("#"+which, 0, {offset: {top:-amount_above}});
6671		}
6672	}
6673}
6674/////////////////////////////////////////////////////////////////////////////////////////////////
6675
6676function scrollto(obj) {
6677	var t=0;	
6678	var pad = 35;
6679	var strTop = document.getElementById(obj).style.top;
6680	if(strTop=="") doscroll(0,getScrollHeight(),0);
6681	else {
6682		pxPos = strTop.indexOf("px");
6683		targetYPos = parseInt(strTop.substring(0, pxPos)) - pad;
6684		var y = getScrollHeight(); //document[getDocElName()].scrollTop;
6685		clearTimeout(timer);
6686		
6687		//alert(getScrollHeight()+' / '+targetYPos+' / '+y);
6688		doscroll(targetYPos,y,t);
6689	}
6690}
6691/////////////////////////////////////////////////////////////////////////////////////////////////
6692function doscroll(targetYPos,y,t) {
6693	var speed = 6;
6694	var diff = targetYPos - y;
6695	var steps = diff/(speed*speed);
6696	t += (t+steps)/diff;
6697	newY = (t==1) ? y+diff : y + (diff * (-Math.pow(2, -20 * t/1) + 1));
6698	if(t) window.scrollTo(0, newY);
6699	
6700	if(t >= 1 || lastT == t || !t) clearTimeout(timer);
6701	else timer=setTimeout("doscroll("+targetYPos+","+y+","+t+")",1);
6702	
6703	lastT = t;
6704	
6705	return false;
6706}
6707/////////////////////////////////////////////////////////////////////////////////////////////////
6708function getDocElName(){
6709	if(document.compatMode && document.compatMode == "CSS1Compat") return "documentElement";
6710	else return "body";
6711}
6712/////////////////////////////////////////////////////////////////////////////////////////////////
6713function handle(delta) {
6714	clearTimeout(timer);
6715}
6716/////////////////////////////////////////////////////////////////////////////////////////////////
6717function wheel(event){
6718	var delta = 0;
6719	if (!event) event = window.event;
6720	if (event.wheelDelta) {
6721		delta = event.wheelDelta/120; 
6722		if (window.opera) delta = -delta;
6723	} else if (event.detail) {
6724		delta = -event.detail/3;
6725	}
6726	if (delta)	handle(delta);
6727}
6728/////////////////////////////////////////////////////////////////////////////////////////////////
6729/* Initialization code. */
6730if (window.addEventListener)
6731	window.addEventListener('DOMMouseScroll', wheel, false);
6732window.onmousewheel = document.onmousewheel = wheel;
6733
6734
6735/////////////////////////////////////////////////////////////////////////////////////////////////
6736function di(id,name){
6737	if (document.images) document.images[id].src=eval(name+".src");
6738}
6739/////////////////////////////////////////////////////////////////////////////////////////////////
6740function getadmin(url) {
6741	document.location.href=url+"/admin";
6742}
6743/////////////////////////////////////////////////////////////////////////////////////////////////
6744function closeadmin(url) {
6745	parent.document.location="/"+url;
6746}
6747/////////////////////////////////////////////////////////////////////////////////////////////////
6748function cargoToolset(doshow) {
6749	if(doshow) {
6750		$("#toolset").css("display","block");
6751		//$("#toolsetframe").remove(); // breaks safari
6752		$(document).trigger("showToolset");
6753	}
6754}
6755/////////////////////////////////////////////////////////////////////////////////////////////////
6756function detectBrowser() {
6757	var browser=navigator.appName;
6758	var b_version=navigator.appVersion;
6759	var version=parseFloat(b_version);
6760	return browser;
6761}
6762/////////////////////////////////////////////////////////////////////////////////////////////////
6763function getScrollHeight() {
6764    var y;
6765    if (self.pageYOffset) {
6766        y = self.pageYOffset;
6767    } else if (document.documentElement && document.documentElement.scrollTop) {
6768        y = document.documentElement.scrollTop;
6769    } else if (document.body) {
6770        y = document.body.scrollTop;
6771    }
6772    return parseInt(y);
6773}
6774/////////////////////////////////////////////////////////////////////////////////////////////////
6775function getScrollWidth() {
6776    var x;
6777    if (self.pageXOffset) {
6778        x = self.pageXOffset;
6779    } else if (document.documentElement && document.documentElement.scrollLeft) {
6780        x = document.documentElement.scrollLeft;
6781    } else if (document.body) {
6782        x = document.body.scrollLeft;
6783    }
6784    return parseInt(x);
6785}
6786/////////////////////////////////////////////////////////////////////////////////////////////////
6787function truncateText(trunc,len, dir) {
6788	if (trunc.length > len) {
6789		if(dir == "normal") trunc = trunc.substring(0, len)+'...';
6790		else if(dir == "center") trunc = trunc.substring(0, (len/2))+'…'+trunc.substring(trunc.length, trunc.length-(len/2));
6791		else trunc = '...'+trunc.substring(trunc.length, trunc.length-len);
6792	}
6793	return trunc;
6794}
6795/////////////////////////////////////////////////////////////////////////////////////////////////
6796function array_search(needle, haystack) {
6797    var key = '';
6798	for (key in haystack) {
6799		if (parseInt(haystack[key]) === parseInt(needle)) {
6800			return key;
6801		}
6802	}
6803	return false;
6804}
6805/////////////////////////////////////////////////////////////////////////////////////////////////
6806function arfind(ar,value) {
6807	for(i=0;i<ar.length;i++) {
6808		if(ar[i] == value) {
6809			spot = i;
6810			break;
6811		}
6812	}
6813	return spot;
6814}
6815/////////////////////////////////////////////////////////////////////////////////////////////////
6816// Facebook comments
6817// NOTE: There is a duplicate of this function in /_jsapps/api/_cargo/functions.js
6818	function fbComments(variant, fbwidth, fbnum){
6819		addScript("http://connect.facebook.net/en_US/all.js#xfbml=1");
6820		var f_url =
6821			design =
6822			template =
6823			padding = "";
6824		var margin = "30px 0 30px 0";
6825		var element= ".project_bottom";
6826		var colorscheme = (variant == "dark") ? "dark" : "light";
6827		
6828		fbwidth = (!fbwidth) ? 560 : fbwidth;
6829		fbnum = (!fbnum) ? 15 : fbnum;
6830		
6831		$(document).ready(function() {
6832			// Define the template and design
6833			
6834			design = $("input#design").val();
6835			template = $("input#template").val();
6836			
6837			// If it's feed go for it
6838			if(	Cargo.Config.GetCurrentPageType() == "project" && 
6839				($("#detailbottom").length > 0 || $("#content_container.permalink_page").length > 0 || $("#items_container.permapage").length > 0)
6840			  ) {
6841            	
6842            	// Set the current page URL
6843				// f_url = encodeURIComponent(window.location.href.replace("#","/"));
6844				f_url = window.location.href.replace("#","/");
6845				
6846				if(design == "ozfeed" || design == "ozfeed-alt") {
6847            		element = ".project_content .clear:last";
6848            	} else {
6849            		element = ".project_footer";
6850            	}
6851
6852            	// Create the element
6853            	$(element).after('<div class="fb_comments" style="width: '+fbwidth+'; margin: '+margin+'; padding: '+padding+';"><fb:comments href="'+f_url+'" width="'+fbwidth+'" num_posts="'+fbnum+'" colorscheme="'+colorscheme+'"></fb:comments></div>');
6854			}
6855			
6856			// Also add a comment count on Feed
6857			if(template == "feed") {
6858				if($("#detailbottom").length <= 0) {
6859					fbCommentCount();
6860					$(document).bind("paginationComplete", function(e, dataObj) {
6861						fbCommentCount();
6862					});
6863				}
6864			}
6865		});
6866		
6867		// For everything but Feed / SC
6868		$(document).bind("projectLoadComplete", function(e, pid){
6869			fbCommentLoad(pid, variant, fbwidth, fbnum);
6870        });
6871       
6872        
6873        // For everything but Feed / non-SC
6874		$(document).bind("SCprojectLoadComplete", function(e, pid){
6875			// fbCommentLoad(pid, variant, fbwidth, fbnum);
6876        });
6877        
6878	}
6879/////////////////////////////////////////////////////////////////////////////////////////////////
6880// Facebook comment count for Feed
6881	function fbCommentCount() {
6882		$(".project_footer:not(:has(>iframe))").each(function(){
6883			var pid = Cargo.SocialMedia.GetNearestPid( $(this) ),
6884				direct_link = Cargo.Location.GetDirectLink( pid );
6885			
6886			$(this).append('<br/><iframe class="fb_comments_iframe" src="http://www.facebook.com/plugins/comments.php?href=+'+direct_link+'&permalink=1" scrolling="no" frameborder="0" style="border:none; overflow:hidden; width:130px; height:16px; margin-top: 10px;" allowTransparency="true"></iframe> ');
6887		});
6888	}
6889/////////////////////////////////////////////////////////////////////////////////////////////////
6890// Load FaceBook comments for non-feed designs
6891	function fbCommentLoad(pid, variant, fbwidth, fbnum) {
6892		var margin = "30px 0 30px 0";
6893		var timeout = 500;
6894		var template = $("input#template").val();
6895		var design = $("input#design").val();
6896		var domain = $("input#is_domain").val();
6897		var colorscheme = (variant == "dark") ? "dark" : "light";
6898		var position = "before";
6899		var element= ".project_bottom";
6900		
6901		if( !pid ) {
6902			// get the open project
6903			if( $("#current_open").length > 0 && $("#current_open").val() != "none") {
6904				pid = $("#current_open").val();
6905				
6906			} else {
6907				return false;
6908			}
6909		}
6910		
6911		// If you're on a project
6912		if(array_search(pid, pr_list)){
6913		    // Load the Facebook comments script again, for whatever reason(s)
6914			$.getScript("http://connect.facebook.net/en_US/all.js#xfbml=1", function() { 
6915				f_url = Cargo.Location.GetDirectLink( pid );
6916				
6917			    // FB events
6918				FB.Event.subscribe('xfbml.render', function(response){
6919					if(typeof reinitializeScrolling == 'function') {
6920						setTimeout("reinitializeScrolling(false,'main')",timeout);
6921					
6922					} else if(typeof shiftPosition == 'function') {
6923						setTimeout("shiftPosition()",timeout);
6924					}
6925					
6926			    });
6927				FB.Event.subscribe('comment.create', function(response){
6928					if(typeof reinitializeScrolling == 'function') {
6929						setTimeout("reinitializeScroll'ing(false,'main')",timeout);
6930					
6931					} else if(typeof shiftPosition == 'function') {
6932						setTimeout("shiftPosition()",timeout);
6933					}
6934			    });
6935			    FB.Event.subscribe('comment.remove', function(response){
6936					if(typeof reinitializeScrolling == 'function') {
6937						setTimeout("reinitializeScrolling(false,'main')",timeout);
6938					
6939					} else if(typeof shiftPosition == 'function') {
6940						setTimeout("shiftPosition()",timeout);
6941					}
6942			    });
6943				
6944				// Design specific interventions
6945				if(template == "limelight") {
6946					margin = "0 0 30px 0";
6947					
6948				} else if(design == "kant") {
6949					margin = "30px 30px 2px 30px";
6950					padding = "0 0 30px 0";
6951					
6952				} else if(design == "hegel") {
6953					margin = "30px auto 30px auto";
6954					
6955				} else if(design == "nietzsche") {
6956					margin = "-30px 0 50px 0";
6957				
6958				} else if(design == "kennedy" || design == "kennedy-alt") {
6959					element = ".project_footer";
6960					position = "after";
6961					
6962				} else if(design == "landsat") {
6963					element = ".project_text";
6964					position = "inside";
6965					fbwidth = 480;
6966				}
6967				
6968				
6969				if(position == "after") {
6970					$(element).after('<div class="fb_comments" style="width: '+fbwidth+'; margin: '+margin+'; padding: '+padding+';"><fb:comments href="'+f_url+'" width="'+fbwidth+'" num_posts="'+fbnum+'" colorscheme="'+colorscheme+'"></fb:comments></div>');
6971				} else if(position == "inside") {
6972					$(element).append('<div class="fb_comments" style="width: '+fbwidth+'; margin: '+margin+'; padding: '+padding+';"><fb:comments href="'+f_url+'" width="'+fbwidth+'" num_posts="'+fbnum+'" colorscheme="'+colorscheme+'"></fb:comments></div>');
6973				} else {
6974					$(element).before('<div class="fb_comments" style="width: '+fbwidth+'; margin: '+margin+'; padding: '+padding+';"><fb:comments href="'+f_url+'" width="'+fbwidth+'" num_posts="'+fbnum+'" colorscheme="'+colorscheme+'"></fb:comments></div>');
6975				}
6976				
6977				// Force FB to re-parse the comments
6978				FB.XFBML.parse();
6979				
6980			});
6981		}
6982	}
6983/////////////////////////////////////////////////////////////////////////////////////////////////
6984function addScript(script_file, id) {
6985	var scrpt=document.createElement('script');
6986		scrpt.setAttribute('type','text/javascript');
6987		scrpt.setAttribute('src',script_file);   
6988		if( id ) scrpt.setAttribute('id',id);   
6989	var hd=document.getElementsByTagName('head')[0];
6990		hd.appendChild(scrpt);
6991}
6992/////////////////////////////////////////////////////////////////////////////////////////////////
6993function addCSS(css_file) {
6994	var scrpt=document.createElement('link');
6995		scrpt.setAttribute('type','text/css');
6996		scrpt.setAttribute('rel','stylesheet');
6997		scrpt.setAttribute('href',css_file);   
6998	var hd=document.getElementsByTagName('head')[0];
6999		hd.appendChild(scrpt);
7000}
7001
7002/**
7003 *	This inserts a new element into the dom
7004 *	Used by the admin frame, so that we can use jQuery
7005 */
7006function addElementIntoDOM( existing_id, new_html, which) {
7007	if(which == "before") {
7008		$("#"+existing_id).before( new_html );		
7009	} else {
7010		$("#"+existing_id).after( new_html );
7011	}
7012}
7013/**
7014 *	Deletes an element from the dom
7015 *	Used by the admin frame for live preview
7016 */
7017function deleteElementFromDOM( element_id ) {
7018	// Check if there is a br after, if so remove that too
7019	if($("#"+element_id).next().get(0).tagName.toLowerCase() == "br") {
7020	    $("#"+element_id).next().remove();
7021	}
7022	
7023	$("#"+element_id).remove();
7024}
7025
7026/**
7027 *	Returns a jquery object based on the input
7028 *	Used by the admin frame for live preview
7029 *	Tries for class, then id, then tag
7030 *	Usefull because we can return a jQuery element 
7031 *	to a different frame
7032 */
7033function getElementByInput( which ) {
7034	if( $( "."+which ).length > 0 ) {
7035		return $( "."+which );
7036		
7037	} else if( $( "#"+which ).length > 0 ) {
7038		return $( "#"+which );
7039	
7040	} else if( $( which ).length > 0 ) {
7041		return $( which );
7042		
7043	}
7044}
7045
7046/////////////////////////////////////////////////////////////////////////////////////////////////
7047function stripslashes( str ) {
7048    return (str+'').replace(/\0/g, '0').replace(/\\([\\'"])/g, '$1');
7049}
7050/////////////////////////////////////////////////////////////////////////////////////////////////
7051function addslashes (str) {
7052	return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
7053}
7054/////////////////////////////////////////////////////////////////////////////////////////////////
7055function stripTrailingSlash( str ) {
7056    if(str && str.substr(-1) == '/' && str.length > 1) {
7057        return str.substr(0, str.length - 1);
7058    }
7059    return str;
7060}
7061/////////////////////////////////////////////////////////////////////////////////////////////////
7062function stripLeadingSlash( str ) {
7063    if(str && str.charAt(0) == '/' && str.length > 1) {
7064        return str.substr(1, str.length);
7065    }
7066    return str;
7067}
7068/////////////////////////////////////////////////////////////////////////////////////////////////
7069function in_array (needle, haystack, argStrict) {
7070    var key = '',
7071        strict = !! argStrict;
7072
7073    if (strict) {
7074        for (key in haystack) {
7075            if (haystack[key] === needle) {
7076                return true;
7077            }
7078        }
7079    } else {
7080        for (key in haystack) {
7081            if (haystack[key] == needle) {
7082                return true;
7083            }
7084        }
7085    }
7086
7087    return false;
7088}
7089/////////////////////////////////////////////////////////////////////////////////////////////////
7090function readCookie(name) {
7091	var nameEQ = name + "=";
7092	var ca = document.cookie.split(';');
7093	for(var i=0;i < ca.length;i++) {
7094		var c = ca[i];
7095		while (c.charAt(0)==' ') c = c.substring(1,c.length);
7096		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
7097	}
7098	return null;
7099}
7100/////////////////////////////////////////////////////////////////////////////////////////////////
7101function setCookie(c_name,value,exdays) {
7102	var exdate=new Date();
7103	exdate.setDate(exdate.getDate() + exdays);
7104	var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
7105	document.cookie=c_name + "=" + c_value;
7106}
7107/////////////////////////////////////////////////////////////////////////////////////////////////
7108function testIE() {
7109	return Cargo.Config.isIE();
7110}
7111/////////////////////////////////////////////////////////////////////////////////////////////////
7112function ucFirst(str) {
7113	return (str) ? str.charAt(0).toUpperCase() + str.slice(1) : str;
7114}
7115/////////////////////////////////////////////////////////////////////////////////////////////////
7116function getMacVersion() {
7117	var MacVersion = 0;
7118	if(/Mac OS X\s(\d+\_\d+)|(\d+\.\d+)/.test(navigator.userAgent)) {
7119		var MacInfo = /Mac OS X\s(\d+\.\d+)|(\d+\_\d+)/.exec(navigator.userAgent)
7120		if(MacInfo) {
7121			if(MacInfo[0].length > 5) {
7122				MacVersion = MacInfo[1];
7123			} else {
7124				MacVersion = MacInfo[0].replace("_",".");
7125			}
7126		}
7127	};
7128	
7129	return MacVersion;
7130}
7131/////////////////////////////////////////////////////////////////////////////////////////////////
7132
7133var HiRes = window.HiRes || {};
7134
7135HiRes.active = false;
7136
7137HiRes.Queue = {
7138	STATE_LOADING: 0,
7139	STATE_COMPLETE: 1,
7140	STATE_ERROR: -1,
7141	ID: 'hi-res-queue',
7142	FILE_EXTENSION: /(?:\.([^.]+))?$/,
7143	FILE_NAME: /(?:\/([^\/]+))?$/,
7144	element: null,
7145
7146	init: function() {
7147		$('body').append('<div id="' + this.ID + '" style="display: none;" />');
7148		this.element = $('#' + this.ID);
7149	},
7150
7151	search: function() {
7152		if ( $('img[data-hi-res]').length == 0 || window.devicePixelRatio < 1.5) {
7153			return;
7154		}
7155
7156		// $('[data-mid], div.thumb_image img').map(function() {
7157		$('[data-hi-res]').map(function() {
7158			// @TODO Determine means to ignore slideshow thumbnails?
7159			if (this.nodeName === 'IMG') {
7160				HiRes.Queue.push(this);
7161			}
7162		});
7163	},
7164
7165	push: function(img) {
7166		//var img_src = img.getAttribute('data-high-res');
7167		var hi_res_src = img.getAttribute('data-hi-res');
7168		var mid = $(img).data('mid');
7169		// Hack to support thumbnails
7170		var queue_id = mid ? 'hi-res-queue-' + mid : 'hi-res-queue-' + (hi_res_src.match(this.FILE_NAME)[1]).replace(/[\W\.(_2x)]/g, '');
7171		var queue_img = $('#' + queue_id);
7172
7173		if (queue_img.length) {
7174			switch (queue_img.attr('data-hi-res-status')) {
7175				case this.STATE_COMPLETE:
7176					return this.handleCachedImage(queue_img, img);
7177				case this.STATE_LOADING:
7178					return this.handleDuplicateImage(queue_img, img);
7179				default:
7180					return;
7181			}
7182		} else {
7183			this.element.append('<img id="' + queue_id + '" data-hi-res-status="' + this.STATE_LOADING + '">');
7184			queue_img = $('#' + queue_id);
7185			queue_img.data('lo-res-images', [img]);
7186			queue_img.one('load', function() {
7187				HiRes.Queue.handleLoad(queue_img);
7188			}).one('error', function() {
7189				HiRes.Queue.handleError(queue_img);
7190			}).attr('src', hi_res_src);
7191		}
7192	},
7193
7194	handleCachedImage: function(queue_img, img) {
7195		img.src = queue_img.attr('src');
7196	},
7197
7198	handleDuplicateImage: function(queue_img, img) {
7199		var lo_res_images = queue_img.data('lo-res-images');
7200		lo_res_images.push(img);
7201		queue_img.data('lo-res-images', lo_res_images);
7202	},
7203
7204	handleLoad: function(queue_img) {
7205		var hi_res_src = queue_img.attr('src');
7206		queue_img.attr('data-hi-res-status', this.STATE_COMPLETE);
7207		queue_img.data('lo-res-images').map(function(img) {
7208			img.src = hi_res_src;
7209		});
7210	},
7211
7212	handleError: function(queue_img) {
7213		queue_img.attr('data-hi-res-status', this.STATE_ERROR);
7214	}
7215};
7216
7217HiRes.Loader = {
7218	init: function() {
7219				checkPixelRatio();
7220
7221				function checkPixelRatio() {
7222					var prevDevicePixelRatio = parseFloat($.cookie('userPixelRatio'));
7223					
7224					// if(prevDevicePixelRatio != window.devicePixelRatio) {
7225						if(window.devicePixelRatio > 1.5) {
7226							enableHiRes();
7227						} else {
7228							disableHiRes();
7229						}
7230					// }
7231
7232					$.cookie('userPixelRatio', window.devicePixelRatio, {path: '/'});
7233				}
7234
7235				function disableHiRes() {
7236					$.post("/dispatch/cargosite/cargoUseHiRes", { use : false }, function() {}, "json");
7237				}
7238
7239				function enableHiRes() {
7240					$.post("/dispatch/cargosite/cargoUseHiRes", { use : true }, function() {}, "json");
7241
7242					$(document).bind("projectLoadComplete", function(e, pid) {
7243						HiRes.Queue.search();
7244					});
7245
7246					$(document).bind("pageChangeComplete", function(e, newpage) {  
7247						HiRes.Queue.search();
7248					});
7249
7250					$(document).bind("paginationComplete", function(e) {  
7251						HiRes.Queue.search();
7252					});
7253
7254					HiRes.active = true;
7255					HiRes.Queue.init();
7256					HiRes.Queue.search();
7257				}
7258
7259				// listen to changes while page is loaded
7260				try {
7261					var MediaQueryList = window.matchMedia("(-webkit-min-device-pixel-ratio: 1.5)");
7262
7263		            if (typeof MediaQueryList.addListener === "function") {
7264		                MediaQueryList.addListener(function(){
7265		                	checkPixelRatio();
7266		                });
7267		            }
7268				} catch(err) {
7269					// matchMedia does not exist
7270				}
7271			}
7272};
7273
7274$(function(){
7275	HiRes.Loader.init();
7276});

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.