(function($) { var isMobile; var isIOS; var isAndroid; var isSafari; var gncaWatcher = { isIOS: function() { if ( typeof(isIOS) === 'undefined' ) { isIOS = window.navigator.platform && /iP(hone|od|ad)/i.test(window.navigator.platform); } return isIOS; }, isAndroid: function() { if ( typeof(isAndroid) === 'undefined' ) { isAndroid = window.navigator.userAgent && /android/i.test(window.navigator.userAgent); } return isAndroid; }, isMobile: function() { if ( typeof(isMobile) === 'undefined' ) { isMobile = gncaWatcher.isAndroid() || gncaWatcher.isIOS(); } return isMobile; }, isSafari: function() { if ( typeof(isSafari) === 'undefined' ) { isSafari = window.navigator.userAgent && !(/chrome/i.test(window.navigator.userAgent)) && /safari/i.test(window.navigator.userAgent); } return isSafari; }, hasWifi: function() { return gncaWatcher.isAndroid() && navigator.connection && navigator.connection.type === 'wifi'; }, saveData: function() { if ( navigator && navigator.connection ) { // effective connection speed is 3g or lower if ( /\slow-2g|2g|3g/.test( navigator.connection.effectiveType ) ) { return true; } // Save-Data network header is set to true if ( true === navigator.connection.saveData ) { return true; } } return false; } }; window.GNCA_Watcher = gncaWatcher; })( jQuery ); ; if ( 'undefined' === typeof( jQuery.browser ) ) { function isIE() { var style = document.createElement( 'div' ).style; style.cssText = 'position:sticky;position:-webkit-sticky;position:-ms-sticky;'; var isSupported = -1 !== style.position.indexOf( 'sticky' ); return ! isSupported; } var browser = { msie: isIE() }; jQuery.browser = browser; }; /*! * jQuery Cookie Plugin v1.3.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2013 Klaus Hartl * Released under the MIT license */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as anonymous module. define(['jquery'], factory); } else { // Browser globals. factory(jQuery); } }(function ($) { var pluses = /\+/g; function raw(s) { return s; } function decoded(s) { return decodeURIComponent(s.replace(pluses, ' ')); } function converted(s) { if (s.indexOf('"') === 0) { // This is a quoted cookie as according to RFC2068, unescape s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } try { return config.json ? JSON.parse(s) : s; } catch(er) {} } var config = $.cookie = function (key, value, options) { // write if (value !== undefined) { options = $.extend({}, config.defaults, options); if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } value = config.json ? JSON.stringify(value) : String(value); return (document.cookie = [ config.raw ? key : encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // read var decode = config.raw ? raw : decoded; var cookies = document.cookie.split('; '); var result = key ? undefined : {}; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split('='); var name = decode(parts.shift()); var cookie = decode(parts.join('=')); if (key && key === name) { result = converted(cookie); break; } if (!key) { result[name] = converted(cookie); } } return result; }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) !== undefined) { $.cookie(key, '', $.extend(options, { expires: -1 })); return true; } return false; }; })); ; // This file is merely here to set up our global dom library var and ensure the plugins will direct to it if( window.wrap ){ window.jQuery = wrap; } else if( window.jQuery ){ window.wrap = jQuery; }; /* Extend some native JS objects */ if ( !String.trim ) { String.prototype.trim = String.prototype.trim || function trim() { return this.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); }; }; /* DEFINE GLOBAL NAMESPACE */ // The gNews namespace is used across multiple JS scripts. if (typeof window.gNews == "undefined") window.gNews = {}; gNews.Common = function() { // get jQuery var $ = jQuery; // init on dom-ready $(function() { gNews.Common.init(); }); // PUBLIC PROPERTIES & METHODS return { // PROPERTIES isTouch: false, isMsTouch: false, isIOS: false, isAndroid: false, isBlackBerry: false, isWinPhone: false, isIE: false, isTrident: false, isWebkit: false, isSafari: false, isChrome: false, isFirefox: false, isFlash: false, isViewportSet: false, isOrientationChange: false, // to determine whether page is actively being touched or scrolling status: { isTouched: false, isScrolling: false }, // properties used for when the window is being scrolled (iOS only, usually) scrollPos: { current: { left:0, top:0 }, orig: { left:0, top:0 }, delta: { left:0, top:0 } }, scrollCallbacks: [], // array of objects to use to trigger custom jQuery events // format: [ {nodeObj, customEventName}, ... ] // properties used for when the window is resized resizeTimeout: false, resizeCallbacks: [], // array of objects to use to trigger custom jQuery events // format: [ {nodeObj, customEventName}, ... ] // METHODS (PRE DOM-LOAD) preInit: function() { //console.log('gNews.Common.preInit()'); // clear console on escape key hit, local only if (window.location.hostname == 'local.globalnews.ca') { $(document).on('keydown', function(ev) { if (typeof ev !== 'undefined') { keyPress = ev.keyCode; if (keyPress == 27 && console) console.clear(); } }); }; // get ref $html = $('html'); // is device iOS (sometimes Android handles things differently from iOS) this.isIOS = ( navigator.userAgent.match(/(iPad|iPhone|iPod)/gi) ? true : false ); if (this.isIOS ) { $( document.documentElement ).addClass( 'is_ios' ); } // is device Android this.isAndroid = ( navigator.userAgent.match(/Android/gi) ? true : false ); if (this.isAndroid ) { $( document.documentElement ).addClass( 'is_android' ); } // is device a BlackBerry this.isBlackBerry = ( navigator.userAgent.match(/BlackBerry|PlayBook|BB10/gi) ? true : false ); if (this.isBlackBerry ) { $( document.documentElement ).addClass( 'is_blackberry' ); } // is device a Windows Phone this.isWinPhone = ( navigator.userAgent.match(/Windows\sPhone/gi) ? true : false ); if (this.isWinPhone ) { $( document.documentElement ).addClass( 'is_winphone' ); } // handle IE browsers (add version number) this.isIE = ($.browser.msie) ? true : false; this.isTrident = ( navigator.userAgent.match(/Trident/gi) ? true : false ); if ( this.isIE ) { $html.addClass( 'is_ie is_ie'+ this.getIEVersion() ); }; // handle WebKit browsers this.isChrome = ($.browser.chrome) ? true : false; this.isSafari = ($.browser.safari) ? true : false; this.isWebkit = ($.browser.webkit) ? true : false; if (this.isWebkit) { $html.addClass('is_webkit'); if (this.isChrome) { $html.addClass('is_chrome'); } if (this.isSafari) { var versionRegex = /Version\/(\d+)./g; var versionMatch = versionRegex.exec(navigator.userAgent); if ( versionMatch && versionMatch[1] ) { version = parseInt( versionMatch[1], 10 ); // don't bother user agent sniffing for newer safari versions - they don't require the same CSS fixes if ( version < 10 ) { $html.addClass('is_safari'); } } } }; // is device touch capable? this.isTouch = ('ontouchend' in document.documentElement) ? true : false; // is this a touch-capable Microsoft IE browser? this.isMsTouch = ( window.navigator.msMaxTouchPoints>0 && window.navigator.msPointerEnabled ) ? true : false; // does this browser have Flash installed? try { var flashObj = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); if ( flashObj ) { this.isFlash = true; $html.addClass('flash-enabled'); } else { $html.addClass('no-flash'); }; } catch(e) { if ( navigator.mimeTypes["application/x-shockwave-flash"] != undefined ) { this.isFlash = true; $html.addClass('flash-enabled'); } else { $html.addClass('no-flash'); }; }; // tell other apps whether the page is scrolling or not (this can mess stuff up sometimes), iOS only if (this.isTouch && this.isIOS) { // determine if a user is scrolling $( document ).on( 'touchstart touchmove touchend', $.proxy( this.handleIOSTouch, this ) ); $( window ).on( 'scroll', $.proxy( this.handleIOSScroll, this ) ); }; }, /* POST DOM-LOAD METHODS */ init: function() { // is device touch capable? if ( this.isTouch ) { $( document.documentElement ).addClass( 'touch-enabled' ); } else if (this.isMsTouch) { $( document.documentElement ).addClass( 'ms-touch' ); } else { $( document.documentElement ).addClass( 'no-touch' ); }; // touch screen devices need to keep track of state, sometimes if (this.isTouch) { // determine if orientation change has happened $( window ).on( 'orientationchange', $.proxy( this, 'handleOrientationChange' ) ); } else { // determine if window has changed size $( window ).on( 'resize', function( ev ) { // if we're already doing this, don't bother doing it again if (gNews.Common.resizeTimeout) clearTimeout(gNews.Common.resizeTimeout); // run method on resize gNews.Common.resizeTimeout = window.setTimeout( function() { gNews.Common.handleResize(); }, 200); }); }; }, /* METHODS FOR PAGE RESIZE */ // handle when users resize the page handleResize: function(ev) { for (var i in this.resizeCallbacks) { var callbackNode = this.resizeCallbacks[i].node; var callbackFunction = this.resizeCallbacks[i].callback; callbackNode.trigger( callbackFunction ); }; }, registerResizeCallback: function(node, callback) { //console.log('Common.registerResizeCallback()'); // make sure we don't already have one of these for (var i in this.resizeCallbacks) { if (this.resizeCallbacks[i].node==node && this.resizeCallbacks[i].callback==callback) return; }; // add callback var callbackObj = {}; callbackObj.node = node; callbackObj.callback = callback; this.resizeCallbacks.push( callbackObj ); }, removeResizeCallback: function(node, callback) { //console.log('Common.removeResizeCallback()'); for (var i in this.resizeCallbacks) { if (this.resizeCallbacks[i].node.get(0)==node.get(0) && this.resizeCallbacks[i].callback==callback) { this.resizeCallbacks.splice(i, 1); }; }; }, // do stuff you need to do after an orientation change handleOrientationChange: function(ev) { // at the very least, run the resize event this.handleResize(ev); }, /* METHODS FOR DETERMINING WHETHER PAGE IS ACTIVELY BEING SCROLLED / TOUCHED (iOS only) */ // status isScrolling: function() { // return status return this.status.isScrolling; }, handleIOSTouch: function( ev ) { // figure out what the page is doing this.setPosition( ev.type ); // set flags, where appropriate switch (ev.type) { case 'touchstart': this.status.isTouched = true; this.status.isScrolling = false; break; case 'touchmove': this.status.isScrolling = (this.scrollPos.delta.left!=0 || this.scrollPos.delta.top!=0) ? true : false; break; case 'touchend': this.status.isScrolling = (this.scrollPos.delta.left!=0 || this.scrollPos.delta.top!=0) ? true : false; this.status.isTouched = false; break; }; }, handleIOSScroll: function( ev ) { //console.log('Common.handleIOSScroll()'); // don't bother running if user hasn't scrolled if ( !this.status.isScrolling ) return; // figure out what the page is doing this.setPosition( ev.type ); // clear flags this.status.isTouched = false; this.status.isScrolling = false; // call any scroll callbacks we might have for (var i in this.scrollCallbacks) { var callbackNode = this.scrollCallbacks[i].node; var callbackFunction = this.scrollCallbacks[i].callback; callbackNode.trigger( callbackFunction ); }; }, setPosition: function( type ) { //console.log('Common.setPosition()'); // set current position this.scrollPos.current.left = window.pageXOffset; this.scrollPos.current.top = window.pageYOffset; // reset, or set deltas switch (type) { case 'touchstart': this.scrollPos.orig = {left:window.pageXOffset, top:window.pageYOffset}; this.scrollPos.delta = {left:0, top:0}; break; default: this.scrollPos.delta.left = this.scrollPos.orig.left - this.scrollPos.current.left; this.scrollPos.delta.top = this.scrollPos.orig.top - this.scrollPos.current.top; break; }; }, // note: this only works with iOS registerScrollCallback: function(node, callback) { //console.log('Common.registerScrollCallback()'); // make sure we don't already have one of these for (var i in this.scrollCallbacks) { if (this.scrollCallbacks[i].node==node && this.scrollCallbacks[i].callback==callback) return; }; // add callback var callbackObj = {}; callbackObj.node = node; callbackObj.callback = callback; this.scrollCallbacks.push( callbackObj ); }, removeScrollCallback: function(node, callback) { //console.log('Common.removeScrollCallback()'); for (var i in this.scrollCallbacks) { if (this.scrollCallbacks[i].node==node && this.scrollCallbacks[i].callback==callback) { this.scrollCallbacks.splice(i, 1); }; }; }, /* IE BROWSER DETECTION */ getIEVersion: function() { var version = -1; // Return value assumes failure. if ( this.isIE ) { var ua = navigator.userAgent; var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); if (re.exec(ua) != null) version = parseFloat( RegExp.$1 ); }; return version; }, canPlayMp4: function() { var canPlay = false; var v = document.createElement('video'); if(v.canPlayType && v.canPlayType('video/mp4').replace(/no/, '')) { canPlay = true; } return canPlay; }, iFrameAutoHeight: function( $obj ) { $obj.style.height = $obj.contentWindow.document.body.scrollHeight + 'px'; }, EOF: null }; }(); // init right away gNews.Common.preInit(); /* handles resizing embeds */ gNews.Common.EmbedResizer = function() { // PRIVATE var _embeds = []; var _isInit = false; function _init() { //console.log('********** EmbedResizer._init()'); // double-check to make sure we haven't done this yet if ( _isInit ) return; // add eventListener var $body = $('html body'); $body.on('RecentPostsResizeEvent', function() { _resize(); }); gNews.Common.registerResizeCallback( $body, 'RecentPostsResizeEvent' ); // don't do this more than once _isInit = true; }; function _resize() { //console.log('EmbedResizer._resize()'); // loop through array and resize each embed for (var i=0; i<_embeds.length; i++) { _resizeEmbed( _embeds[i] ); }; }; function _resizeEmbed( $embedObj ) { //console.log('EmbedResizer._resizeEmbed()'); // get current object height var newW = $embedObj.width(); // set width to 100%, and height to ratio of orig height $embedObj.css('height', ( newW * $embedObj.data('origEmbedHeight') / $embedObj.data('origEmbedWidth') ) +1 ); }; // PUBLIC return { // this is how you interact with this object -- simply add embed's you want here... add: function( $embedObj ) { //console.log('EmbedResizer.add()'); // don't add if the embed is already in here if ( $embedObj.data('embedResizerIsInit') ) return; // make sure this is initialized the first time you use it if ( !_isInit ) _init(); // add data to node, to save original height/width var origH = $embedObj.height(); var origW = $embedObj.width(); $embedObj.data('embedResizerIsInit', true); $embedObj.data('origEmbedHeight', origH); $embedObj.data('origEmbedWidth', origW); $embedObj.attr('height', ''); $embedObj.attr('width', ''); $embedObj.css( 'width', '100%'); // set width to 100% now, do this on a timer to give the 100% width change time to take effect window.setTimeout( function() { _resizeEmbed( $embedObj ); }, 10 ); // add embed to array _embeds.push( $embedObj ); }, EOF: null } }(); ; // This script is used to decode html entities // // Used in /includes/plugins/gnca-analytics-dash - need to check if this plugin is even used // Used in /includes/plugins/display-dashboard\display-dashboard.js (function( $ ){ var entityMapping = { '&': '&', '"': '\"', ''': '\'', '<': '<', '>': '>', '&nbdash;': '-', '‚': ',', ' ': ' ', '‘': '‘', '’': '’', '“': '“', '“': '“', '”': '”', '”': '”', '‘': '‘', '’': '’', ''': '’', '‚': ',', '–': '-' }; window.GNCA_String = { decodeHtmlEntity: function( str ) { var result = str; for ( var entity in entityMapping ) { result = result.replace( new RegExp(entity, 'g'), entityMapping[entity] ); } result = result.replace( /&#(\d+)*$/, '' ); return result; } } })( jQuery ); ; /** * Handles the form submission for the get in touch widget. Relies on an AJAX callback function (see includes/widgets/get-in-touch.php) */ (function($){ "use strict"; var submit = function(event, form){ event.preventDefault(); var $form = $(form); var $responseDiv = $form.next('.response'); var data = $form.serialize(); // Disable form fields while we're submitting. $form.find('input, textarea').attr("disabled", "disabled"); $responseDiv.html(' Sending your message').removeClass( 'error success warning' ); $.post(gncaGetInTouch.ajaxurl, data, function(response){ if (response.status == 'error') { $responseDiv.removeClass('warning success').addClass('error').html(response.status_msg); $form.find('input, textarea').removeAttr("disabled"); } if (response.status == 'warning') { $responseDiv.removeClass('error success').addClass('warning').html(response.status_msg); $form.find('input, textarea').removeAttr("disabled"); } if (response.status == 'success') { $responseDiv.removeClass('error warning').addClass('success').html(response.status_msg); $form.slideUp( ); } }, 'json'); }; $(document).ready(function(){ $('.gnca-get-in-touch-form').submit( 'submit', function(e){ submit( e, this ) } ); }); })(jQuery); ; function gnca_ajax( template , get_vars, callback ) { var params = JSON.stringify( get_vars ); return jQuery.get( '/gnca-ajax/' + template + '/' + encodeURI( params ) + '/', callback ); } JSON.stringify = JSON.stringify || function (obj) { var t = typeof (obj); if (t != "object" || obj === null) { // simple data type if (t == "string") obj = '"'+obj+'"'; return String(obj); } else { // recurse array or object var n, v, json = [], arr = (obj && obj.constructor == Array); for (n in obj) { v = obj[n]; t = typeof(v); if (t == "string") v = '"'+v+'"'; else if (t == "object" && v !== null) v = JSON.stringify(v); json.push((arr ? "" : '"' + n + '":') + String(v)); } return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}"); } };; // Handles Load More button logic on the video browse page // Used in /templates-redesign/dev/video/video-browse.php jQuery(function( $ ) { $(".load-more-video-btn").on('click', function( ev ) { // prevent default link from firign ev.preventDefault(); $(ev.currentTarget).blur(); // add loading class $(this).addClass('load-more-btn-loading'); // do your thing var url = $(this).attr("data-url"); var $container = $( "ul.video-browse-container, ul.video-browse-container-redesign" ); var last_id = ''; if ( $container.hasClass( 'video-browse-container-redesign' ) ) { last_id = $("ul.video-browse-container-redesign li:last").last().attr('data-post-id'); } else { last_id = $("ul.video-browse-container li:last a").last().attr('data-vid_id'); } var settings = { "video_url" : url, "video_lastid" : last_id } gnca_ajax( 'videozone' , settings , function( data ) { $("ul.video-browse-container, ul.video-browse-container-redesign").append(data); // Lazy load images. if ( 'undefined' !== typeof ( gn_hybrid ) && 'undefined' !== typeof ( gn_hybrid.LazyLoad ) ) { var $images = document.querySelectorAll( 'ul.video-browse-container-redesign img:not([src])' ); [].forEach.call( $images, function( $image ) { gn_hybrid.LazyLoad.startWatching( $image ); }); } $(".load-more-video-btn").removeClass('load-more-btn-loading'); if( MorePosts ) { MorePosts.afterCachedLoadMore(); } if( $("input.gnca_load_more_stop").length > 0 ) { $(".load-more-video-btn").css( "display", "none" ); } } ); return false; }); }); ; /* eslint-disable */ /** * Triggers a function once DOM is loaded, just like $(document).ready() */ var DOMReady = function( fn ) { if ( 'loading' !== document.readyState ) { fn(); } else { document.addEventListener( 'DOMContentLoaded', fn ); } }; ;