;(function(){ if (typeof App === 'undefined') App = {}; // args: jquery element to align App.VertAlignStoryColumn = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.VertAlignStoryColumn.prototype.init = function(){ // requires elements var a = [ Display.content, Display.picker ]; if (!Display.required(a)){ Util.output('VertAlignStoryColumn has missing elements.'); return; } // call straight away, & on resize var valign = function(){ j.css('padding-top', 40); var c = Display.content.height(); var p = parseInt(Display.content.css('padding-top')); // header space var topTail = Display.picker.height()+p; var win = $(window).height(); var h = j.height(); var a; if (win-topTail>c) a = (win-topTail-h)/2; else if (cc) a = (win-topTail-h)/2; else if (c= win) v = 'auto'; j.css('bottom', v); }; align(); Resize.addTo(align); }; }; })(); ;(function(){ if (typeof App === 'undefined') App = {}; // arg: j for jquery element containing links to carousel items App.StoryCarousel = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.StoryCarousel.prototype.init = function(){ // requires elements var container = $('#main .container, #MainContent_main .container'); var a = [ Display.section, container ]; if (!Display.required(a)){ Util.output('StoryCarousel has missing elements.'); return; } // common elements var list = j.find('li'); var active = 0; var wait = 15000; var paused = false; var timer, widget, bar, button, perc, tempPaused, exPaused, loading; if (list.length > 1){ // look for 'active' link to use as first list.each(function(index){ if (list.eq(index).hasClass('active')) active = index; }); Util.output('First carousel story: '+active); // add functionality var buttonDisplayPaused = function(){ if (!button.hasClass('paused')) button.addClass('paused'); }; var buttonDisplayPlay = function(){ button.removeClass('paused'); }; // this is for when a custom event is picked up to pause. // this will be controlled separately as it is possible to have // paused properly (and we don't won't the external unpause to // start it off again!) var pauseForCotnent = function(){ exPaused = true; if (!paused){ clearTimeout(timer); buttonDisplayPaused(); } }; var UnpauseFromContent = function(){ exPaused = false; if (!paused && !tempPaused) restartTimer(); }; // this starts a temporary pause, while certain // elements have mouseover var hoverPause = function(){ tempPaused = true; buttonDisplayPaused(); clearTimeout(timer); }; var hoverUnpause = function(){ tempPaused = false; if (!paused && !exPaused) restartTimer(); } // args: optional boo to force pause (true) or unpause (false) var pauseToggle = function(boo){ clearTimeout(timer); if (typeof boo === 'undefined') boo = paused || exPaused ? false : true; if (!boo){ exPaused = false; paused = false; restartTimer(); } else { paused = true; buttonDisplayPaused(); } } // args: el for jquery element that causes a temporary pause on hover var addHoverPause = function(el){ el.mouseover(hoverPause); el.mouseout(hoverUnpause); }; // args: el for jquery element that can be clicked to pause var addPause = function(el){ el.click(function(e){ pauseToggle(); e.preventDefault(); }); } var addWidget = function(){ var c = list.eq(active); widget = $('

Progress: 0%

Play/pause story carousel
'); c.append(widget); bar = widget.find('p'); button = widget.find('a'); if (paused) buttonDisplayPaused(); addHoverPause(bar); addPause(button); }; // args: story is the newly loaded data to replace the current story, // theme for theme of link that triggered change var swapStories = function(story, theme){ // stop any of the current stories related content (if listening!) CustomEvents.doEvent('stopContent'); // kill custom events (if they are listening!) CustomEvents.doEvent('killCustomEvents'); // fade out current story container.fadeTo(500, 0, function(){ // swap content container.html(story); // apply new theme colours Util.removeTheme(Display.section); Display.section.addClass(theme); // apply any newly loaded js Main.scan(container); // fade in container.fadeTo(500, 1, function(){ // add timer widget loading = false; addWidget(); startTimer(); }); }); }; // args: str for string path to content, theme for theme of link that // triggered change // (note: content is in 2 places - page for no-js & in stories folder for ajax. // we'll load the ajax file with the same name as the page. var loadStory = function(str, theme){ loading = true; str = '/stories'+str; //Util.output('Load: '+str+', theme: '+theme); // remove current widget widget.remove(); // make the ajax call $.get(str, function(data){ swapStories(data, theme); }).fail(function(xhr, t, e){ Util.output('loadStory error: '+e); }); }; var timerTick = function(){ clearTimeout(timer); perc += 1; bar.css('width', perc+'%'); bar.attr('title', 'Progress: '+perc+'%'); bar.text('Progress: '+perc+'%'); if (perc >= 100){ // next story... active = active+1 >= list.length ? 0 : active+1; loadStory(list.eq(active).find('a:first-child').attr('href'), Util.findTheme(list.eq(active))); return; } restartTimer(); }; var restartTimer = function(){ if (!loading){ clearTimeout(timer); buttonDisplayPlay(); timer = setTimeout(timerTick, wait/100); } }; var startTimer = function(){ // cancel (any set) timer & unpause clearTimeout(timer); paused = false; tempPaused = false; exPaused = false; perc = 0; bar.width(0); bar.attr('title', 'Progress: 0%'); bar.text('Progress: 0%'); restartTimer(); }; var sendToStory = function(data){ var i, n, b; var str = null; // check data to see if the path was passed over correctly for (key in data){ if (key === 'path'){ str = data[key]; break; } } // if no path was found, abort if (str == null){ Util.output('sendToStory aborted. No path found!'); return; } // find match for theme (and update active)... n = list.length; b = false; for (i = 0; i < n; i++){ if (list.eq(i).find('a:first-child').attr('href') === str){ b = true; active = i; break; } } // if no match found abort if (!b){ Util.output('sendToStory aborted. No matching story found!'); return; } // now load... loadStory(str, Util.findTheme(list.eq(active))); } // add and start timer addWidget(); startTimer(); // some content may pause the timer. this will be marked // by 'exPaused' CustomEvents.addTo('PauseForContent', pauseForCotnent); CustomEvents.addTo('UnpauseFromContent', UnpauseFromContent); // listen out for outside events that change the carousel... CustomEvents.addTo('SendStoryCarouselTo', sendToStory); } }; }; })(); ;(function(){ if (typeof App === 'undefined') App = {}; // arg: j for jquery hyperlink element App.StoryLink = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.StoryLink.prototype.init = function(){ // requires elements (NA ... StoryLink will just fire a custom event, // it is up to other JavaScript elements to make use of it) var story = j.attr('href'); j.click(function(e){ CustomEvents.doEvent('SendStoryCarouselTo', { path: story }); track.pushEvent("Navigation", "Carousel | " + j.text(), "URL:" + document.URL); e.preventDefault(); }); }; }; })(); ;(function() { if (typeof App === 'undefined') App = {}; // args: jquery element add tweets to... App.TwitterFeed = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.TwitterFeed.prototype.init = function(){ // requires jquery.twitter... jQuery(function($){ $(".twitter_feed").tweet({ username: "pearsonplc", //join_text: "auto", avatar_size: null, count: 1, // auto_join_text_default: "we said,", // auto_join_text_ed: "we", // auto_join_text_ing: "we were", // auto_join_text_reply: "we replied to", // auto_join_text_url: "we were checking out", // loading_text: " ", twitter_search_url: "twitter.com/search" }); }); }; }; }()); ;(function(){ if (typeof App === 'undefined') App = {}; // arg: j for jquery element (container with articles) App.TabSet = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.TabSet.prototype.init = function(){ // don's apply tabs in ie7 (they have issues) if ($('html').hasClass('lt-ie8')) return; // requires elements (at least 2 articles) var articles = j.find('article'); if (articles.length < 2){ Util.output('TabSet: less than 2 articles.'); return; } // common elements // add a modifier class to the articles articles.addClass('tabbed'); articles.each(function(index){ $(this).attr('id', 'tab'+index).addClass('inactive'); }); articles.first().removeClass('inactive').addClass('active'); // clone the title and add as navigation var titles = j.find('article h2'); var nav = $(''); j.prepend(nav); var li; var w = ((1/titles.length)*100)+'%'; titles.each(function(index){ li = $('
  • '); li.find('a').append($(this).html()); li.css('width', w); nav.append(li); }); // clicking nav item will switch active tab var navLinks = nav.find('a'); navLinks.first().addClass('active'); navLinks.click(function(e){ navLinks.removeClass('active'); $(this).addClass('active'); var id = $(this).attr('href'); id = id.substr(1); //articles.removeClass('active').removeClass('inactive'); articles.addClass('inactive').css('display', 'none'); articles.each(function(index){ if (id === $(this).attr('id')){ Util.output('inactive/active'); $(this).removeClass('inactive').addClass('active').css('display', 'block'); } }); e.preventDefault(); }); }; }; })(); ;(function(){ if (typeof App === 'undefined') App = {}; // args: j for jquery element (container) with sections tags to arrange App.Carousel = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.Carousel.prototype.init = function(){ // requires elements (at least 2 sections) var sections = j.find('section'); var n = sections.length; if (n < 2){ Util.output('Carousel: less than 2 sections.'); return; } // common elements var num = 0; var tran = 500; var i, dot, str, dotList; // wrap sections in a carousel_strip var strip = $(''); strip.width(j.width()*n); j.prepend(strip); sections.each(function(index){ strip.append($(this)); }); // detect size change... var resizeCarousel = function(){ var w = j.width(); strip.width(w*n); strip.stop().css('margin-left', -(num*w)); }; Resize.addTo(resizeCarousel); // add prev & next arrows... var prev = $('Previous'); j.append(prev); var next = $('Next'); j.append(next); var anim = function(){ strip.stop().animate({ marginLeft: -(num*j.width()) }, tran); }; // args: c for new 'current' case number var applyNum = function(c){ Util.output(c); num = c; prev.removeClass('disabled'); next.removeClass('disabled'); if (num === 0) prev.addClass('disabled'); if (num === n-1) next.addClass('disabled'); dotList.removeClass('active'); dotList.eq(num).addClass('active'); anim(); }; prev.click(function(e){ if (!prev.hasClass('disabled')){ applyNum(num-1); e.preventDefault(); } }); next.click(function(e){ if (!next.hasClass('disabled')){ applyNum(num+1); e.preventDefault(); } }); // add selector dots var dots = $(''); for (i = 0; i < n; i++){ str = sections.eq(i).find('.tab_info h3').first().text(); dot = $('
  • '+str+'
  • '); dots.append(dot); } dotList = dots.find('li'); j.append(dots); dots.css('margin-left', -dots.width()/2); dots.on('click', 'a', function(e){ var h = $(this).attr('href') //if ($('html').hasClass('lt-ie8')) h = h.substr(h.indexOf('#')+1); Util.output('hash: '+h); applyNum(h*1-1); e.preventDefault(); }); // add a custom event listener var goTo = function(data){ if (typeof data !== 'undefined' && typeof data.num !== 'undefined'){ data.num = data.num < n ? data.num : n-1; applyNum(data.num); } else { Util.output('Carousel: goTo. Number not supplied!'); } } CustomEvents.addTo('CaseStudyNum', goTo); // finally, if there's a hash, go there... var hash = window.location.hash; if (hash.length > 0) { hash = hash.substring(1); CustomEvents.doEvent('CaseStudyNum', {num: parseInt(hash)}); } }; }; })(); ;(function(){ if (typeof App === 'undefined') App = {}; // arg: j for jquery element to divide into columns App.MultiColumn = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.MultiColumn.prototype.init = function(){ // this will divide the contents into 2 columns // class 'new_col' must be present (otherwise leave 'as is') // ALSO: only do this if multi-column layout is NOT supported via CSS // (check with modernizr: no-csscolumns) if ($('.no-csscolumns').length < 1) return; var newCol = j.find('.new_col'); if (newCol.length < 1){ Util.output("MultiColumn: leave 'as is', new_col NOT found."); return; } // common elements Util.output('MultiColumn ready.'); var str = '
    '; var col1 = $(str); var col2 = $(str); var c = col1; var p; var contents = j.contents(); Util.output('contents: '+contents.length); contents.each(function(){ p = $(this); if (p.hasClass('new_col')) c = col2; c.append(p); }); j.append(col1); j.append(col2); }; }; })(); // Please note: As this isea was added after the tabs were removed, // it does not consider needing to change tabs to show the case study. ;(function(){ if (typeof App === 'undefined') App = {}; // args: j for jquery link that triggers goto. App.CaseStudyGoTo = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.CaseStudyGoTo.prototype.init = function(){ // requires elements // none (we'll use some custom events, if the right // elements are listening all well and good). var hash = j.attr('href'); if (!/^#/.test(hash)){ Util.output('CaseStudyGoTo does not href hash!'); return } // The carousel is expecting a number... hash = parseInt(hash.substr(1))-1; // reference the target (we'll jump there if it exists) targ = $(j.attr('href')); // call a custom event... j.click(function(e){ CustomEvents.doEvent('StopVideo'); CustomEvents.doEvent('CaseStudyNum', { num: hash }); //if (targ) if (targ.length > 0) Display.scrollPage.animate({ scrollTop: targ.offset().top }, 500); e.preventDefault(); }); }; } })(); ;(function(){ if (typeof App === 'undefined') App = {}; // args: j for jquery link to a youtube video App.CaseStudyVideo = function(j){ this.element = typeof j !== 'undefined' ? j : null; this.player = null; App.CaseStudyVideo.prototype.init = function(){ // required elements var tabBlock = $('#tab_block'); if (tabBlock.length < 1){ Util.output("CaseStudyVideo: is missing #tab_block (as container)"); return; } /// common properties var done = false; var stopped = false; var video = null; /// functionality var stopVideo = function(){ Util.output('stopVideo'); stopped = true; if (App.CaseStudyVideo.player !== null) App.CaseStudyVideo.player.stopVideo(); if (Display.video !== null) Display.video.addClass('hide_video'); }; // called if Display.video is NOT set var addVideoHolder = function(){ Display.video = $('
    Close video
    '); tabBlock.prepend(Display.video); Main.scan(tabBlock); // listen for custom events CustomEvents.addTo('StopVideo', stopVideo); }; var onPlayerStateChange = function(event) { //Util.output(event.data); switch (event.data){ case YT.PlayerState.PLAYING : if (!done) done = true; break; case YT.PlayerState.ENDED : Util.output('YT.PlayerState.ENDED'); App.CaseStudyVideo.player.seekTo(2); App.CaseStudyVideo.player.pauseVideo(); break; default : // do nothing ;-) } }; var onPlayerReady = function(event) { Util.output('onPlayerReady'); if (!stopped) event.target.playVideo(); }; var onPlayerError = function(event) { var tryAgain = function(){ if (!done && !stopped){ App.CaseStudyVideo.player.loadVideoById(id, 0, 'hd1080'); } }; Util.output('YT Player Error: '+event.data); setTimeout(tryAgain, 500); }; App.CaseStudyVideo.onYouTubeIframeAPIReady = function() { Util.output('onYouTubeIframeAPIReady'); Util.output('actual id: ' + App.CaseStudyVideo.id); App.CaseStudyVideo.player = new YT.Player('player', { height: '100%', width: '100%', videoId: App.CaseStudyVideo.id, suggestedQuality: 'hd1080', events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange, 'onError': onPlayerError }, playerVars: { wmode: "transparent" } }); }; // add to global onYouTubeIframeAPIReady = function(){ App.CaseStudyVideo.onYouTubeIframeAPIReady(); }; var loadVideo = function(){ // find yt code in url... var r = /(v=)+([\w|-]+)+($|&)/; var result = r.exec(j.attr('href')); Util.output(result); App.CaseStudyVideo.id = result[2]; Util.output('id: '+App.CaseStudyVideo.id); if (App.CaseStudyVideo.api === null){ Util.output('loadVideo'); App.CaseStudyVideo.api = document.createElement('script'); App.CaseStudyVideo.api.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(App.CaseStudyVideo.api, firstScriptTag); } else { stopped = false; Display.video.removeClass('hide_video'); App.CaseStudyVideo.player.loadVideoById(App.CaseStudyVideo.id); } }; var applyTheme = function(){ // remove any theme that might already be on the video holder Display.video.removeClass('theme_0 theme_1 theme_2'); // find the theme (if any) of the hyperlink Display.video.addClass(Util.findTheme(j)); }; // click event for video j.click(function(e){ Util.output('Watch click!'); track.pushEvent("Signposting", j.parent().text(), "URL:" + document.URL); if (!Display.video) addVideoHolder(); Display.video.show(); applyTheme(); loadVideo(); // if there anything to stop while the video plays? CustomEvents.doEvent('PauseForContent'); e.preventDefault(); }); }; }; App.CaseStudyVideo.api = null; App.CaseStudyVideo.id = null; })(); ;(function(){ if (typeof App === 'undefined') App = {}; // args: j is a jquery link ref App.CloseCaseStudyVideo = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.CloseCaseStudyVideo.prototype.init = function(){ // required elements var a = [ Display.video ]; if (!Display.required(a)){ Util.output('CloseCaseStudyVideo has missing elements.'); return; } // remove video var stopVideo = function(){ CustomEvents.doEvent('StopVideo'); // did we stop anything while the video played? CustomEvents.doEvent('UnpauseFromContent'); }; var closeVideo = function(){ if (Display.video.css('display') != 'none'){ Util.output('closeVideo'); stopVideo(); } }; j.click(function(e){ closeVideo(); e.preventDefault(); }); }; }; })(); (function(){ if (typeof App === 'undefined') App = {}; // arg: hyperlink element (jquery) that launches video App.WatchBigVideo = function(j){ this.element = typeof j !== 'undefined' ? j : null; this.player = null; App.WatchBigVideo.prototype.init = function(){ // requires elements var a = [ Display.content, Display.section ]; if (!Display.required(a)){ Util.output('WatchBigVideo has missing elements.'); return; } /// common properties var done = false; var stopped = false; /// functionality var stopVideo = function(){ Util.output('stopVideo'); stopped = true; if (App.WatchBigVideo.player !== null) App.WatchBigVideo.player.stopVideo(); Display.video.addClass('hide_video'); }; // called if Display.video is NOT set var addVideoHolder = function(){ Display.video = $('
    Close video
    '); Display.content.prepend(Display.video); Main.scan(Display.content); // listen for custom events CustomEvents.addTo('StopVideo', stopVideo); }; var onPlayerStateChange = function(event) { //Util.output(event.data); switch (event.data){ case YT.PlayerState.PLAYING : if (!done) done = true; break; case YT.PlayerState.ENDED : Util.output('YT.PlayerState.ENDED'); App.WatchBigVideo.player.seekTo(2); App.WatchBigVideo.player.pauseVideo(); break; default : // do nothing ;-) } }; var onPlayerReady = function(event) { Util.output('onPlayerReady'); if (!stopped) event.target.playVideo(); }; var onPlayerError = function(event) { var tryAgain = function(){ // this still needs some attention, occassionally gets caught in a 'error' loop if (!done && !stopped){ App.WatchBigVideo.player.loadVideoById(id, 0, 'hd1080'); } }; Util.output('YT Player Error: '+event.data); setTimeout(tryAgain, 500); }; App.WatchBigVideo.onYouTubeIframeAPIReady = function() { Util.output('onYouTubeIframeAPIReady'); Util.output('actual id: ' + App.WatchBigVideo.id); App.WatchBigVideo.player = new YT.Player('player', { height: '100%', width: '100%', videoId: App.WatchBigVideo.id, suggestedQuality: 'hd1080', events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange, 'onError': onPlayerError }, playerVars: { wmode: "transparent" } }); }; // add to global onYouTubeIframeAPIReady = function(){ App.WatchBigVideo.onYouTubeIframeAPIReady(); }; var loadVideo = function(){ // find yt code in url... var r = /(v=)+([\w|-]+)+($|&)/; var result = r.exec(j.attr('href')); Util.output(result); App.WatchBigVideo.id = result[2]; Util.output('id: '+App.WatchBigVideo.id); if (App.WatchBigVideo.api === null){ Util.output('loadVideo'); App.WatchBigVideo.api = document.createElement('script'); App.WatchBigVideo.api.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(App.WatchBigVideo.api, firstScriptTag); } else { stopped = false; Display.video.removeClass('hide_video'); App.WatchBigVideo.player.loadVideoById(App.WatchBigVideo.id); } }; var applyTheme = function(){ // remove any theme that might already be on the video holder Display.video.removeClass('theme_0 theme_1 theme_2'); // find the theme (if any) of the hyperlink Display.video.addClass(Util.findTheme(j)); }; // click event for video j.click(function(e){ Util.output('Watch click!'); track.pushEvent("Signposting", j.parent().text(), "URL:" + document.URL); if (!Display.video) addVideoHolder(); Display.video.show(); Display.section.hide(); applyTheme(); loadVideo(); // if there anything to stop while the video plays? CustomEvents.doEvent('PauseForContent'); e.preventDefault(); }); }; }; App.WatchBigVideo.api = null; App.WatchBigVideo.id = null; })(); (function(){ if (typeof App === 'undefined') App = {}; // arg: jquery element holding the video App.VideoToFillContent = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.VideoToFillContent.prototype.init = function(){ // requires elements var a = [ Display.header ]; if (!Display.required(a)){ Util.output('VideoToFillContent has missing elements.'); return; } var fill = function(){ j.height(0); var bottom = Display.picker ? Display.picker.height() : 0; if (Display.footer) bottom += Display.footer.height(); var h = $(window).height(); var c = h-bottom-Display.header.height(); j.height(c); }; Resize.addTo(fill); fill(); }; }; })(); (function(){ if (typeof App === 'undefined') App = {}; // arg: jquery hyperlink element App.CloseBigVideo = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.CloseBigVideo.prototype.init = function(){ // requires elements var a = [ Display.video, Display.content, Display.section ]; if (!Display.required(a)){ Util.output('CloseBigVideo has missing elements.'); return; } // remove video var stopVideo = function(){ // Send a custom event, if there is a video playing // it should respond CustomEvents.doEvent('StopVideo'); // did we stop anything while the video played? CustomEvents.doEvent('UnpauseFromContent'); //jwplayer('player_9935').stop(); //Display.video.find('#player_9935').html(""); }; var closeVideo = function(){ if (Display.video.css('display') != 'none'){ Util.output('closeVideo'); //Display.video.hide(); // ie doesn't like this! Display.section.show(); stopVideo(); Resize.doResize(); } } // click event to remove video j.click(function(e){ closeVideo(); e.preventDefault(); }); // swapping content may require closing the video... CustomEvents.addTo('stopContent', closeVideo); }; }; })(); (function(){ if (typeof App === 'undefined') App = {}; // args: jquery element container with download_column(s) App.DownloadColumnHeight = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.DownloadColumnHeight.prototype.init = function(){ // requires elements var columns = j.find('.download_column'); var a = [ columns ]; if (!Display.required(a)){ Util.output('DownloadColumnHeight has missing elements.'); return; } // find the tallest column & make all the same var h = 0; var col, n; columns.each(function(){ col = $(this); n = col.height(); if (n > h) h = n; }); columns.height(h); }; }; })(); (function(){ if (typeof App === 'undefined') App = {}; // args: jquery element (fieldset or warpper containing input) App.HeaderSearch = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.HeaderSearch.prototype.init = function(){ // requires elements var input = $('#Header_HeaderSearch'); var a = [ input ]; if (!Display.required(a)){ Util.output('HeaderSearch has missing elements.'); return; } // common elements var r = /^\s+$/; // whitespace only. var emptyText = 'SEARCH'; var val = input.val(); var loaded = false; var total = 5; var wait = 500; var out = 3000; var timer, outTimer, url, content, list, n, i, cat, cList, item; var results = $(''); j.append(results); // add 'search' text when empty input.attr('data-behavior', 'SearchFocus'); Main.scan(j); // show predictive search on change... var stopTimeout = function(e){ clearTimeout(outTimer); Util.output('stopTimeout'); } var startTimeout = function(e){ outTimer = setTimeout(hideResults, out); } var holder = $('
    '); var iframe = $(''); if ($('html').hasClass('lt-ie9')) iframe.attr('frameborder', 0); holder.append(iframe); $('body').append(holder); // args rb for result_block jquery element var addItem = function(rb){ item = $('
  • '); item.append(rb); results.prepend(item); } var showResults = function(){ results.removeClass('hidden'); // show top 3 pdfs, 1 video, & make up difference with web... cat = content.find('#results_cat_downloads') cList = cat.find('.result_block'); n = cList.length < 3 ? cList.length : 3; for (i = n-1; i >= 0; i--) addItem(cList[i]); cat = content.find('#results_cat_video'); cList = cat.find('.result_block'); if (cList.length > 0) addItem(cList[0]); cat = content.find('#results_cat_web'); cList = cat.find('.result_block'); i = results.find('li').length; n = total - i; for (i = n-1; i >= 0; i--) addItem(cList[i]); list = results.find('a'); list.removeClass('long'); list.removeClass('short'); list.each(function(){ item = $(this); i = item.height(); if (i > 28) item.addClass('long'); else item.addClass('short'); item.focus(stopTimeout); item.blur(startTimeout); }); results.find('.result_block').last().addClass('last'); }; var hideResults = function(){ if (!results.hasClass('hidden')) results.addClass('hidden'); list = results.find('a'); list.each(function(){ item = $(this); item.off('focus', stopTimeout); item.off('blur', startTimeout); }); results.html(''); }; // detect input change var iframeReady = function(e){ loaded = true; content = iframe.contents(); list = content.find('.result_block, .result_altblock'); if (list.length > 0) showResults(); else hideResults(); } var loadSearch = function(){ iframe.one('load', iframeReady); loaded = false; Util.output(input.val()); url = encodeURI('/search/default.aspx?zoom_query='+input.val()+'&zoom_per_page=100'); iframe.attr('src', url); }; var inputChange = function(e){ Util.output(input.val()); clearTimeout(timer); timer = setTimeout(loadSearch, wait); }; input.change(inputChange); var inputKeypress = function(e){ input.change(); }; var detectChange = function(e){ input.change(); input.on('keyup', inputKeypress); }; var ignoreChange = function(e){ input.off('keyup', inputKeypress); }; input.focus(detectChange); input.blur(ignoreChange); input.focus(stopTimeout); input.blur(startTimeout); }; }; })(); (function(){ if (typeof App === 'undefined') App = {}; // args: jquery element (input field only please!) App.SearchFocus = function(j){ this.element = typeof j !== 'undefined' ? j : null; App.SearchFocus.prototype.init = function(){ // common elements var r = /^\s+$/; // whitespace only. var emptyText = 'Search'; var val = j.val(); if (emptyText.toUpperCase() === val) emptyText = emptyText.toUpperCase(); // add 'search' text when empty var searchFocus = function(e){ val = j.val(); //Util.output('searchFocus: "'+val+'"'); if (val === emptyText || r.test(val)){ val = ""; j.val(val); } }; var searchBlur = function(e){ val = j.val(); //Util.output('searchBlur: "'+val+'"'); if (val.length === 0 || r.test(val)){ val = emptyText; j.val(val); } }; j.on('focus', searchFocus); j.on('blur', searchBlur); }; }; })(); var Main = { setUp: function () { Resize.init(); Display.assignKeyElements(); Tracking.init(); Main.scan(); }, // args: optional jquery element to search inside // scan will look for behaviors in 'App' scan: function (j) { if (j == undefined) j = $(document); j.find('*[data-behavior]').each(function () { var c = $(this); var list = c.attr('data-behavior'); $.each(list.split(" "), function (index, b) { if (typeof App[b] !== 'undefined') { var obj = new App[b](c); obj.init(); } else Util.output('data-behavior: "' + b + '" not recognised!'); }); // then remove attr to prevent initialising more than once... c.removeAttr('data-behavior'); }); } }; /* ========================================================================== DISPLAY ========================================================================== */ var Display = { // commonly shared elements (assign when page loads) wrapper: null, header: null, content: null, section: null, picker: null, footer: null, // not set until needed video: null, popup: null, iframe: null, popupSrc: null, // for scrolling scrollPage: null, // assign the commonly shared elements before scanning for behaviors assignKeyElements: function () { var j; j = $('#wrapper'); if (j.length > 0) Display.wrapper = j; j = $('#header'); if (j.length > 0) Display.header = j; j = $('#content'); if (j.length > 0) Display.content = j; j = $('#main, #MainContent_main'); if (j.length > 0) Display.section = j; j = $('#story_picker'); if (j.length > 0) Display.picker = j; j = $('#footer'); if (j.length > 0) Display.footer = j; // sort out which is the window scroll elements Display.scrollPage = $('html, body'); $('html, body').each(function () { var i = $(this).attr('scrollTop'); $(this).attr('scrollTop', i + 1); if ($(this).attr('scrollTop') === i + 1) { Display.scrollPage = this.nodeName.toLowerCase(); // alert('Display.scrollPage: '+Display.scrollPage); $(this).attr('scrollTop', i); return false; } }); }, // args: array of required commonly shared elements // (as listed at the top of 'Display') required: function (a) { var boo = true; var i; var n = a.length; for (i = 0; i < n; i++) if (!a[i] || a[i].length < 1) boo = false; return boo; } }; /* ========================================================================== RESIZE ========================================================================== */ var Resize = { timer: null, ie: false, // lt ie9 also fired onrise with layout changes, // compare window size with each call too... dim: { w: 0, h: 0 }, resizeList: [], init: function () { //Resize.ie = (navigator.userAgent.indexOf('MSIE') > -1); Resize.ie = $('html').hasClass('lt-ie9'); $(window).resize((Resize.ie ? Resize.startTimer : Resize.doResize)); }, // args: f for function to add to list addTo: function (f) { Resize.resizeList.push(f); }, doResize: function () { var i; var n = Resize.resizeList.length; for (i = 0; i < n; i++) Resize.resizeList[i](); }, startTimer: function () { if (Resize.dim.w != $(window).width() || Resize.dim.h != $(window).height()) { Resize.clearTimer(); Resize.dim.w = $(window).width(); Resize.dim.h = $(window).height(); Resize.timer = setTimeout(Resize.doResize, 500); } }, clearTimer: function () { clearTimeout(Resize.timer); }, // args: f for function to remove from event removeFrom: function (f) { var i; var n = Resize.resizeList.length; for (i = n - 1; i >= 0; i--) { if (Resize.resizeList[i] === f) { Resize.resizeList.splice(i, 1); break; } } } }; /* ========================================================================== CUSTOM EVENTS ========================================================================== */ var CustomEvents = { list: {}, // args: e for string representing event, f for function to add event addTo: function (e, f) { // see if event name exists, add event name to list if it's not... if (typeof CustomEvents.list[e] === 'undefined') CustomEvents.list[e] = []; // add the function to the array for this event name CustomEvents.list[e].push(f); //Util.output("Custom Event '"+e+"' added!"); }, // args: e for string representing event, data for an object of optional // data to pass to each function on list doEvent: function (e, data) { if (typeof CustomEvents.list[e] !== 'undefined') { // clone the array (as some functions may alter the original during the loop) var i; var ev = CustomEvents.list[e].slice(0); var n = ev.length; //Util.output("Custom Event '"+e+"' called, "+n+" response"+(n !== 1 ? "s" : "")+"!"); for (i = 0; i < n; i++) { if (typeof ev[i] === 'function') ev[i](data); } ev = null; } else Util.output("Custom Event '" + e + "' not in use!"); }, // args: e for string representing event, f for function to remove from event removeFrom: function (e, f) { if (typeof CustomEvents.list[e] !== 'undefined') { var i; var ev = CustomEvents.list[e]; var n = ev.length; for (i = n - 1; i >= 0; i--) { if (ev[i] === f) { ev.splice(i, 1); //Util.output("Custom Event ("+i+") '"+e+"' removed!"); break; } } } } }; /* ========================================================================== GA EVENTS ========================================================================== */ var Tracking = { init: function () { track.init(); $("#logo a").click(function () { track.pushEvent("Navigation", "Logo Home", "URL:" + document.URL); }); // $("#primary_links a").click(function () { // track.pushEvent("Drop down navigation", $(this).text(), "URL:" + document.URL); // }); // $("a.social").click(function () { // track.pushEvent("Navigation", $(this).find('img').attr('alt'), "URL:" + document.URL); // }); // $(".footer_list a").click(function () { // track.pushEvent("Navigation", 'Footer links - ' + $(this).text(), "URL:" + document.URL); // }); // $(".footer_articles a").click(function () { // track.pushEvent("Signposting", 'Footer articles - ' + $(this).parent().text(), "URL:" + document.URL); // }); // $("a.download_icon").click(function () { // track.pushEvent("Signposting", $(this).parent().find('p').text(), "URL:" + document.URL); // }); // $(".download_column a").click(function () { // track.pushEvent("Download", $(this).find('span').first().text(), "URL:" + $(this).attr['href']); // }); // $(".key_download a").click(function () { // track.pushEvent("Download", $(this).parent().find('h2').text(), "URL:" + $(this).attr['href']); // }); $("a[href$='pdf']").click(function () { track.pushEvent("Download", $(this).parent().text(), "URL:" + $(this).attr('href')); }); // $(".popup_content .actions a[href$='pdf']").click(function () { // track.pushEvent("Download", $(this).parent().text(), "URL:" + $(this).attr['href']); // }); } }; /* ========================================================================== UTIL ========================================================================== */ var Util = { // true or false log: true, // args: o for output string (or whatever) output: function (o) { if (console && Util.log) console.log(o); }, // args: j for jquery element. looks up tree // from supplied j, returns class name as string findTheme: function (j) { var theme = null; var c = j; var look = function () { if (c.hasClass('theme_0')) theme = 'theme_0'; if (c.hasClass('theme_1')) theme = 'theme_1'; if (c.hasClass('theme_2')) theme = 'theme_2'; if (c.hasClass('theme_3')) theme = 'theme_3'; if (theme === null && c.parent().length > 0) { c = c.parent(); look(); } }; look(); return theme === null ? 'theme_0' : theme; }, // args: j for jquery element. removes any theme // on this jquery element only removeTheme: function (j) { j.removeClass('theme_0'); j.removeClass('theme_1'); j.removeClass('theme_2'); j.removeClass('theme_3'); } }; /* ========================================================================== KICKOFF ========================================================================== */ (function () { $(document).ready(function () { Main.setUp(); }); } ());