// Module pattern (function( $ ) { // Backwards compatibility if ( $.fn.on === undefined ) { $.fn.on = function( event, fn ) { this.bind( event, fn ); } } // Backwards compatibility if ( $.fn.off === undefined ) { $.fn.off = function( event, fn ) { return this.unbind( event, fn ); } } // The plugin wrapper $.fn.newsticker = function( options ) { var self = this; self.methods = $.fn.newsticker.methods; self.api = $.fn.newsticker.api; self.delegate = $.fn.newsticker.delegate; self.settings = $.extend( {}, $.fn.newsticker.defaults, options); // Method call return return this.each( function() { self.api( 'init', $(this) ); }); } // Default newsticker settings $.fn.newsticker.defaults = { style : 'scroll', showControls : true, tickerTitle : '', feedItems : 10, feeds : '', feedFormat : '%title% posted by %author%, %timeago%', noCache : false, twitter : '', twitterFormat : '%excerpt% posted on Twitter %timeago%', twitterCount : '', parseTwitterLinks : true, openLinksInNewWindow: false, facebook : '', facebookFormat : '%excerpt%... Posted on Facebook %timeago%', facebookCount : '', lastfm : '', lastfmFormat : '%title% listened to %timeago%', lastfmCount : '', tumblr : '', tumblrFormat : '%title% posted by %author%, %timeago%', tumblrCount : '', pinterest : '', pinterestFormat : '%excerpt% pinned %timeago%', pinterestCount : '', excerptLength : 100, sortBy : 'timestamp', reverseOrder : false, autoStart : true, timeAgoFormat : function( date ) { return $.fn.newsticker.methods.getTimeAgo( date ); }, dateFormat : function( date ) { return $.fn.newsticker.methods.getFormattedDate( date ); } } // An interface to call style methods $.fn.newsticker.delegate = function( name ) { var style_method = this.style[name], args = Array.prototype.slice.call(arguments, 1); if ( typeof( style_method ) === 'function' ) { return style_method.apply( this, args ); } return false; } // An interface to call general newsticker methods $.fn.newsticker.api = function( method ) { var api_method = this.methods[method], args = Array.prototype.slice.call(arguments, 1); if ( typeof( api_method ) === 'function' ) { return api_method.apply( this, args ); } return false; } // Global newsticker methods $.fn.newsticker.methods = { // Get unique newsticker ID getId : function() { var newDate = new Date; return newDate.getTime(); }, // Once-off initialisation routine init : function( element ) { // Validate newsticker style and load if valid if ( typeof( $.fn.newsticker.styles[ this.settings.style] ) === 'object' ) { this.style = $.fn.newsticker.styles[ this.settings.style ]; } else { console.log( 'ERROR: Invalid display style.' ); return; } // Update settings with defaults from newsticker style object this.settings = $.extend( this.delegate( 'settings' ), this.settings); // Start style initialization this.delegate( 'init' ); // Create dom object this.dom = {}; this.dom.list = element; // Compile feeds array. Check for 'sugar' feeds -- Twitter, Facebook page, Last.fm, Googe Plus this.api( 'getFeeds' ); if (this.feeds.length === 0 && this.settings.twitter.length === 0 && this.settings.facebook.length === 0 && this.settings.lastfm.length === 0 && this.settings.tumblr.length === 0 && this.settings.pinterest.length === 0) { // List items this.dom.items = this.dom.list.children('li'); // Startup this.api( 'startup' ); } }, // Startup. This is a sort of second init, called only when all the list items are loaded startup : function() { var self = this, dom = this.dom, settings = this.settings, list = dom.list; // Make dom modifications -- this is applied to all newsticker instances, regardless of style // Wrap the list inside a div, and insert a title before it list.wrap('
'); // Insert title if set if (settings.tickerTitle.length > 0) { $('

'+settings.tickerTitle+'

