/*! * * Homebrewed plugin functions! * * Basically it's a bunch of common functions used in the websites we * build. They're built in the format of jQuery plugins for reusability. * * You may remove those that you don't need. * * - HC * * @TODO: Make these more extensible for easier future usage. */ var homebrew = {}; (function($) { /* Avoid `console` errors in browsers that lack a console. */ var method, noop = function () {}, methods = [ 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn' ], length = methods.length, console = (window.console = window.console || {}); while (length--) { method = methods[length]; // Only stub undefined methods. if (!console[method]) { console[method] = noop; } } /* Setup homebrew object */ var root = $('html'); $.extend(homebrew, { browser : { ie : root.hasClass('ie'), ie9 : root.hasClass('ie9'), lt9 : root.hasClass('lt9'), ie8 : root.hasClass('ie8'), lt8 : root.hasClass('lt8'), ie7 : root.hasClass('ie7'), firefox : (window.mozIndexedDB !== undefined) }, events : { transitionEnd : 'oTransitionEnd otransitionend webkitTransitionEnd transitionend' }, classes : { transitionable: 'is-transitionable' }, screenSize : { small : false, medium : false, large : true }, mediaQueries : { small : 'only screen and (max-width: 40em)', medium : 'only screen and (min-width: 40.063em)', large : 'only screen and (min-width: 64.063em)' }, mediaQueriesIE9 : { small : { size : 640, method : 'max-width' }, medium : { size : 641, method : 'min-width' }, large : { size : 1025, method : 'min-width' } } }); $.extend(homebrew, { utils : { /* * Executes a function a max of once every n milliseconds * * Arguments: * Func (Function): Function to be throttled. * * Delay (Integer): Function execution threshold in milliseconds. * * Returns: * Lazy_function (Function): Function with throttling applied. */ throttle : function(func, delay) { var timer = null; return function () { var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function () { func.apply(context, args); }, delay); }; }, /* End throttle */ /* * Executes a function when it stops being invoked for n seconds * Modified version of _.debounce() http://underscorejs.org * * Arguments: * Func (Function): Function to be debounced. * * Delay (Integer): Function execution threshold in milliseconds. * * Immediate (Bool): Whether the function should be called at the beginning * of the delay instead of the end. Default is false. * * Returns: * Lazy_function (Function): Function with debouncing applied. */ debounce : function(func, delay, immediate) { var timeout, result; return function() { var context = this, args = arguments, later = function() { timeout = null; if (!immediate) result = func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, delay); if (callNow) result = func.apply(context, args); return result; }; } /* End debounce */ }, /* End utils */ makePlugin : function(plugin) { var pluginName = plugin.prototype.name; $.fn[pluginName] = function(options) { var args = $.makeArray(arguments), after = args.slice(1); return this.each(function() { var instance = $.data(this, pluginName); if(instance) { if(typeof options === 'string') { instance[options].apply(instance, after); } else if(instance.update) { instance.update.apply(instance, args); } } else { new plugin(this, options); } }); }; }, /* End makePlugin */ generateUniqueID : function() { return String(new Date().getTime()) + String(Math.round(Math.random()*100000, 10)); }, getSelectorsFromHTMLString : function(str) { if(typeof str !== 'string') { console.error('homebrew.getSelectorsFromHTMLString(): Expecting a string as the first argument. Please check:'); console.log(str); return {}; } var tagMatch = str.match(/<(.*?) /g), attributesMatch = str.match(/ (.*?)=("|')(.*?)("|')/g), selectorsObj = {}; if(tagMatch) { selectorsObj.tag = tagMatch[0].replace(/(<| )/g, ''); } if(attributesMatch) { var attributeSplitArray, classesArray; while(attributesMatch.length) { attributeSplitArray = $.trim(attributesMatch.shift()).split('='); switch(attributeSplitArray[0]) { case 'class' : classesArray = attributeSplitArray[1].replace(/("|')/g, '').split(' '); for(var i = classesArray.length-1; i > -1; i--) { if(classesArray[i] === '') { classesArray.splice(i, 1); } } selectorsObj.classes = classesArray; break; default : selectorsObj[attributeSplitArray[0]] = attributeSplitArray[1].replace(/("|')/g, ''); break; } } } return selectorsObj; }, /* End getSelectorsFromHTMLString */ getClassFromHTMLString : function(str) { var selectorsObj = this.getSelectorsFromHTMLString(str); if(selectorsObj.classes && selectorsObj.classes.length) { return selectorsObj.classes; } else { return []; } }, getKeyValuePairsFromString : function(str, pairSeparator, keyValueSeparator) { pairSeparator = pairSeparator || ';'; keyValueSeparator = keyValueSeparator || ':'; var splitArray = str.split(pairSeparator), keyValuePairs = {}, currentPair; while(splitArray.length) { currentPair = splitArray.shift(); if(!currentPair) continue; currentPair = currentPair.split(keyValueSeparator); currentPair = currentPair.map(function(str) { return $.trim(str); }); if(currentPair[1] === 'true') { currentPair[1] = true; } else if(currentPair[1] === 'false') { currentPair[1] = false; } keyValuePairs[currentPair[0]] = currentPair[1]; } return keyValuePairs; }, watchSize : function(mediaQuery, callback) { var self = this, _mediaQuery = self.mediaQueries[mediaQuery]; if(typeof _mediaQuery === 'undefined') { throw new Error('homebrew.watchSize(): No match media query. mediaQuery provided is ' + mediaQuery); } /* For modern browsers, use native matchMedia.addListener */ if(typeof matchMedia === 'function' && matchMedia.addListener) { var matchMediaObj = matchMedia(_mediaQuery); callback(matchMediaObj.matches); matchMediaObj.addListener(function(mq) { callback(mq.matches); }); /* For IE9, simulate the matchMedia.addListener behaviour using * a resize handler. */ } else if(!self.browser.lt9) { var mediaQueryProps = self.mediaQueriesIE9[mediaQuery]; if(typeof mediaQueryProps === 'undefined') return; var currentScreen, getCurrentScreen; if(mediaQueryProps.method === 'min-width') { getCurrentScreen = function() { return ($(window).width() >= mediaQueryProps.size); }; } else if(mediaQueryProps.method === 'max-width') { getCurrentScreen = function() { return ($(window).width() <= mediaQueryProps.size); }; } currentScreen = getCurrentScreen(); callback(currentScreen); $(window).on('resize.watchMedia', self.utils.throttle(function() { if(currentScreen !== getCurrentScreen()) { currentScreen = !currentScreen; callback(currentScreen); } }, 100)); /* For legacy browsers, only run the functions for medium * screens and above. */ } else { if(mediaQuery === 'small' || mediaQuery === 'xsmall') { callback(false); } else { callback(true); } } } /* End watchSize */ }); homebrew.watchSize('small', function(isMediumScreen) { homebrew.screenSize.small = isMediumScreen; homebrew.screenSize.medium = !isMediumScreen; }); homebrew.watchSize('large', function(isLargeScreen) { homebrew.screenSize.medium = !isLargeScreen; homebrew.screenSize.large = isLargeScreen; }); /**---- Carouselify ---**\ * Turn a list of elements into a rotating carousel. * * Arguments: * $('.carousel').carouselify({ * items : '.carousel-item', * activeItem : null, * classes : { * active : 'is-active', * hidden : 'is-hidden' * }, * loop : true, * transitions : { * enable : true, * classes : { * transitionIn : 'is-transitioning-in', * transitionOut : 'is-transitioning-out', * reverse : 'is-reverse' * }, * onStart : null, * onEnd : null * }, * switchers : { * enable : true, * markups : { * nextSwitcher : '