PageSourceSearch

https://stjohnschurchstanmore.org.uk/Images/Content/2755/Templates/54664/js/script.js

js stjohnschurchstanmore.org.uk collected 2026-09-25 07:54:55 UTC 32,183 bytes, 759 lines download raw bytes

1/*
2	Main ChurchInsight template Javascript/JQuery file.
3	WARNING - do not edit this file unless you know exactly what you are doing.
4	Better to use the scriptOverRide.js file to add local changes to a template.
5	If you need advice, contact ChurchInsight Support.
6*/
7
8// This file runs after the web-page has loaded, as there is a "defer" attribute on the <script> tag in the HTML header.
9// The preloaded JQuery version is V1.10.2.
10
11$(document).ready(function () 
12{ 'use strict';
13
14// Custom values set here. Change for a particular customer.
15var SlideShowDefaultButtonText = 'Read more';
16var bAddDarkenedOverlayForSlideShowCaptions = false;
17var bSplitFooterAddressAtSecondComma = true;
18
19// #################### Define some useful functions #######################
20
21// We have to put all functions here, as OSX does not allow functions to be inside if statements.
22
23// function to turn a slice name into a selector reference for the corresponding <section> tag
24function GetSectionTagRef(SliceName) {
25	return 'section.' + SliceName + ' ';
26}
27
28var SectionTag, SectionTags; // will be used to hold required slices
29function SectionTagExists(SliceName) {
30	if (SectionTags.hasClass(SliceName)) {
31		SectionTag = SectionTags.filter(GetSectionTagRef(SliceName));
32		if (SectionTag.length !== 0) { // at least one slice exists, great. You could have more than one in theory.
33			return true;
34		}
35	}
36	SectionTag = undefined; // remove all data.
37	return false;
38}
39
40function GetRefItem(SectionTag, Ref) {
41	if (typeof Ref === "string") {
42		if (Ref === '') { // allows us to return the section tag itself.
43			return SectionTag;
44		} else {
45			return SectionTag.find(Ref);
46		}
47	} else {
48		return Ref;
49	}
50}
51
52// A function to easily set JQuery toggles.
53// SectionTag is a $ variable.
54function ApplyToggleVisibilityOnClick(SectionTag, ClickRef, ToggleRef, iDelay, bShowToggleItemInitially) {
55
56	var ClickItem = GetRefItem(SectionTag, ClickRef);
57	var ToggleItem = GetRefItem(SectionTag, ToggleRef);
58
59	if (bShowToggleItemInitially) {
60		ToggleItem.show(0);
61	} else {
62		ToggleItem.hide(0);
63	}
64	// Note we add a function here. Since we are only using calling function arguements inside the function argument,
65	// variable scoping correctly works.
66	 ClickItem.click(function () {
67		ToggleItem.toggle(iDelay);
68	});
69}
70
71function ApplyHideOnClick(SectionTag, ClickRef, ToHideRef) {
72
73	var ClickItem = GetRefItem(SectionTag, ClickRef);
74	var ToHideItem = GetRefItem(SectionTag, ToHideRef);
75
76	 ClickItem.click(function () {
77		ToHideItem.hide(0);
78	});
79}
80
81// function to test if text exists.
82var sAttrText, sAttrText2, sAttrText3, sAttrText4; // Results come back in these variables.
83var DollarTextarea = $("<textarea/>"); // store this once.
84function TextExists(attrText, bSplit) {
85
86	if (attrText === undefined) {return false;}
87	if (attrText === null) {return false;}
88
89	var TextToProcess = attrText.trim();
90	if (TextToProcess === '') {return false;}
91
92	// decode the text, so that &amp;lt; becomes < etc.
93	// This works by turning into HTML and then turning back into text.
94	if (TextToProcess.indexOf('&') !== -1) { // we could use the .includes('&') method, but it is quite new, so some browsers can't cope.
95		TextToProcess = DollarTextarea.html(TextToProcess).text();
96	}
97	if (TextToProcess === '') {return false;}
98
99	sAttrText = ''; // set return values to blank.
100	sAttrText2 = '';
101	sAttrText3 = '';
102	sAttrText4 = '';
103	if (bSplit) {
104		var arrSplitText = TextToProcess.split('*');
105		sAttrText = arrSplitText[0].trim();
106		if (arrSplitText.length > 1) {sAttrText2 = arrSplitText[1].trim();}
107		if (arrSplitText.length > 2) {sAttrText3 = arrSplitText[2].trim();}
108		if (arrSplitText.length > 3) {sAttrText4 = arrSplitText[3].trim();}
109	} else {
110		sAttrText = TextToProcess;
111	}
112
113	return (sAttrText + sAttrText2 + sAttrText3 + sAttrText4 !== '');
114}
115
116// Function to hide a column if it contains no images.
117var SystemSlice;
118function HideDivsIfAllEmpty(ColumnClass) {
119	var ImageWrappers = SystemSlice.find('div.' + ColumnClass);
120	if (ImageWrappers.find('img').length === 0) { // have to use find not children, as img tags can be inside <a> tags.
121		ImageWrappers.hide(0);
122	}
123}
124
125// ################### Slice activation functions go here. #########################
126
127// All slide shows have the same defaults at present.
128var BxDefaultValues = {
129	mode: 'fade',
130	auto: true,
131	pause: 8000,
132	speed: 500,
133	pager: true,
134	controls: true,
135	preloadImages: 'all',
136	touchEnabled: false,
137	adaptiveHeight: true
138};
139
140function ActivateBxSlider(SliceName) {
141	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
142
143        var bannerSlides = SectionTag.find('div.bannerSlides'); // use a "find" here, as structure of slices varies.
144        var gallery_ul = bannerSlides.children('ul.gallery_ul');
145        var ImageList = gallery_ul.find('img');
146        if (ImageList.length === 0) {return;} // No images, so give up.
147
148        // ul.gallery_ul must be displayed before bx-slider can be applied.
149        // So since we hide it while the page was loading, we show it now.
150        bannerSlides.show(0); // show the slice now. It was hidden by CSS.
151
152        if (ImageList.length > 1) { // carry on as normal.
153          gallery_ul.bxSlider(BxDefaultValues);
154        } else { // Just 1 image, so we don't set up the slider, but do some minor adjustments to help the CSS.
155          gallery_ul.css('margin','0px');
156          var S = '<div class="bx-wrapper"><div class="bx-viewport"></div></div>';
157          gallery_ul.wrap(S);
158        }
159
160        // Code to enable user defined text to appear over banner slides.
161        ImageList.each(function() {
162			var ThisImg = $(this);
163			if (TextExists(ThisImg.attr('alt'), true)) { // check if there is any alt text.
164				var DarkenedClass = '';
165				if (bAddDarkenedOverlayForSlideShowCaptions) {DarkenedClass = ' DarkenedOverlay';}
166				var title = '<div class="slideTitle' + DarkenedClass + '">' + sAttrText + '</div>';
167				// even if the subtitle text is empty, we keep the div for styling reasons.
168				// If there is a long caption, reduce font weight from bold to normal.
169				var FontStyle = '';
170				if (sAttrText2.length > 100) {FontStyle = ' style="font-weight:400;" ';}
171				var subtitle = '<div class="slideText' + DarkenedClass + '"' + FontStyle + '>' + sAttrText2 + '</div>';
172
173				var ButtonLink = '';
174				var ButtonText = sAttrText3;
175				if (ButtonText === '') {ButtonText = SlideShowDefaultButtonText;}
176				if (ButtonText !== '' && ButtonText !== 'none'){
177					var ButtonColor = sAttrText4;
178					if (TextExists(ThisImg.parent().attr('href'), false)) { // check for href text. NOTE: sAttrTextX values are reset.
179
180						// add button colour if we have some colour data.
181						// Check for a " character, as that will spoil our HTML.
182						if (ButtonColor !== '' && ButtonColor.indexOf('"') === -1) {
183							ButtonColor = ' style="background-color:' + ButtonColor + ' !important;border-color:' + ButtonColor + ' !important;" ';
184						}
185
186						// build the completed button link.
187						ButtonLink = '<a class="slideButton" href="' + sAttrText + '"' + ButtonColor + '>' + ButtonText + '</a>';
188					}
189				}
190
191				var caption = '<div class="caption">' + title + subtitle + ButtonLink + '</div>';
192				$(caption).insertAfter(this);
193			}
194			ThisImg.removeAttr('title'); // remove the title attribute so that pop-up text does not appear.
195	  });
196	}
197}
198
199// define a function, so we can activate a SlickNav menu in a controlled way.
200function ActivateMenu(SliceName) {
201	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
202
203	  var SectionTagRef = GetSectionTagRef(SliceName);
204	  var RootMenuDeskTop = SectionTag.children('div.nav-menu').children('ul.root_menu');
205
206	  RootMenuDeskTop.slicknav({ // activate SlickNav for this slice.
207		prependTo: SectionTagRef + '> div.SlickNav_Wrapper',
208		allowParentLinks: true, // Top level items can be links
209		label: 'Menu',
210		// Use hex escape characters here.
211		closedSymbol: '&#xe900', // a logical OR "V" symbol
212		openedSymbol: '&#xe901', // a nice up pointing ">" symbol
213		duplicate: bDesktopScreenPossible // only need to duplicate if the desktop menus are needed.
214	  });
215
216		var SlickNavLastItem = SectionTag.find('ul.slicknav_nav > li:last-child');
217		//Add extra links onto the SlickNav menu manually, to replace top-link log-out buttons etc.
218		var ExtraLink_1, ExtraLink_2;
219		if (bUserLoggedIn) {
220			ExtraLink_1 = '<li class="ExtraLink"><a href="/User/Logout.aspx"><i class="journey-icon-login"></i>Logout</a></li>';
221			ExtraLink_2 = '<li class="ExtraLink"><a href="/Admin/Default.aspx"><i class="journey-icon-register"></i>Web Office</a></li>';
222		} else {
223			ExtraLink_1 = '<li class="ExtraLink"><a href="/user/login.aspx"><i class="journey-icon-login"></i>Login</a></li>';
224			ExtraLink_2 = '<li class="ExtraLink"><a href="/User/Registration.aspx"><i class="journey-icon-register"></i>Register</a></li>';
225		}
226		var ExtraLink_3 = '<li class="ExtraLink SearchOpen"><a><i class="journey-icon-search"></i>Search</a></li>';
227		$(ExtraLink_1 + ExtraLink_2 + ExtraLink_3).insertAfter(SlickNavLastItem);
228
229		if (bOnTouchDevice && bDesktopScreenPossible) { // have to do more work on menus.
230
231			// Having made the SlickNav menu - delete what we don't want.
232
233			SectionTag.children("div.SlickNav_Wrapper").children("div.slicknav_menu").children('ul.slicknav_nav').find('li.SlickNavNotNeeded').remove();
234
235			// deactivate the top level <a> tag in the desk-top version so touch-screens work correctly.
236			// The link goes nowhere, but retains all the styling.
237			RootMenuDeskTop.children("li.has_sub_menu").children('a').removeAttr("href");
238		}
239
240		// Add a close menu icon into slickNav.
241		var SlickNavIcon = SectionTag.find('span.slicknav_icon');
242		$('<div class="SlickNavCloseIcon"></div>').insertAfter(SlickNavIcon);
243
244		// apply all the visibility on-clicks to make the menu slice work.
245
246		// Find some commonly used items.
247		var SearchOverlay = SectionTag.find("div.search-overlay");
248		var SlickNavBtn = SectionTag.find("a.slicknav_btn");
249
250		ApplyToggleVisibilityOnClick(SectionTag, "li.ExtraLink.SearchOpen", SearchOverlay, 0, false);
251		ApplyToggleVisibilityOnClick(SectionTag, "div.top-link-wrapper a:last-child", SearchOverlay, 0, false);
252		ApplyHideOnClick(SectionTag, "a.search-close", SearchOverlay);
253		ApplyHideOnClick(undefined, SlickNavBtn, SearchOverlay);
254		// Toggles for menu-bars and menu-close icons
255		ApplyToggleVisibilityOnClick(undefined, SlickNavBtn, SlickNavIcon, 0, true); // no delay on the toggle.
256		ApplyToggleVisibilityOnClick(SectionTag, SlickNavBtn, "div.SlickNavCloseIcon", 0, false); // no delay on the toggle.
257
258		// Need autocomplete="off" to be added to the search box <input> tag.
259		// This stops horrible browser autocomplete text from appearing.
260		SectionTag.find('div.search_div input').attr("autocomplete","off");
261
262	  }
263}
264
265function ActivateFooter(SliceName) {
266	if (bSplitFooterAddressAtSecondComma) {
267		if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
268			// .footer-column-2 can be a div or a span, so just look for the class.
269			var FooterAddress = SectionTag.find('.footer-column-2');
270			if (FooterAddress.children('*').length === 0) { // only proceed if there are no html tags within this element.
271				if (TextExists(FooterAddress.text(), false)) {
272					var AddressText = sAttrText;
273					if (AddressText.indexOf(',') !== -1) {
274						AddressText = AddressText.replace(/\,/, "¬"); // change first comma
275						if (AddressText.indexOf(',') !== -1) {
276							AddressText = AddressText.replace(/\,/, ",<br>"); // now break at the 2nd comma
277							AddressText = AddressText.replace(/¬/, ","); // put back first comma
278							FooterAddress.html(AddressText); // have to use html() here, as there is a <br> tag.
279						}
280					}
281				}
282			}
283		}
284	}
285}
286
287function ActivateArticleList4(SliceName) {
288	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
289	
290		// Get the summaries
291		var Summarys = SectionTag.find('div.articleListSummary span');
292
293	  // Create the links at the bottom of the article cards. 
294	  var j=0;
295	  SectionTag.find('div.articleListTitle a').each(function () {
296		var ThisAtag = $(this);
297		var titleLink = ThisAtag.attr("href");
298		var articleListLink = ThisAtag.parent().parent().children('.articleListLink');
299		// See if we have new link text.
300		if (TextExists(Summarys.eq(j).text(), true)) {
301			if (sAttrText2 !== '') {
302				articleListLink.text(sAttrText2);
303			}
304		}
305		articleListLink.wrapInner('<a href="' + titleLink + '">');
306		j++;
307	  });
308	  
309	  Summarys.each(function () {
310		var ThisSummary = $(this);
311		var S = ThisSummary.text();
312		if (TextExists(S, true)) {
313			sAttrText = sAttrText.replace(/\\/g,'<br>');
314			if (S !== sAttrText) {
315				ThisSummary.html(sAttrText);
316			}
317		}
318 	  });
319  }
320}
321
322function ActivateBlockImages(SliceName) {
323	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
324		SectionTag.find("div.image_blocks img" ).each(function() {
325			if (TextExists($(this).attr('alt'), true)) { // check if there is any alt text.
326				var cardGridCaption = '<div class="image_block_title_wrapper"><div class="image_block_title">' + sAttrText + '</div><div class="image_block_text">' + sAttrText2 + '</div></div>';
327				$(cardGridCaption).insertAfter( this );
328			}
329			$(this).removeAttr('title'); // remove the title attribute so that pop-up text does not appear.
330		});
331	}
332}
333
334function ActivateBannerImage(SliceName) {
335	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
336		
337		var bImageApplied = false;
338		var GnValues = SectionTag.find("span.groupnotes_value");
339		if (GnValues.length > 0) {
340		
341			if (TextExists(GnValues.eq(0).find("a").attr('href'), false)) { // assume first note is banner image.
342			
343				SectionTag.css('background-image','url(' + sAttrText + ')');
344				bImageApplied = true;
345				
346				// background image applied, so add group name, if available.
347				if (TextExists($('head meta[name="Group Name"]').attr('content'), false)) {
348					SectionTag.find('h1').text(sAttrText);
349				}
350				
351				// Apply css background-position if available.
352				if (GnValues.length > 1) {
353					var GnNames = SectionTag.find("span.groupnotes_name");
354					TextExists(GnNames.eq(1).text(), false);
355					if (sAttrText.indexOf('Banner Image Position') !== -1) { // check if the second note is this.
356						if (TextExists(GnValues.eq(1).text(), false)) {
357							SectionTag.css('background-position', sAttrText);
358						}
359					}
360				}
361			}
362		}
363		if (!bImageApplied) { // Didn't find background image, so hide the whole slice.
364			SectionTag.hide();
365			if (SectionTagExists('slice_content_page')) { // add a grey border to the content slice.
366				SectionTag.addClass('AddTopBorder');
367			}
368		} 
369	}
370}
371 
372function BuildArticleSlider(SliderSliceName, SliderBlogName) {
373	if (SectionTagExists(SliderSliceName)) { // check if slice exists, and load into SectionTag if it does
374		var Slider = SectionTag;
375		if (SectionTagExists(SliderBlogName)) { // check if slice exists, and load into SectionTag if it does
376			var Blog = SectionTag;
377			var BlogArticles = Blog.find('div.blogcomponent_articlediv div.ArticleBody');
378          	if (BlogArticles.length === 0) {SectionTag.hide();return;}
379			var ulGallery = Slider.find('ul.gallery_ul');
380			var Li = ulGallery.children('li');
381			// First build the <li> in the gallery
382			var i;
383			for (i = 2; i <= BlogArticles.length; i++) {
384				Li.clone().appendTo(ulGallery);
385			}
386			// Now add all the blog articles as image captions.
387			var Img = ulGallery.find('img');
388			var S;
389			i = 0;
390			BlogArticles.each(function() {
391              // Add in section.slice_Testimony to pick up some styles.
392				S = '<div class="caption"><section class="slice_Testimony">' + $(this).html() + '</section></div>';
393				$(S).insertAfter(Img.eq(i));
394				i++;
395			});
396			
397			// Turn into a slider
398			var BxOptions = {
399				mode: 'fade',
400				auto: false,
401				pause: 5000,
402				speed: 500,
403				pager: true,
404				controls: true,
405				preloadImages: 'visible', // all images are the same.
406				touchEnabled: false,
407				adaptiveHeight: false // all images are the same.
408			};
409			Slider.find('div.bannerSlides').show(0);
410			ulGallery.bxSlider(BxOptions);
411		}
412	}
413}
414 
415function ActivateLandingArticles(SliceName) {
416	/* this code does an intelligent layout change for a article list, depending on the number of articles */
417	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
418		var rMarginWidth = 1.28866 * 2.0, rCleverWidth;
419		var Articles = SectionTag.find('div.article_cards > div');
420		var iArticles = Articles.length;
421		switch(iArticles) {
422			case 1:
423				rCleverWidth = 100.0 - rMarginWidth; break;
424			case 2:
425				rCleverWidth = 50.0 - rMarginWidth; break;
426			case 3: case 5: case 6: case 9:
427				rCleverWidth = 33.33333 - rMarginWidth; break;
428			case 4: case 7: case 8: case 10: case 11: case 12:
429				rCleverWidth = 25.0 - rMarginWidth; break;
430			//case 5:
431				//rCleverWidth = 20.0 - rMarginWidth; break;
432			default:
433				rCleverWidth = 25.0 - rMarginWidth; break;
434		}
435		Articles.css('width', rCleverWidth + '%');
436	}
437}
438 
439 function ActivateLandingList(SliceName) {
440	if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
441
442	  // Create the links at the bottom of the article cards.
443	  SectionTag.find('div.articleListTitle a').each(function () {
444		var ThisAtag = $(this);
445		var titleLink = ThisAtag.attr("href");
446		var articleListLink = ThisAtag.parent().parent().children('.articleListLink');
447		articleListLink.wrapInner('<a href="' + titleLink + '">');
448	  });
449  }
450}
451 
452 function ActivateRedBanner(SliceName) {
453   if (SectionTagExists(SliceName)) { // check if slice exists, and load into SectionTag if it does
454	if(SectionTag.find('div.ArticleBody').length > 0){SectionTag.removeClass('HideElement');}
455   }
456 }
457
458// ########################## Check various conditions #############################
459
460var bOnTouchDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
461var iDeskTopWidth = 992;
462var iMobileScreenAllowence = 64; // Because of other stuff on a screen, you have to assume the browser window could get bigger on a rotation.
463var bDesktopScreenPossible = ((screen.width + iMobileScreenAllowence) >= iDeskTopWidth || (screen.height + iMobileScreenAllowence) >= iDeskTopWidth);
464
465var BodyTag = $('body');
466var bOnSystemPopupPage = BodyTag.hasClass('system_popup') || (window.location.href.toLowerCase().indexOf('popup=yes') !== -1);
467var bUserLoggedIn = BodyTag.hasClass('logged_in_user');
468
469SectionTags = BodyTag.find('section'); // Store all the section tags to speed up later code.
470var bOnContentPage = SectionTags.hasClass('slice_content_page');
471var bOnSystemPage = SectionTags.hasClass('slice_system_page');
472var bOnHomePage = SectionTags.hasClass('slice_SlidesFullWidth');
473var bOnLandingPage = SectionTags.hasClass('slice_LandingArticles');
474
475ActivateBannerImage('slice_BannerImage');
476
477// Activate the slide shows first as they are usually near the top of the visible screen.
478if (bOnHomePage) {
479
480	// ##############################################################
481	// # js for Slide Shows slices. We use BX-slider V4.2.5
482	// ##############################################################
483
484	// The slide-shows are hidden via CSS when the page first loads, to give a smoother page-load experience.
485	// All slide-show CI modules must have a class "bannerSlides" defined within them.
486
487	// Activate all the slide-shows. Do in sensible order, so any visible ones are done first.
488	ActivateBxSlider('slice_SlidesFullWidth');
489  	ActivateRedBanner('RedBanner');
490}
491
492// #######################################
493// # Menu data changes
494// #######################################
495
496// We make the required adjustments to the one set of menu HTML on the page, before cloning it and activating all the copies.
497
498var ulModuleRootMenu = BodyTag.find('ul.root_menu');
499var bMenuPresent = (ulModuleRootMenu.length !== 0);
500if (bMenuPresent) {
501
502   /* remove sub menus from Home */
503   // This assumes that the home menu is the first item with a sub menu.
504  var HomeMenuLi = ulModuleRootMenu.children('li:first-child');
505  HomeMenuLi.children('ul').remove();
506  HomeMenuLi.removeClass('has_sub_menu'); // remove class
507  
508  // Set up the search icon in the search box.
509  var DeskTopSearchBox = BodyTag.find('header div.top-link-wrapper div.search-form');
510  $('<i class="journey-icon-search"></i>
510').appendTo(DeskTopSearchBox);
511  var HiddenSearchBox = DeskTopSearchBox.find('input.button');
512  DeskTopSearchBox.find('i').click(function(){HiddenSearchBox.click();}); // set up the click.
513  
514  if (bUserLoggedIn) {
515	//ulModuleRootMenu.children('li:last-child').children('ul').remove(); // delete submenus of Myarea.
516	BodyTag.find('header div.top-link-wrapper a.Login').attr('href','/user/logout.aspx').text('LOGOUT');
517	BodyTag.find('header div.top-link-wrapper a.Bookings').attr('href','/admin').text('WEB OFFICE');
518  }
519
520  // remove copies of 1st item elements in dropdown sub-menu.
521  ulModuleRootMenu.find('li.menu_item_level_2:first-child').each(function() {
522
523	var ThisLi = $(this);
524	if(ThisLi.children("a[href^='/MyArea/']").length === 0) { // only if not a link into /MyArea/...
525
526	  if(ThisLi.siblings().length === 0) { // no other <li> so it is the only entry
527		var ul = ThisLi.parent();
528	    ul.parent().removeClass('has_sub_menu'); // remove class from the <li> at the level above
529		ul.remove(); // delete whole parent <ul>
530
531	  } else {
532		if (bOnTouchDevice && bDesktopScreenPossible) {
533			// On a touch device, the copies of the level one links at the 2nd level have to be kept for the desktop menus.
534			// But in the SlickNav menus, these 2nd level links are not needed.
535			// So we mark the items so we can delete them later, after data is copied into the SlickNav menu.
536			ThisLi.addClass('SlickNavNotNeeded'); // Mark the 2nd level <li> tag.
537		} else {
538			// Not on a touch screen, so Desktop and SlickNav menus will be the structurally the same.
539			ThisLi.remove(); // so just remove this <li> tag
540		}
541	  }
542	}
543  });
544
545  // Make sure the online bible goes to a fresh tab/page.
546  ulModuleRootMenu.find('a[href$="/Online_Bible.aspx"]').attr("target","_blank");
547
548	// #######################################
549	// # SlickNav menus V1.0.10
550	// #######################################
551
552	ActivateMenu('slice_Header_L');
553
554	// ######## Footer Slice code ####################
555
556	// If there is a header, then there is probably a footer.
557	// This is the footer top. There is no need to clone this HTML.
558
559	ActivateFooter("slice_FooterTop_L");
560
561} // end of if bNeedMenus
562
563// Here do things ONLY needed on a home page.
564if (bOnHomePage) {
565
566	  // Article list - 4 in a row on desktop
567	ActivateArticleList4('slice_WelcomeArticles');
568
569	// image blocks
570	ActivateBlockImages('slice_image_blocks_4');
571  
572	// Article slider
573	BuildArticleSlider('slice_WhatPeopleSay','slice_HiddenWhatPeopleSayBlog');
574		
575} else if (bOnContentPage) {
576	
577	// code to try and make content images work on mobile phones. Set max-width css property is if has not already been set.
578	// If width and height attributes are both set, then the image is compressed horizontally, but that is still better than it overflowing.
579	var ContentImages = BodyTag.find('section.slice_content_page div.ArticleBody img');
580	ContentImages.each(function() {
581		var Img = $(this);
582		if (Img.css('max-width') === 'none') {
583			Img.css('max-width','100%');
584		}
585	});
586
587} else if (bOnLandingPage) {  
588  
589  	ActivateLandingList('slice_LandingArticles');
590	ActivateLandingArticles('slice_LandingArticles');  
591  
592} else if (bOnSystemPage || bOnSystemPopupPage) {
593
594	// work out what kind of page we are on.
595	var PageType = window.location.pathname.toLowerCase();
596	if (PageType.endsWith(".aspx")) {
597		PageType = PageType.substring(0, PageType.indexOf(".aspx"));
598		PageType = PageType.replace(/\//g, "_"); // replace all / to _ Have to use \/ to get a / in the reg-ex. The g denotes a global exchange.
599		PageType = PageType + "_aspx";
600	} else if (PageType.indexOf(".html") === (PageType.length - 5)) {
601		// Assume we are on a local machine.
602		PageType = '_user_registration_aspx';
603	}
604	//alert(PageType);
605
606	/* Possible page types are now:
607	'_calendar_month_aspx'
608	'_media_allmedia_aspx'
609	'_user_registration_aspx'
610	'_user_copyright_aspx'
611	'_user_termsandconditions_aspx'
612	'_user_privacypolicy_aspx'
613	'_user_help_aspx'
614	'_publisher_search_aspx' - this is search results.
615	'_paymentgroup_registration_aspx'
616	'_myarea_walletitem_aspx'
617	*/
618
619	if (SectionTagExists("slice_system_page")) { // check if slice exists, and load into SectionTag if it does
620		SystemSlice = SectionTag;
621		SystemSlice.addClass(PageType); // add class onto <section> tag, so CSS can locate it.
622	} else {
623		BodyTag.addClass(PageType); // add class onto <body> tag, so CSS can locate it. This will apply to various pop-up windows eg shop T&Cs.
624		BodyTag.addClass('system_popup'); // add this in case it is not on.
625    }
626
627	if (PageType === '_media_allmedia_aspx' || PageType === '_publisher_search_aspx') {
628
629		// Add a toggle for the media controls.
630		var MediaControls = SystemSlice.find('div#media_controls'); // these media controls are on the search page too.
631		if (MediaControls.length !== 0) {
632			$('<a class="system_toggle_advanced">Advanced Options</a>').insertBefore(MediaControls);
633			ApplyToggleVisibilityOnClick(SystemSlice, "a.system_toggle_advanced", MediaControls, 0, false);
634		}
635
636		HideDivsIfAllEmpty('media_summary_image'); // Hide some empty columns, if needed.
637
638		if (PageType === '_publisher_search_aspx') { // Extra things to do on the search page.
639
640			HideDivsIfAllEmpty('search_article_image'); // Hide some empty columns, if needed.
641			HideDivsIfAllEmpty('search_event_image'); // Hide some empty columns, if needed.
642
643			// If we have been sent to the search page explicitly then prepare the page for searching.
644			 var SearchBox = SystemSlice.find('input[id$="_txtSearchStringTemplate"]');
645			 if (SearchBox.length === 1) {
646				 if (SearchBox.val() === 'Activate_Search') {
647					 SystemSlice.find('h2').hide(); // hide the search result titles
648					 SearchBox.val(''); // Clear the search text box
649					 SearchBox.attr('placeholder','Type your search text here');
650					 SearchBox.attr("autocomplete","off");
651					 MediaControls.show(); // make the search controls show.
652				 }
653			 }
654			 
655			// If no data is found then, print a message, rather than have a blank page.
656			 if (SystemSlice.find('div.system_section').length === 0) {
657				 var HTML = '<span>No data found.<br><br>Please use the advanced options to refine your search.</span>';
658				 $(HTML).appendTo(SystemSlice.find('div.system_body'));
659				 MediaControls.show(); // make the search controls show.
660			 }
661		}
662	}
663
664	// Fix calendar mobile page. Add a class to days we want to hide on the mobile/list view.
665	if (PageType === '_calendar_month_aspx') {
666		var DivToday = SystemSlice.find('div.calendar_day_wrapper_today');
667		if (DivToday.length !== 0) {  // we are on a calendar page with today's date.
668			var NoEvents = SystemSlice.find('div#calendar_no_events');
669			if (NoEvents.length === 0) { // only bother if there are some events.
670				DivToday.prevAll().addClass('CalendarHideOnListView'); // so we can hide days earlier in the current week.
671				var DivThisWeek = DivToday.parent();
672				DivThisWeek.prevAll().addClass('CalendarHideOnListView'); // so we can hide earlier weeks.
673				// If no events are visible, then tell the user.
674				var AllDaysInVisibleWeeks = SystemSlice.find('div.calendar_week:not(".CalendarHideOnListView") div.calendar_day_wrapper');
675				var iDaysVisible = AllDaysInVisibleWeeks.not('.calendar_day_wrapper_empty').not('.CalendarHideOnListView').length;
676				if (iDaysVisible === 0) {
677					$('<div id="calendar_no_events">There are no events in the selected month.</div>').insertAfter(SystemSlice.find('div.calendar'));
678				}
679			}
680		}
681	}
682
683} // end of bOnHomePage or bOnSystemPage if-block
684
685// Corrections for various hardware/browsers
686var P = navigator.platform;
687var bSmallAppleDevice = (P === 'iPhone' || P === 'iPad' || P === 'iPod');
688//var bAppleDevice = (P === 'MacIntel' || bSmallAppleDevice);
689
690var UA = navigator.userAgent;
691// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent for details.
692var bOnSafari = (UA.indexOf('Safari/') !== -1 && UA.indexOf('Chrome/') === -1 && UA.indexOf('Chromium/') === -1);
693
694//alert(P + ' # ' + UA); // DEBUGGING line.
695
696if (bOnSafari) {
697	// Fix the twitter feed on Safari. Need to replace height:100% with a fixed height, to prevent a near infinite scroll.
698	// We can't just add a class on the <iframe>, as it is created dynamically by Twitter js.
699	// So instead we add a class on the wrapper div, just before where the iframe will appear.
700	SectionTags.find('div.WhatsOnTwitter').addClass('OnAppleDevice');
701}
702if (bSmallAppleDevice) {
703	// Parallex images are often a mess on small apple devices, so add a tag onto the <body> tag so we can take evasive action.
704	BodyTag.addClass('OnSmallAppleDevice');
705}
706
707// Warnings.
708var iNumSwitchFastParallexOnSlices = SectionTags.filter('.SwitchFastParallexOn').length;
709if (iNumSwitchFastParallexOnSlices > 1) {
710	alert('WARNING: Theme has ' + iNumSwitchFastParallexOnSlices + ' SwitchFastParallexOn slices.');
711}
712
713// Code to make sure anchor links do not dissappear behind a fixed header (used on Quainton School).
714if (bOnContentPage) {
715	var iHeaderHeight = 0;
716	if (SectionTagExists('slice_Header_L')) {
717		var CssPosition = SectionTag.css('position');
718		if (CssPosition === 'fixed'){ // only do if we have a fixed header.
719			iHeaderHeight = SectionTag.outerHeight(true);
720		}
721	}
722	if (iHeaderHeight > 0 && SectionTagExists('slice_content_page')) {
723		var HashLinks = SectionTag.find('a:not([href="#"])[href^="#"]');
724		HashLinks.click(function(){
725			window.setTimeout(function(){window.scrollBy(0, -iHeaderHeight);}, 500); // wait 500ms, then scroll down, so link is not under the header.
726		});
727	}
728}
729                               
730// Sort out login/logout/register/web-office links
731var SB = BodyTag.find('div.HiddenStatusBar');
732if (SB.length === 1) {
733	if (bUserLoggedIn) {
734		var bWebOfficeActive = (SB.find('a.weboffice_link').length === 1);
735		if (!bWebOfficeActive) { // Need to hide WO links.
736			BodyTag.find('header a[href="/admin"]').hide();
737			BodyTag.find('header a[href="/Admin/Default.aspx"]').hide();
738			BodyTag.find('section.slice_FixedSideLinks a[href="/admin"]').hide();
739		}
740	} else {
741		var SBRL = SB.find('a.register_link');
742		if (SBRL.length === 0) { // Need to hide the register links. Need TWO versions for case changes.
743			BodyTag.find('header a[href="/User/Registration.aspx"]').hide();
744			BodyTag.find('header a[href="/user/registration.aspx"]').hide();
745			BodyTag.find('section.slice_FixedSideLinks a[href="/User/Registration.aspx"]').hide();
746			BodyTag.find('section.slice_FixedSideLinks a[href="/user/registration.aspx"]').hide();
747		} else {
748			var RegLink = SBRL.attr('href');
749			if (RegLink !== "/User/Registration.aspx") {
750				BodyTag.find('header a[href="/User/Registration.aspx"]').attr('href',RegLink);
751				BodyTag.find('header a[href="/user/registration.aspx"]').attr('href',RegLink);
752				BodyTag.find('section.slice_FixedSideLinks a[href="/User/Registration.aspx"]').attr('href',RegLink);
753				BodyTag.find('section.slice_FixedSideLinks a[href="/user/registration.aspx"]').attr('href',RegLink);
754			}
755		}
756	}
757}
758
759});

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.