').insertBefore(list); } // Save both of the new dom elements dom.wrapper = list.parent(); dom.title = dom.wrapper.children('.newsticker_title'); // Add controls if set to true if (settings.showControls === true) { var pause_or_resume = settings.autoStart === false ? 'resume' : 'pause', controls; $('').insertAfter(list); controls = list.next('.newsticker_controls'); controls.children('.previous').on('click', function() { self.delegate( 'previous' ); }); controls.children('.pause').on('click', function() { self.delegate( 'pause' ); }); controls.children('.resume').on('click', function() { self.delegate( 'resume' ); }); controls.children('.next').on('click', function() { self.delegate( 'next' ); }); } // Save controls dom.controls = controls === undefined ? dom.wrapper.children('.newsticker_controls') : controls; // Pause animation on hover if set to true if (settings.pauseOnHover === true) { dom.items.on('mouseover', function(){ self.delegate( 'pause' ); }); dom.items.on('mouseout', function(){ self.delegate( 'resume' ); }); } // Handle window resize $(window).resize( function() { self.api( 'resize' ); }); // Allow styles to make their own DOM manipulations this.delegate( 'manipulateDom' ); // Loop through individual items this.delegate( 'itemLoop' ); // Start animation this.delegate( 'start' ); }, // Get collection of feeds to fetch getFeeds : function() { var self = this, settings = self.settings, feedItems = settings.feedItems, count, url; self.feeds = []; // Feeds if (settings.feeds.length > 0) { var _feeds = typeof (settings.feeds) === 'string' ? [settings.feeds] : settings.feeds; for (var i = 0, max = _feeds.length; i < max; i += 1) { var _feed = _feeds[i]; url = typeof (_feed) === 'string' ? _feed : _feed.url; count = _feed.hasOwnProperty('count') ? _feed.count : feedItems; self.feeds.push({ 'type' : 'feed', 'url' : document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + parseInt(count) + '&callback=?&q=' + encodeURIComponent( url ), 'count' : count }); } } // Twitter feed if (settings.twitter.length > 0) { count = settings.twitterCount > 0 ? settings.twitterCount : feedItems; self.feeds.push({ 'type' : 'twitter', 'url' : 'http://api.twitter.com/1/statuses/user_timeline.json?screen_name=' + encodeURIComponent( settings.twitter ) + '&callback=?&include_entities=1&count=' + parseInt(count), 'count' : count }); } // Last.fm feed if (settings.lastfm.length > 0) { count = settings.lastfmCount > 0 ? settings.lastfmCount : feedItems; url = 'http://ws.audioscrobbler.com/1.0/user/' + settings.lastfm + '/recenttracks.rss'; self.feeds.push({ 'type' : 'lastfm', 'url' : document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + parseInt(count) + '&callback=?&q=' + encodeURIComponent( url ), 'count' : count }); } // Tumblr feed if (settings.tumblr.length > 0) { count = settings.tumblrCount > 0 ? settings.tumblrCount : feedItems; url = 'http://' + settings.tumblr + '.tumblr.com/rss'; self.feeds.push({ 'type' : 'tumblr', 'url' : document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + parseInt(count) + '&callback=?&q=' + encodeURIComponent( url ), 'count' : count }); } // Pinterest feed if (settings.pinterest.length > 0) { count = settings.pinterestCount > 0 ? settings.pinterestCount : feedItems; url = 'http://pinterest.com/' + settings.pinterest + '/feed.rss'; self.feeds.push({ 'type' : 'pinterest', 'url' : document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + parseInt(count) + '&callback=?&q=' + encodeURIComponent( url ), 'count' : count }); } // Facebook page feed -- this should always be the last feed requested if (settings.facebook.length > 0) { var fb, date = new Date(); $.ajax({ url: document.location.protocol + '//graph.facebook.com/'+settings.facebook, // The timestamp is appended to prevent ID caching dataType: 'jsonp', success: function(json){ fb = json; }, error: function(xhr, status, error) { console.log( 'An error occurred while trying to fetch this profile from Facebook' ); fb = 'error'; }, complete: function() { if ( fb !== 'error' ) { self.api( 'completeFacebookRequest', fb ); } } }); } else { self.api( 'getFeedItems' ); } }, // Executed when request to Facebook for a Facebook page JSON object is completed completeFacebookRequest : function( fb ) { var settings = this.settings, count = settings.facebookCount > 0 ? settings.facebookCount : settings.feedItems, url = 'https://www.facebook.com/feeds/page.php?id=' + fb.id + '&format=rss20'; this.feeds.push({ 'type' : 'facebook', 'url' : document.location.protocol + '//ajax.googleapis.com/ajax/services/feed/load?v=1.0&num=' + parseInt(count) + '&callback=?&q=' + encodeURIComponent( url ), 'count' : count, 'data' : fb }); // Get list items from feed this.api( 'getFeedItems' ); }, // Add items from fetched RSS feed addItems : function( items, response, type ) { var entries = this.api( 'getItemsFromResponse', response, type ), max = entries.length, i = 0; for (i; i < max; i += 1) { var entry = entries[i]; entry.timestamp = this.api( 'getTimestamp', entry, type ); items.push( entry ); } return items; }, // Get entries from ajax call response getItemsFromResponse : function( response, type ) { switch (type) { case 'twitter': return response; break; default: return response.responseData.feed.entries; break; } }, // Get timestamp getTimestamp : function( item, type ) { switch (type) { case 'twitter': var v = item.created_at.split(' '); return new Date(Date.parse( v[1] + " " + v[2] + ", " +v[5] + " " + v[3] + " UTC")); break; default: return new Date( item.publishedDate ); break; } }, // Get feed items getFeedItems : function() { var self = this, items = [], feeds = this.feeds, complete = 0, feed, type, url; for (var i = 0, max = feeds.length; i < max; i += 1) { feed = feeds[i], type = feed.type, url = feed.url; // Prevent feed caching if ( self.settings.noCache === true ) { var timestamp = new Date().getTime(); url += '&' + timestamp; } $.ajax({ url: url, dataType: 'json', success: function(data) { if ( type === 'feed' && data.responseStatus !== 200) { console.log( 'Unable to load feed' ); return; } // Add items to collection self.api( 'addItems', items, data, type ); }, error: function(xhr, status, error) { console.log( 'An error occurred while trying to fetch feed from ' + feed.url + '. Status: ' + status ); }, complete: function() { // Make sure that every feed call has been completed before proceeding complete += 1; if (complete === max) { self.api( 'completeFeedItemsRequest', items, type ); } } }); } }, // Function to execute when feed items retrieval is complete completeFeedItemsRequest : function( items, type ) { var i, settings = this.settings, max = items.length > settings.feedItems ? settings.feedItems : items.length, html, list = this.dom.list, sort_by = settings.sortBy, reverse = settings.reverseOrder; // Sort items if (sort_by === 'random') { items = this.api( 'randomize', items ); } else { items.sort( this.api('sortBy', sort_by, reverse ) ); } for (i = 0; i < max; i += 1) { html = this.api( 'displayFeedItem', items[i], type ); list.append( html ); } this.dom.items = list.children('li'); this.api( 'startup' ); }, // Sort feed items sortBy : function(field, reverse) { var key = function(x) { return x[field]; }; return function( a, b ) { var A = key(a), B = key(b); return ( (A < B) ? -1 : (A > B) ? +1 : 0) * [-1,1][+!!reverse]; } }, // Randomly order feed items randomize : function( array ) { var tmp, current, top = array.length; if (top) while( --top ) { current = Math.floor( Math.random() * (top + 1) ); tmp = array[current]; array[current] = array[top]; array[top] = tmp; } return array; }, // Get feed item format getFormat : function( type ) { var settings = this.settings; switch (type) { case 'facebook': return settings.facebookFormat.length > 0 ? settings.facebookFormat : settings.feedFormat; break; case 'twitter': return settings.twitterFormat.length > 0 ? settings.twitterFormat : settings.feedFormat; break; case 'lastfm': return settings.lastfmFormat.length > 0 ? settings.lastfmFormat : settings.feedFormat; break; case 'tumblr': return settings.tumblrFormat.length > 0 ? settings.tumblrFormat : settings.feedFormat; break; case 'pinterest': return settings.pinterestFormat.length > 0 ? settings.pinterestFormat : settings.feedFormat; break; default: return settings.feedFormat; break; } }, // Display feed item displayFeedItem : function( item, type ) { var text = this.api( 'getFormat', type ), replace = ['author', 'excerpt', 'link', 'item_link', 'title', 'timeago', 'date'], replacement, key; for (var i = 0; i < replace.length; i += 1) { key = replace[i]; // Get replacement if (key === 'timeago') { replacement = this.settings.timeAgoFormat( item.timestamp ); } else if (key === 'date') { replacement = this.settings.dateFormat.apply( this, [ item.timestamp ] ); } else { replacement = this.api( 'getReplacement', item, key, type ); } // Do replacement switch (key) { case 'author': text = text.replace( /\%author\%/g, replacement ); break; case 'excerpt': text = text.replace( /\%excerpt\%/g, replacement ); break; case 'link': text = text.replace( /\%link\%/g, replacement ); break; case 'item_link': text = text.replace( /\%item_link\%/g, replacement ); break; case 'title': text = text.replace( /\%title\%/g, replacement ); break; case 'timeago': text = text.replace( /\%timeago\%/g, replacement ); break; case 'date': text = text.replace( /\%date\%/g, replacement); break; } } return '
  • ' + text + '
  • '; }, // Get entry key getReplacement : function( item, key, type ) { switch (key) { case 'author' : switch (type) { case 'twitter': return item.user.name; break; default: return item.author; break; } break; case 'excerpt' : switch (type) { case 'twitter': var text = this.api( 'getTwitterText', item, this.settings.parseTwitterLinks ); return text; break; case 'facebook': var t = $(item.content).text(); if (t === '') { return item.contentSnippet.length > this.settings.excerptLength ? item.contentSnippet.slice(0, this.settings.excerptLength) : item.contentSnippet; } else { return t; } break; case 'lastfm': return item.title; break; default: return item.contentSnippet.length > this.settings.excerptLength ? item.contentSnippet.slice(0, this.settings.excerptLength) : item.contentSnippet; break; } break; case 'link' : switch (type) { case 'twitter': return 'https://twitter.com/#!/'+ item.user.screen_name; break; case 'facebook': return 'http://facebook.com/' + this.settings.facebook; break; case 'pinterest': return 'http://pinterest.com/' + this.settings.pinterest + '/'; break; default: return item.link; break; } break; case 'item_link' : switch (type) { case 'twitter': return 'https://twitter.com/#!/'+ item.user.name + '/statuses/'+ item.id_str; break; case 'lastfm': return item.content; break; default: return item.link; break; } break; case 'title' : switch (type) { case 'twitter': return ''; break; default: return item.title; break; } break; } }, // Get Twitter text getTwitterText: function( item, parseLinks ) { var text = item.text, self = this, entities = [], links, entity; text = text.length > this.settings.excerptLength ? text.slice(0, this.settings.excerptLength) : text; if ( parseLinks === false ) { return text; } // Parse URLs in tweets jQuery.each( item.entities, function(name, links) { for ( var i = 0, max = links.length; i < max; i += 1 ) { entity = links[i]; entity.type = name; entity.start = entity.indices[0]; entities.push( entity ); } }); entities.sort( this.api('sortBy', 'start', false ) ); for ( var i = 0, max = entities.length; i < max; i += 1 ) { text = this.api( 'parseTwitterLink', text, entities[i] ); } return text; }, // Parse Twitter link parseTwitterLink: function( text, entity ) { var start = entity.start, end = entity.indices[1], url, text; if ( start < this.settings.excerptLength ) { url = this.api( 'getTwitterLink', entity ); text = text.slice(0, start) + url + text.slice(end); } return text; }, // Get Twitter link, depending on whether it's a URL, user mention or hashtag getTwitterLink: function( entity ) { var target = this.settings.openLinksInNewWindow === true ? 'target="_blank"' : ''; switch ( entity.type ) { case 'urls' : return '' + entity.display_url + ''; break; case 'user_mentions': return '@' + entity.screen_name + ''; break; case 'hashtags': return '#' + entity.text + ''; break; } }, // Default way to display time ago getTimeAgo: function( date ) { var now = new Date(), elapsed = now.getTime() - date.getTime(), // milliseconds elapsed day = 86400000, minute = 60000, hour = 3600000, units, timeago; if (elapsed < hour) { units = Math.ceil( elapsed / minute); timeago = units > 1 ? units + ' minutes ago' : units + ' minute ago'; } else if (elapsed < day) { units = Math.ceil( elapsed / hour); timeago = units > 1 ? units + ' hours ago' : units + ' hour ago'; } else { units = Math.ceil( elapsed / day); timeago = units > 1 ? units + ' days ago' : units + ' day ago'; } return timeago; }, // Default date format getFormattedDate: function( date ) { var date = new Date( date ), months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; return date.getDate() + ' ' + months[ date.getMonth() ]; // eg. 16 Aug }, // Get newsticker list width getListWidth : function() { if (this.settings.showControls) { return this.dom.controls.position().left - this.dom.title.outerWidth( true ); } else { return this.dom.wrapper.width() - this.dom.title.outerWidth( true ) - 1; } }, // Pause function to be executed whenever pause is initiated pause : function() { if (this.settings.showControls === true) { var self = this; this.dom.controls.children('.pause') .removeClass('pause') .addClass('resume') .off('click', function() { self.delegate( 'pause' ) }) .on('click', function() { self.delegate( 'resume' ) }); } }, // Resume function to be executed whenever resume is initiated resume : function() { if (this.settings.showControls === true) { var self = this; this.dom.controls.children('.resume') .removeClass('resume') .addClass('pause') .off('click', function() { self.delegate( 'resume' ); }) .on('click', function() { self.delegate( 'pause' ) }); } }, // Handle window resizing resize : function() { // First try delegating the resizing to the style's resize method. If none exists, handle it ourselves if (this.delegate( 'resize' ) === false) { this.dom.list.width( this.api( 'getListWidth' ) ); } } } // Newsticker styles collection $.fn.newsticker.styles = { // // Fading news ticker // fade : { // Loads style-specific settings settings : function() { return { 'fadeOutSpeed' : 'slow', 'fadeInSpeed' : 'slow', 'transitionSpeed' : 4000, 'pauseOnHover' : true }; }, // Manipulate individual list item manipulateItem : function(item, is_first) { var self = this; item.css({ 'position' : 'absolute', 'left' : 0, 'top' : 0 }); if (is_first) { item.addClass('display'); } else { item.hide(); } }, // Style-specific dom manipulations (see methods.manipulateDom for other dom manipulations) manipulateDom : function() { this.dom.wrapper.css({'width' : '100%'}); this.dom.title.css({'float' : 'left', 'margin' : 0}); this.dom.list.css({'float' : 'left', 'width' : this.api('getListWidth') + 'px', 'position' : 'relative', 'list-style' : 'none'}); }, // Loop through each individual list item itemLoop : function() { var is_first = true, self = this; this.dom.items.each( function() { self.delegate( 'manipulateItem', $(this), is_first); is_first = false; }); }, // Get adjacent item (either previous or next) adjacentItem : function( movement ) { var self = this; this.dom.items.each(function() { if ( $(this).hasClass('display') ) { self.delegate( 'itemTransform', $(this), movement ); } }) }, // Item transformation (called by nextItem and previousItem) // The item passed to this function is the one currently on display itemTransform : function( item, movement ) { // Fade out current item this.delegate( 'itemFadeOut', item ); if (movement === 'next') { if ( item.is('li:last-child') ) { this.delegate( 'itemFadeIn', this.dom.items.first() ); } else { this.delegate( 'itemFadeIn', item.next() ); } } else if (movement === 'previous') { if ( item.is('li:first-child') ) { this.delegate( 'itemFadeIn', this.dom.items.last() ); } else { this.delegate( 'itemFadeIn', item.prev() ); } } }, // Fade item in itemFadeIn : function( item ) { item.fadeIn( this.settings.fadeInSpeed, function() { item.addClass('display'); }); }, // Fade item out itemFadeOut : function( item ) { item.fadeOut( this.settings.fadeOutSpeed, function() { item.removeClass('display'); }); }, // Start fade action start : function() { var self = this; this.animationId = window.setInterval( function() { self.delegate( 'adjacentItem', 'next' ); }, this.settings.transitionSpeed) }, // Pause fade pause : function() { clearInterval( this.animationId ); this.api( 'pause' ); return this; }, // Resume fade resume : function() { this.delegate( 'start' ); this.api( 'resume' ); return this; }, // Next item next : function() { this.delegate( 'pause' ) .delegate( 'adjacentItem', 'next' ); return this; }, // Previous item previous : function() { this.delegate( 'pause' ) .delegate( 'adjacentItem', 'previous' ); return this; } }, // // Reveal news ticker // reveal : { // Initialization script init : function() { this.progress = { animate : true, original : {}, span : {}, text : '', html: '', length : 0, i: 0, j: 0, k: 0, elements: {}, nextHtml: {}, nextHtmlIndex: [], nextHtmlContent : '' }; }, // Custom settings for this display style settings : function() { return { 'letterRevealSpeed' : 70, 'transitionSpeed' : 2000, 'pauseOnHover' : false }; }, getLength: function() { var progress = this.progress; if (progress.length === 0) { progress.length = progress.text.length; } return progress.text.length; }, resetTicker: function( vars ) { var progress = this.progress; progress.span = vars.span; progress.elements = vars.elements; progress.text = vars.text; progress.html = vars.html; progress.length = 0; progress.j = 0; this.delegate( 'getNextHtml' ); progress.i = 0; }, getNextHtml: function() { var progress = this.progress; if ( progress.elements.length <= progress.j ) { progress.nextHtml = {}; progress.nextHtmlIndex = [-1]; } else { progress.nextHtml = progress.elements[progress.j]; progress.nextHtmlIndex = progress.nextHtml.indeces; progress.nextHtmlContent = $(progress.nextHtml).text(); progress.k = 0; } }, increment: function() { var self = this, progress = self.progress; if ( progress.nextHtmlIndex.start === progress.i ) { clearInterval( this.animationId ); this.animationId = window.setInterval( function() { self.delegate( 'incrementHtml' ); }, self.settings.letterRevealSpeed ); } else { progress.span.html( progress.text.slice(0, progress.i) ); progress.i += 1; } }, incrementHtml: function() { var self = this, progress = self.progress, text = progress.span.text, element = $( self.delegate( 'getOuterHtml', $(progress.nextHtml) ) ), reveal; progress.k += 1; reveal = progress.nextHtmlContent.slice(0, progress.k); element = $( self.delegate( 'getOuterHtml', element.children().text( reveal ) ) ); progress.span.html( progress.text.slice(0, progress.i) + element.html() ); if (progress.k === progress.nextHtmlIndex.length ) { progress.i += progress.nextHtmlIndex.element.html().length; clearInterval( this.animationId ); progress.j += 1; self.delegate( 'getNextHtml' ); this.animationId = window.setInterval( function() { self.delegate( 'revealLetter' ); }, self.settings.letterRevealSpeed ); } }, revealAll: function() { var progress = this.progress; progress.span.html( progress.html ); progress.i = this.delegate( 'getLength' ); }, manipulateDom : function() { var self = this, dom = self.dom, list = dom.list; dom.wrapper.css({'width' : '100%'}); dom.title.css({'float' : 'left', 'overflow' : 'hidden'}); list.css({'float' : 'left', 'position' : 'relative', 'list-style' : 'none', 'margin' : 0, 'padding' : 0}); list.width( this.api( 'getListWidth' ) + 'px' ); }, pause : function() { this.delegate( 'stopAnimation' ); this.delegate( 'revealAll' ); this.api( 'pause' ); return this; }, resume : function() { var self = this, progress = self.progress; progress.animate = true; this.animationId = window.setTimeout( function() { self.delegate( 'adjacentItem', 'next' ); }, 50 ); self.api( 'resume' ); return self; }, // Reveal adjacent item adjacent : function( side ) { this.delegate( 'stopAnimation' ); this.api( 'pause' ); this.delegate( 'adjacentItem', side ); this.delegate( 'revealAll' ); return this; }, // Reveal previous item previous : function() { return this.delegate( 'adjacent', 'previous' ); }, // Reveal next item next : function() { return this.delegate( 'adjacent', 'next' ); }, // Stop animation. Used by pause, previous and next methods. stopAnimation : function() { clearInterval(this.animationId); this.progress.animate = false; }, // Manipulate individual list item manipulateItem : function(item, is_first) { // Give each list item position and wrap text in span item.css({'position' : 'absolute', 'left' : 0, 'top' : 0, 'z-index' : 1}) .wrapInner(''); // Hide each span and make it a block element -- IE8 fix item.children('span').css({'opacity' : 0, 'display' : 'block', 'position' : 'relative', 'z-index' : 4}); if (is_first) { item.addClass('revealing'); } }, // Loop through items before animation begins itemLoop : function() { var is_first = true, self = this, dom = self.dom; dom.items.each( function() { self.delegate( 'manipulateItem', $(this), is_first ); is_first = false; }); }, // Prepare a new item for reveal prepareItem : function() { var self = this, item = self.dom.list.find('.revealing'), progress = self.progress, html, text; if (item.children('.revealing_text').length === 0) { item.append('') .children('.revealing_text').css({'opacity' : 1, 'position' : 'absolute', 'left' : 0, 'top' : 0}); } item.css({ 'z-index' : 2 }); html = item.children('.original_text'); text = self.delegate( 'decodeHtml', html.html() ); this.delegate( 'resetTicker', { span : item.children('.revealing_text'), text : text, html : html.html(), elements : this.delegate( 'getElements', html, text ) }); if (progress.animate === true) { self.delegate( 'animate' ); } }, // Return the links within a given list item getElements : function( html, text ) { var self = this, elements = html.children(); elements.each( function( i, element ) { elements[i].indeces = self.delegate( 'getElement', $(element), html.html() ); }); return elements; }, // Return start point and length of HTML element getElement : function( element, original_string ) { var el = this.delegate( 'getOuterHtml', element ), start = original_string.indexOf( el.html() ), length = element.text().length; return { 'start' : start, 'length' : length, 'element' : el }; }, // Decode HTML decodeHtml: function(string) { string = string.replace( /]*>([\S\s]*?)<\/script>/gmi, '' ); string = $("
    ").html(string).html(); return string; }, // Return outer HTML // @see http://stackoverflow.com/questions/2419749/get-selected-elements-outer-html getOuterHtml : function( element ) { return element.clone().wrap('

    ').parent(); }, // Animate animate: function() { var self = this; this.animationId = window.setInterval( function() { self.delegate( 'revealLetter' ); }, self.settings.letterRevealSpeed ); }, // Reveal the next letter revealLetter : function() { var self = this, progress = self.progress; self.delegate( 'increment' ); if ( progress.i > self.delegate( 'getLength' ) ) { clearInterval(this.animationId); this.animationId = window.setTimeout( function() { self.delegate( 'adjacentItem', 'next' ); }, self.settings.transitionSpeed ); } }, // Adjacent item adjacentItem : function( side ) { var dom = this.dom, current = dom.list.find('.revealing').removeClass('revealing'), adjacent = this.delegate( side === 'previous' ? 'getPreviousItem' : 'getNextItem', dom, current ); adjacent.addClass('revealing'); current .css({ 'z-index' : 1 }) .children('.revealing_text').text(''); this.delegate( 'prepareItem' ); }, // Start revealing the next item getNextItem : function(dom, current) { return ( current.is('li:last-child') ) ? dom.list.find('li:first-child') : current.next(); }, // Start revealing the previous item getPreviousItem : function(dom, current) { return ( current.is('li:first-child') ) ? dom.list.find('li:last-child') : current.prev(); }, // Start the animation process start : function() { if (this.settings.autoStart === true) { this.delegate( 'prepareItem' ); } } }, // // Scrolling news ticker // scroll : { // Initialization script init : function() { this.progress = { autoScroll : this.settings.autoStart, left : 0, boundary : 0, last : {}, current : {}, animationId : 0 }; }, // Manages the scrolling action resetLeft : function() { this.progress.left = parseInt( this.dom.list.css('left') ); }, // Loads style-specific settings settings : function() { return { 'scrollSpeed' : 50, 'slideSpeed' : 1000, 'slideEasing' : 'swing', 'pauseOnHover' : true }; }, // Style-specific dom manipulations manipulateDom : function(is_secondary) { var dom = this.dom, is_secondary = typeof( is_secondary ) === 'undefined' ? false : is_secondary; if (is_secondary === false) { dom.wrapper.css({'width' : '10000px', 'position' : 'relative'}); dom.title.css({'float' : 'left'}); dom.list.wrap('

    ') .css({'position' : 'absolute', 'left' : 10}); dom.scroller = this.dom.wrapper.children('.newsticker_scroller'); } else if (is_secondary === true) { dom.wrapper.css({'width' : '100%'}); dom.scroller.css({'position' : 'absolute', 'height' : '100%', 'overflow' : 'hidden', 'width' : this.api( 'getListWidth' )+'px', 'left' : dom.title.outerWidth(true)+'px'}); } }, // Individual news item dom manipulations // @return integer. Next X coordinate. manipulateItem : function( item, x ) { var width = item.css({'float' : 'left'}).outerWidth(true); item.css({'position' : 'absolute', 'display' : 'inline', 'left' : x+'px', 'width' : width+'px'}); x += width; return x; }, // Set up style-specific item modifications itemLoop : function() { var self = this, x = 0, progress = this.progress, dom = this.dom; dom.items.each( function() { x = self.delegate( 'manipulateItem', $(this), x ); }); progress.current = dom.items.first(); progress.last = dom.items.last(); progress.boundary = dom.items.length === 1 ? progress.current.width() : progress.current.next().position().left; self.delegate( 'manipulateDom', true ); }, // Start -- if autoScroll is off, this does nothing start : function() { if (this.progress.autoScroll === true) { this.delegate( 'animate' ); } }, // Sets off the scrolling animation animate : function() { var self = this, progress = self.progress; if (progress.autoScroll === false) { progress.autoScroll = true; } progress.animationId = window.setInterval( function() { self.delegate( 'doAnimation' ); }, self.settings.scrollSpeed); }, // Do animation doAnimation : function() { var progress = this.progress; if (progress.left + progress.boundary < 0) { this.delegate( 'nextItem' ); } progress.left -= 1; this.dom.list.css({ 'left' : progress.left+'px' }); }, // Pause scroll pause : function() { var progress = this.progress; progress.autoScroll = false; clearInterval(progress.animationId); this.api( 'pause' ); return this; }, // Resume scrolling resume : function() { this.delegate( 'animate' ); this.api( 'resume' ); return this; }, // Next item -- fired by next control button next : function() { var self = this, progress = self.progress, settings = self.settings, left = progress.boundary < 0 ? progress.left - progress.current.width() : '-' + progress.boundary; self.delegate( 'pause' ); self.dom.list.animate({'left' : left + 'px'}, settings.slideSpeed, settings.slideEasing, function() { self.delegate( 'resetLeft' ); self.delegate( 'nextItem' ); }); }, // Window resize resize : function() { this.dom.scroller.width( this.api( 'getListWidth' )); }, // Previous item -- fired by previous control button previous : function() { var self = this, progress = self.progress, settings = self.settings, previous, left; self.delegate( 'pause' ); previous = self.delegate( 'getPrevious' ); previous.css({'left' : progress.current.position().left - parseInt( previous.width() )}); left = previous.position().left < 0 ? (0 - previous.position().left) : '-' + previous.position().left; self.dom.list.animate({'left' : left + 'px'}, settings.slideSpeed, settings.slideEasing, function() { self.delegate( 'resetLeft' ); self.delegate( 'previousItem', previous ); }); }, // Switch to next item nextItem : function() { var progress = this.progress, dom = this.dom, last = dom.items.last(), first = dom.items.first(), new_x = progress.last.outerWidth() + progress.last.position().left, current = progress.current; current.css({'left' : new_x+'px'}); if ( current.next().length === 0 ) { progress.current = first; progress.last = last; } else { progress.current = current.next(); progress.last = progress.current.prev(); } // Set next boundary if ( progress.current.next().length === 0 ) { progress.boundary = first.position().left; } else { progress.boundary = progress.current.next().position().left; } }, // Get previous item getPrevious : function() { var progress = this.progress; if (progress.current.prev().length === 0) { return this.dom.items.last(); } return progress.current.prev(); }, // Switch to previous item previousItem : function( previous ) { var progress = this.progress, dom = this.dom; progress.current = previous; if ( progress.current.prev().length === 0 ) { progress.last = dom.items.last(); } else { progress.last = progress.current.prev(); } // Set next boundary if ( progress.current.next().length === 0) { progress.boundary = dom.items.first().position().left; } else { progress.boundary = progress.current.next().position().left; } } } } })( jQuery );