Created
July 27, 2017 15:52
-
-
Save Davidslv/a11b86ed8736ce322c801077ef1a16e7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
"use strict"; | |
window.GOVUK = window.GOVUK || {}; | |
var $ = window.jQuery; | |
function BrowseColumns(options){ | |
if(options.$el.length === 0) return; | |
if($(window).width() < 640) return; // don't ajax navigation on mobile | |
this.$el = options.$el; | |
this.$root = this.$el.find('#root'); | |
this.$section = this.$el.find('#section'); | |
this.$subsection = this.$el.find('#subsection'); | |
this.$breadcrumbs = $('.govuk-breadcrumbs'); | |
this.animateSpeed = 330; | |
if(this.$section.length === 0){ | |
this.$section = $('<div id="section" class="section-pane pane with-sort" />'); | |
this.$el.prepend(this.$section); | |
this.$el.addClass('section'); | |
} | |
if(this.$subsection.length === 0){ | |
this.$subsection = $('<div id="subsection" class="subsection-pane pane" />').hide(); | |
this.$el.prepend(this.$subsection); | |
} else { | |
this.$subsection.show(); | |
} | |
this.displayState = this.$el.data('state'); | |
if(typeof this.displayState === 'undefined'){ | |
this.displayState = 'root'; | |
} | |
this._cache = {}; | |
this.lastState = this.parsePathname(window.location.pathname); | |
this.$el.on('click', 'a', this.navigate.bind(this)); | |
$(window).on('popstate', this.popState.bind(this)); | |
} | |
BrowseColumns.prototype = { | |
popState: function(e){ | |
var state = e.originalEvent.state, | |
loadPromise; | |
if(!state){ // state will be null if there was no state set | |
state = this.parsePathname(window.location.pathname); | |
} | |
if(this.lastState.slug === state.slug){ | |
return; // nothing has changed | |
} | |
if(state.slug == ''){ | |
loadPromise = this.showRoot(); | |
} else if(state.subsection){ | |
loadPromise = this.restoreSubsection(state); | |
} else { | |
loadPromise = this.loadSectionFromState(state, true); | |
} | |
loadPromise.then(function(){ | |
this.trackPageview(state); | |
}.bind(this)); | |
}, | |
restoreSubsection: function(state){ | |
// are we displaying the correct section for the subsection? | |
if(this.lastState.section != state.section){ | |
// load the section then load the subsection after | |
var sectionPathname = window.location.pathname.split('/').slice(0,-1).join('/'); | |
var sectionState = this.parsePathname(sectionPathname); | |
return this.loadSectionFromState(sectionState, true) | |
.then(function(){ | |
return this.loadSectionFromState(state, true); | |
}.bind(this)); | |
} else { | |
return this.loadSectionFromState(state, true); | |
} | |
}, | |
sectionCache: function(prefix, slug, data){ | |
if(typeof data === 'undefined'){ | |
return this._cache[prefix + slug]; | |
} else { | |
this._cache[prefix + slug] = data; | |
} | |
}, | |
isDesktop: function(){ | |
return $(window).width() > 768; | |
}, | |
showRoot: function(){ | |
this.$section.html(''); | |
this.displayState = 'root'; | |
this.$root.find('h1').focus(); | |
var out = new $.Deferred() | |
return out.resolve(); | |
}, | |
showSection: function(state){ | |
state.title = this.getTitle(state.slug); | |
this.setTitle(state.title); | |
this.$section.html(state.sectionData.html) | |
this.highlightSection('root', state.path); | |
this.removeLoading(); | |
this.updateBreadcrumbs(state); | |
var animationDone; | |
if(this.displayState === 'subsection'){ | |
// animate to the right position and update the data | |
animationDone = this.animateSubsectionToSectionDesktop(); | |
} else if(this.displayState === 'root'){ | |
animationDone = this.animateRootToSectionDesktop(); | |
} else { | |
animationDone = new $.Deferred(); | |
animationDone.resolve(); | |
} | |
return animationDone.then(function(){ | |
this.$section.find('h1').focus(); | |
}.bind(this)); | |
}, | |
animateSubsectionToSectionDesktop: function(){ | |
var out = new $.Deferred() | |
function afterAnimate(){ | |
this.displayState = 'section'; | |
this.$el.removeClass('subsection').addClass('section'); | |
this.$section.attr('style', ''); | |
this.$section.find('.pane-inner').attr('style', ''); | |
this.$section.addClass('with-sort'); | |
this.$root.attr('style', ''); | |
out.resolve(); | |
} | |
// animate to the right position and update the data | |
this.$root.css({ position: 'absolute', width: this.$root.width() }); | |
this.$subsection.hide(); | |
this.$section.css('margin-right', '63%'); | |
if(this.isDesktop()){ | |
this.$section.find('.pane-inner.curated').animate({ | |
paddingLeft: '30px' | |
}, this.animateSpeed); | |
this.$section.find('.pane-inner.alphabetical').animate({ | |
paddingLeft: '96px' | |
}, this.animateSpeed); | |
var sectionProperties = { | |
width: '35%', | |
marginLeft: '0%', | |
marginRight: '40%' | |
}; | |
} else { | |
var sectionProperties = { | |
width: '30%', | |
marginLeft: '0%', | |
marginRight: '45%' | |
}; | |
} | |
this.$section.animate(sectionProperties, this.animateSpeed, afterAnimate.bind(this)); | |
return out; | |
}, | |
animateRootToSectionDesktop: function(){ | |
var out = new $.Deferred() | |
this.displayState = 'section'; | |
this.$el.removeClass('subsection').addClass('section'); | |
return out.resolve(); | |
}, | |
showSubsection: function(state){ | |
state.title = this.getTitle(state.slug); | |
this.setTitle(state.title); | |
this.$subsection.html(state.sectionData.html); | |
this.highlightSection('section', state.path); | |
this.highlightSection('root', '/browse/' + state.section); | |
this.removeLoading(); | |
this.updateBreadcrumbs(state); | |
var animationDone; | |
if(this.displayState !== 'subsection'){ | |
animationDone = this.animateSectionToSubsectionDesktop(); | |
} else { | |
animationDone = new $.Deferred(); | |
animationDone.resolve(); | |
} | |
return animationDone.then(function(){ | |
this.$subsection.find('h1').focus(); | |
}.bind(this)); | |
}, | |
animateSectionToSubsectionDesktop: function(){ | |
var out = new $.Deferred(); | |
// animate to the right position and update the data | |
this.$root.css({ position: 'absolute', width: this.$root.width() }); | |
this.$section.find('.sort-order').hide(); | |
this.$section.find('.pane-inner').animate({ | |
paddingLeft: '0' | |
}, this.animateSpeed); | |
if(this.isDesktop()){ | |
var sectionProperties = { | |
width: '25%', | |
marginLeft: '-13%', | |
marginRight: '63%' | |
}; | |
} else { | |
var sectionProperties = { | |
width: '30%', | |
marginLeft: '-18%', | |
marginRight: '63%' | |
}; | |
} | |
this.$section.animate(sectionProperties, this.animateSpeed, function(){ | |
this.$el.removeClass('section').addClass('subsection'); | |
this.$subsection.show(); | |
this.$section.removeClass('with-sort'); | |
this.displayState = 'subsection'; | |
this.$section.find('.sort-order').attr('style', ''); | |
this.$section.attr('style', ''); | |
this.$section.find('.pane-inner').attr('style', ''); | |
this.$root.attr('style', ''); | |
out.resolve(); | |
}.bind(this)); | |
return out; | |
}, | |
getTitle: function(slug){ | |
var $link = this.$el.find('a[href$="/browse/'+slug+'"]:first'), | |
$heading = $link.find('h3'); | |
if($heading.length > 0){ | |
return $heading.text(); | |
} else { | |
return $link.text(); | |
} | |
}, | |
setTitle: function(title){ | |
$('title').text(title); | |
}, | |
addLoading: function($el){ | |
this.$el.attr('aria-busy', 'true'); | |
$el.addClass('loading'); | |
}, | |
removeLoading: function(){ | |
this.$el.attr('aria-busy', 'false'); | |
this.$el.find('a.loading').removeClass('loading'); | |
}, | |
// getSectionData: returns a promise which will contain the data | |
// Returns data from the cache if it is there or puts the data in the cache | |
// if it is not. | |
getSectionData: function(state){ | |
var cacheForSlug = this.sectionCache('section', state.slug), | |
out = new $.Deferred(), | |
url = '/browse/' + state.slug + '.json'; | |
if(typeof state.sectionData !== 'undefined'){ | |
out.resolve(state.sectionData); | |
} else if(typeof cacheForSlug !== 'undefined'){ | |
out.resolve(cacheForSlug); | |
} else { | |
$.ajax({ | |
url: url | |
}).then(function(data){ | |
this.sectionCache('section', state.slug, data); | |
out.resolve(data); | |
}.bind(this)); | |
} | |
return out; | |
}, | |
highlightSection: function(section, slug){ | |
this.$el.find('#'+section+' .active').removeClass('active') | |
this.$el.find('a[href$="'+slug+'"]').parent().addClass('active'); | |
}, | |
parsePathname: function(pathname){ | |
var out = { | |
path: pathname, | |
slug: pathname.replace(/\/browse\/?/, '') | |
}; | |
if(out.slug.indexOf('/') > -1){ | |
out.section = out.slug.split('/')[0]; | |
out.subsection = out.slug.split('/')[1]; | |
} else { | |
out.section = out.slug; | |
} | |
return out; | |
}, | |
scrollToBrowse: function(){ | |
var $body = $('body'), | |
elTop = this.$el.offset().top; | |
if( $body.scrollTop() > elTop ){ | |
$('body').animate({scrollTop: elTop}, this.animateSpeed); | |
} | |
}, | |
loadSectionFromState: function(state, poppingState){ | |
var donePromise = this.getSectionData(state); | |
if(state.subsection){ | |
var sectionPromise = donePromise; | |
donePromise = $.when(sectionPromise); | |
} | |
return donePromise | |
.then(function(sectionData){ | |
state.sectionData = sectionData; | |
this.scrollToBrowse(); | |
this.lastState = state; | |
if(state.subsection){ | |
return this.showSubsection(state); | |
} else { | |
return this.showSection(state); | |
} | |
}.bind(this)) | |
.then(function() { | |
if(typeof poppingState === 'undefined'){ | |
history.pushState(state, '', state.path); | |
this.trackPageview(state); | |
} | |
}.bind(this)); | |
}, | |
navigate: function(e){ | |
if(e.currentTarget.pathname.match(/^\/browse\/[^\/]+(\/[^\/]+)?$/)){ | |
var $target = $(e.currentTarget); | |
if ($target.hasClass('ab-test-redirect')) { | |
// Allow browser to follow link, which will redirect to the correct page | |
return; | |
} | |
e.preventDefault(); | |
var state = this.parsePathname(e.currentTarget.pathname); | |
state.title = $target.text(); | |
if(state.path === window.location.pathname){ | |
return; | |
} | |
this.addLoading($target); | |
this.loadSectionFromState(state); | |
} | |
}, | |
updateBreadcrumbs: function(state) { | |
var $newBreadcrumbs = $(state.sectionData.breadcrumbs); | |
this.$breadcrumbs.html($newBreadcrumbs.html()); | |
}, | |
trackPageview: function(state){ | |
var sectionTitle = this.$section.find('h1').text(); | |
sectionTitle = sectionTitle ? sectionTitle.toLowerCase() : 'browse'; | |
if (GOVUK.analytics && GOVUK.analytics.trackPageview) { | |
GOVUK.analytics.trackPageview( | |
state.path, | |
null, | |
{ | |
dimension1: sectionTitle | |
} | |
); | |
} | |
} | |
}; | |
GOVUK.BrowseColumns = BrowseColumns; | |
$(function(){ GOVUK.browseColumns = new BrowseColumns({$el: $('.browse-panes')}); }) | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment