Create a gist now

Instantly share code, notes, and snippets.

@draeton /lounge.js Secret
Last active Dec 16, 2015

OnStar » Experience OnStar code sample
/*!
* Brand Lounge - Experience OnStar Plugin
*
* Copyright (c) 2011 Digitas
* All Rights Reserved.
*
*/
/**
* Create the brand lounge
*
* Dependencies: jquery.ba-bbq.js, jquery.tmpl.js, page.lounge-nf.css, cufon-yui.js, shadedborder.js
* http://admin.brightcove.com/js/BrightcoveExperiences.js ,
* http://admin.brightcove.com/js/APIModules_all.js
*
* @example $('#lounge').lounge();
* @desc Initializes the brand lounge using all default values.
*
* @param {Object} options An object literal with key/value pairs for lounge settings
*
* @option {String} templates The jQuery template file, relative path from doclib
* @option {Object} params The JSON data selection object
* @option {String} doclib The root directory for the document library
*
* @name $.fn.lounge
* @author Matthew Cobbs <matthew.cobbs@digitas.com>
*/
/*global jQuery, Liferay, Cufon, brightcove, APIModules, RUZEE */
(function ($, window, Liferay, Cufon, brightcove, APIModules, RUZEE) {
/**
* This module holds all of the brand lounge methods
* for use in the lounge namespace
*/
var methods = (function () {
var _$lounge = null, // global brand lounge div reference
_$grid = null, // global grid div reference
_$back = null, // the back button
_$thumbs = null, // the content thumbnails
_$features = null, // the content features
_$allsquares = null, // the grid array squares
_gridArray = [], // a temporary array of grid squares
_currentFeature = '', // current feature id string
_backClass = '', // need to save for restoring class for tracking
_isIe = Liferay.Browser.isIe(),
_borders = {
dt: RUZEE.ShadedBorder.create({corner:4}),
dtInner: RUZEE.ShadedBorder.create({corner:4}),
dd: RUZEE.ShadedBorder.create({corner:4}),
ddInner: RUZEE.ShadedBorder.create({corner:4,border:3})
},
// default settings
_defaults = {
templates: '', // jquery template file
jsondir: '', // json file location
params: {
brand: 'onstar', // selected brand string
lang: 'en_us', // selected language string
id: '', // deep linking id string
v: '' // video id
},
doclib: '', // location of the doclibrary
imglib: '' // location of the imglibrary
},
// lounge settings object
_settings;
/**
* initialize the lounge
* @param {Object} options
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function init (options) {
// merge options with defaults
_settings = $.extend(true, {}, _defaults, options);
return this.each(function () {
var $this = $(this);
// $this is the brand lounge
_$lounge = $this;
// load the content
$this.bind('templatesLoaded', function () {
$this.lounge('getLoungeContent');
});
$this.lounge('getLoungeTemplates');
// bind the hashchange event to get lounge content
$(window).bind('hashchange', function (e) {
$this.lounge('getLoungeContent', e);
});
});
}
/**
* get the query parameters for the content json based on the hash in the url
* @param {Object} e The hashchange event object
* @return {Object} The query paramaters object
* @namespace $.fn.lounge
*/
function getQueryParameters (e) {
var state = $.bbq.getState(),
i;
// some defaults
state.brand = state.brand || _settings.params.brand;
state.lang = state.lang || _settings.params.lang;
// get param values from state
for (i in _settings.params) {
if (_settings.params.hasOwnProperty(i)) {
_settings.params[i] = state.hasOwnProperty(i) ? state[i] : '';
}
}
return _settings.params;
}
/**
* create the grid of 60 squares
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function createGrid () {
return this.each(function () {
var $this = $(this),
$gridsquarewrap = $('div.grid-square-wrap'),
i;
$('img.grid-square', $gridsquarewrap).css({
width: '8px',
height: '8px',
top: '30px',
left: '30px',
opacity: 0
});
// remove from #lounge and add 59 squares (for 60 total)
$this.remove();
for (i = 0; i < 59; i++) {
$gridsquarewrap.clone().appendTo($this);
}
// reattach and show (still hidden because img opacity == 0)
$this.appendTo(_$lounge).show();
// set all squares
_$allsquares = $('img.grid-square');
});
}
/**
* start the grid hover animations
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function bindGridHandlers () {
return _isIe ? this : this.each(function () {
var $this = $(this),
shrink = {
width: '64px',
height: '64px',
top: '2px',
left: '2px',
opacity: 0.05
},
grow = {
width: '68px',
height: '68px',
top: '0px',
left: '0px',
opacity: 0.2
},
hover = function (e) {
var $this = $(this);
if (e.type === 'mouseover') {
$this.animate(shrink, 200);
} else if (e.type === 'mouseout') {
$this.animate(grow, 400);
}
};
$this.delegate('img.grid-square', 'hover', hover);
});
}
/**
* stop the grid hover animations
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function unbindGridHandlers () {
return _isIe ? this : this.each(function () {
$(this).undelegate('img.grid-square', 'hover');
});
}
/**
* hide grid squares in random order
* @param {Array} squares An array of squares or nothing
* @param {Function} callback Function on complete
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function transitionGridIn (squares, callback) {
return this.each(function () {
var $squares = squares ? $(squares) : _$allsquares,
l = $squares.length,
grow = {
width: '68px',
height: '68px',
top: '0px',
left: '0px',
opacity: 0.2
},
duration = 400;
// fade in fixed length
$squares.animate(grow, duration, 'swing', function () {
if (--l === 0 && callback) {
callback();
}
});
});
}
/**
* show grid squares in random order
* @param {Array} squares An array of squares or nothing
* @param {Function} callback Function on complete
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function transitionGridOut (squares, callback) {
return this.each(function () {
var $squares = squares ? $(squares) : _$allsquares,
l = $squares.length,
shrink = {
width: '8px',
height: '8px',
top: '30px',
left: '30px',
opacity: 0
},
duration = 250;
// fade out fixed length
$squares.animate(shrink, duration += 5, 'swing', function () {
if (--l === 0 && callback) {
callback();
}
});
});
}
/**
* return an array of grid squares based on position and size
* @return {Array}
* @namespace $.fn.lounge
*/
function getGridArray (width, height, row, col) {
var $squares = $('img.grid-square'),
rows = [],
result = [],
idx = (row - 1) * 10 + (col - 1),
i, j, k, l;
rows.push(idx);
for (i = 0; i < height - 1; i++) {
idx += 10;
rows.push(idx);
}
for (j = 0, l = rows.length; j < l; j++) {
for (k = 0; k < width; k++) {
result.push( $squares[rows[j]+k] );
}
}
return result;
}
/**
* routes to a brand lounge feature
* @param {String} id The feature id
* @param {String} v Brightcove video id, if in query string
* @namespace $.fn.lounge
* @private
*/
function gotoFeature (id, v) {
var $feature = $('#lounge-dd-'+id),
layout = $feature.data('layout'), // layout properties
$inner = $feature.find('.inner'),
$close = $feature.find('.close'),
backTracking;
// check if current feature
if (id === _currentFeature) {
// if a video id was passed, trigger the video handler
if (v) {
$('#video-'+v).trigger('click');
}
} else {
_currentFeature = id;
// set back tracking class
backTracking = $.trim( $close.attr('class').replace('close', '') );
_$back.attr('class', _backClass); // reset back class
_$back.addClass(backTracking);
// stop the slideshows
_$lounge.lounge('stopSlideshows');
// set the grid array based on feature layout
_gridArray = _$grid.lounge('getGridArray', layout.w, layout.h, layout.row, layout.col);
// fade out the grid squares first
_$grid.lounge('transitionGridOut', _gridArray, function () {
// show the dd (content)
_$thumbs.fadeOut('fast', function () {
if (_$thumbs.filter(":animated").length === 1) {
_$back.fadeIn('fast');
$feature.fadeIn('fast', function () {
// create video player if necessary
$(window).trigger('createVideoPlayers');
// rounded corners
if ( !$feature.data('cornered') ) {
_borders.dd.render( $feature );
_borders.ddInner.render( $feature.find('.inner') );
$feature.data('cornered', true);
}
$inner.animate({
top: '-6px',
left: '6px'
}, 200);
});
}
});
});
}
return true;
}
/**
* routes to thumbnails view
* @namespace $.fn.lounge
* @private
*/
function gotoThumbnails () {
if (_currentFeature) {
_currentFeature = "";
var $inners = _$features.find('.inner');
// close out video players
$(window).trigger('closeVideoPlayers');
_$back.fadeOut('fast');
_$features.fadeOut('fast', function () {
// reset the .inner div position
$inners.css({
top: '0px',
left: '0px'
});
});
// begin slideshow aimations
_$lounge.lounge('startSlideshows');
// fade in the grid elements here
_$lounge.lounge('transitionGridIn', _gridArray, function () {
_$thumbs.fadeIn('fast');
});
}
return true;
}
/**
* bind the click and hover handlers for the content blocks
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function bindLoungeHandlers () {
return this.each(function () {
var $this = $(this);
// click handlers for displaying and hiding content divs
$this.delegate('dt', 'click', function () {
var $thumb = $(this),
id = $thumb.attr('id'),
linkid = id.replace('lounge-dt-', '');
// set the hash id
$.bbq.pushState({id: linkid}, 2);
});
$this.delegate('div.back, div.close', 'click', function () {
// set the hash id
$.bbq.pushState({}, 2);
});
// hover effects
$this.delegate('dt', 'hover', function (e) {
var $this = $(this),
$inner = $this.find('.inner');
if (e.type === 'mouseover') {
$inner.stop().animate({
top: '-6px',
left: '6px'
}, 200);
} else if (e.type === 'mouseout') {
$inner.stop().animate({
top: '0px',
left: '0px'
}, 200);
}
});
// begin slideshow aimations
$this.lounge('startSlideshows');
});
}
/**
* unbind the lounge handlers
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function unbindLoungeHandlers () {
return this.each(function () {
var $this = $(this);
$this.undelegate('dt');
$this.undelegate('div.back');
});
}
/**
* start up any slideshows
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function startSlideshows () {
return this.each(function () {
var $this = $(this),
$slideshows = $('.slideshow', $this);
$slideshows.each(function () {
var $this = $(this),
$slides = $('.slide', $this),
interval = $this.data('interval'),
$now, $next;
// don't set a new interval if one exists
if (interval) {
return;
}
// hide all but the first slide
$slides.show().slice(1).hide();
// set an interval to loop through slides
interval = setInterval(function () {
$now = $slides.filter(':visible');
$next = $now.nextAll('.slide').eq(0);
if (!$next.length) {
$next = $slides.eq(0);
}
$now.fadeOut();
$next.fadeIn();
}, 1800);
// save the interval id on the slideshow
$this.data('interval', interval);
});
});
}
/**
* stop any slideshows
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function stopSlideshows () {
return this.each(function () {
var $this = $(this),
$slideshows = $('.slideshow', $this);
$slideshows.each(function () {
var $this = $(this),
interval = $this.data('interval');
// if there is an interval on the slideshow, clear it
if (interval) {
clearInterval(interval);
$this.data('interval', null);
}
});
});
}
/**
* get the lounge templates and append to the body
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function getLoungeTemplates () {
return this.each(function () {
var $this = $(this);
$.get(_settings.templates, function (data) {
$('body').append(data);
$this.trigger('templatesLoaded');
});
});
}
/**
* load the lounge content from a json file, and parse with jQuery template
* @param {Object} e The hashchange event object
* @return {Object} jQuery object
* @namespace $.fn.lounge
*/
function getLoungeContent (e) {
var json, params = getQueryParameters(e);
// skip loading if we're already here
if (_$lounge.data('brand') === params.brand && _$lounge.data('lang') === params.lang) {
// if there is a deep-linking id, trigger handler
if (params.id) {
gotoFeature(params.id, params.v); // pass id and, if exists, video id
} else {
gotoThumbnails();
}
return this;
}
// set the json url
json = _settings.jsondir + params.brand + '-' + params.lang + '.json';
return this.each(function () {
// get default json
$.ajax({
url: json,
dataType: 'json',
success: function (json) {
// set lounge data
_$lounge.data('brand', params.brand);
_$lounge.data('lang', params.lang);
// back to home, if after initial load
if (_$features) {
$.bbq.pushState({}, 2);
}
if (json) {
// switch up bg if there is one in the file
if (json.background) {
_$lounge.css('background-image', "url('" + json.background.src + "')");
}
// apply the jquery template to the rest
_$lounge.lounge('unbindLoungeHandlers');
_$lounge.html( $("#loungeTemplate").tmpl(json) );
_$lounge.lounge('bindLoungeHandlers');
// set collections
_$thumbs = $('dt', _$lounge);
_$features = $('dd', _$lounge).each(function () {
// parse the class for layout properties
var $feature = $(this),
layout = $feature.attr('class');
$feature.data('layout', {
w: layout.match(/w\-(\d+)/)[1],
h: layout.match(/h\-(\d+)/)[1],
row: layout.match(/row\-(\d+)/)[1],
col: layout.match(/col\-(\d+)/)[1]
});
});
// set up videos queue
$(window).trigger('setupVideosQueue');
// the background (display) grid
_$grid = $('div.grid', _$lounge);
_$grid.lounge('createGrid').lounge('bindGridHandlers').lounge('transitionGridIn');
// the content div, which rests over the grid
$('.lounge-content', _$lounge).fadeIn('fast');
// the back button
_$back = $('div.back', _$lounge);
_backClass = _$back.attr('class');
// run the cufon replacement on new content
if (Cufon.replaceAll) {
Cufon.replaceAll();
}
// rounded corners on thumbs
_borders.dt.render( _$thumbs );
_borders.dtInner.render( _$thumbs.find('.inner') );
// if there is a deep-linking id, go to feature
if (params.id) {
gotoFeature(params.id, params.v);
}
}
},
error: function (xhr, status, e) {
// back to defaults
$.bbq.pushState({}, 2);
}
});
});
}
// public interface
return {
'init': init,
'bindGridHandlers': bindGridHandlers,
'bindLoungeHandlers': bindLoungeHandlers,
'createGrid': createGrid,
'getGridArray': getGridArray,
'getLoungeContent': getLoungeContent,
'getLoungeTemplates': getLoungeTemplates,
'startSlideshows': startSlideshows,
'stopSlideshows': stopSlideshows,
'transitionGridIn': transitionGridIn,
'transitionGridOut': transitionGridOut,
'unbindGridHandlers': unbindGridHandlers,
'unbindLoungeHandlers': unbindLoungeHandlers
};
}());
/**
* brand lounge plugin controller function; determines which plugin method
* to call; if blank or an options object is passed in, calls init
* @param {String} method The method name
* @return {*} The result of the method
* @namespace $.fn
*/
function lounge (method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method==='object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.lounge' );
return this;
}
}
// extend the jQuery prototype
$.extend($.fn, {'lounge': lounge});
}(jQuery, this, Liferay, Cufon, brightcove, APIModules, RUZEE));
/*!
* VideoPlayer - Brightcove API Wrapper
*
* Copyright (c) 2011 Digitas
* All Rights Reserved.
*/
/**
* Create and manipulate brightcove video players using HTML controls
*
* Dependencies: http://admin.brightcove.com/js/BrightcoveExperiences.js ,
* http://admin.brightcove.com/js/APIModules_all.js
*
* @author Matthew Cobbs <matthew.cobbs@digitas.com>
*/
/*global jQuery, brightcove, APIModules */
(function ($, window, brightcove, APIModules) {
var document = window.document,
_videosQueue = {}, // a hash for video player stuff
_isIE = Liferay.Browser.isIe(),
console = window.console || {log: function () {}};
/**
* constructor function for video players
* @param {String} playerID The brightcove player id
* @private
*/
function VideoPlayer(playerID) {
// brightcove stuff
this.id = playerID;
this.player = null;
this.controls = null;
this.scrollIndex = 0;
this.scrollMaxIndex = 0;
// DOM stuff
this.$player = $('.videos-'+this.id);
this.$videos = this.$player.parents('.videos').eq(0);
this.$note = this.$videos.find('.videos-note');
this.$subtitle = this.$videos.find('.videos-subtitle').eq(0);
this.subtitleHtml = this.$subtitle.html();
this.$thumbsDiv = this.$videos.find('.videos-thumbs');
this.$thumbs = this.$videos.find('.videos-thumb');
this.$prev = this.$videos.find('.videos-prev');
this.$next = this.$videos.find('.videos-next');
// check
this.hasThumbs = this.$thumbs.length > 0;
// get started
this.init();
}
/**
* init
*/
VideoPlayer.prototype.init = function () {
if (this.hasThumbs) {
this.scrollMaxIndex = this.$thumbs.length - 3;
this.$thumbsDiv.css({'left': '0px', 'display': 'block'});
this.bindHandlers();
this.prevNextCheck();
}
// fix this, there is no history
var state = $.bbq.getState();
if (state.data && state.data.v) {
this.playVideo(state.data.v);
} else {
this.playVideo();
}
};
/**
* event listeners
*/
VideoPlayer.prototype.bindHandlers = function () {
var self = this; // inside event handlers
if (this.hasThumbs) {
this.$thumbs.unbind('click').click(function () {
var id = $(this).attr('id').replace('video-', '');
self.playVideo(id);
return true;
});
this.$prev.unbind('click').click(function () {
if (self.scrollIndex <= 0) {
return;
}
self.scrollTo( --self.scrollIndex );
});
this.$next.unbind('click').click(function () {
if (self.scrollIndex >= self.scrollMaxIndex) {
return;
}
self.scrollTo( ++self.scrollIndex );
});
}
};
/**
* unbind event listeners when removing brightcove players
*/
VideoPlayer.prototype.unbindHandlers = function () {
if (this.hasThumbs) {
this.$thumbs.unbind('click');
this.$prev.unbind('click');
this.$next.unbind('click');
}
};
/**
* set controls from brightcove API
*
* Throws an error if controls fail to load
*/
VideoPlayer.prototype.setControls = function () {
this.player = brightcove.getExperience(this.id);
if (this.player.type === 'flash') {
this.controls = this.player.getModule(APIModules.VIDEO_PLAYER);
} else { // html, create a shim
var self = this,
$newPlayer = _videosQueue[self.id].clone.clone();
this.controls = {
'loadVideo': function (id) {
brightcove.removeExperience(self.id);
$newPlayer.append('<param name="@videoPlayer" value="' + id + '" />');
self.$player.prepend($newPlayer);
_videosQueue[self.id].skipInit = true;
brightcove.createExperience($newPlayer[0], $newPlayer[0].parentNode, true);
},
'pause': function () {
brightcove.removeExperience(self.id);
self.$player.prepend($newPlayer);
}
};
}
if (!this.controls) {
throw new Error('Failed to load controls from Brightcove API');
}
return true; // success
};
/**
* play the video with the matching id
* @param {String} videoID The brightcove video id
*/
VideoPlayer.prototype.playVideo = function (videoID) {
var $thumb, subtitle, index;
if (this.hasThumbs) {
if (videoID) {
$thumb = this.$thumbs.filter('#video-'+videoID);
index = this.$thumbs.index($thumb);
} else {
// get the first video id
$thumb = this.$thumbs.eq(0);
index = 0;
videoID = ($thumb.attr('id') || "").replace('video-', '');
}
}
try {
if (this.setControls() && videoID) {
this.controls.loadVideo(videoID);
if (this.hasThumbs) {
// switch in the subtitle and add playing class
subtitle = $thumb.find('.videos-subtitle').html();
this.$thumbs.removeClass('playing');
this.$note.hide();
this.$subtitle.html(subtitle);
$thumb.addClass('playing');
// scroll to index of thumb, or max if less
if (index < this.scrollIndex || index > this.scrollIndex + 2) {
this.scrollIndex = index;
if (this.scrollIndex > this.scrollMaxIndex) {
this.scrollIndex = this.scrollMaxIndex;
}
this.scrollTo(this.scrollIndex);
}
}
}
} catch (ex) {
console.log(ex);
}
};
/**
* scroll thumbs to an index
*/
VideoPlayer.prototype.scrollTo = function (index) {
if (this.hasThumbs) {
if (_isIE) {
this.$thumbsDiv.css({
'left': (-index * 158) + 'px'
});
} else {
this.$thumbsDiv.stop().animate({
'left': (-index * 158) + 'px'
}, 100);
}
this.prevNextCheck();
}
};
/**
* check whether prev and next arrows should be disabled
*/
VideoPlayer.prototype.prevNextCheck = function () {
if (this.hasThumbs) {
if (this.scrollIndex === 0) {
this.$prev.addClass('videos-prev-disabled');
} else {
this.$prev.removeClass('videos-prev-disabled');
}
if (this.scrollIndex === this.scrollMaxIndex) {
this.$next.addClass('videos-next-disabled');
} else {
this.$next.removeClass('videos-next-disabled');
}
this.$prev.show();
this.$next.show();
}
};
/**
* close out video player and reset player state
*/
VideoPlayer.prototype.close = function () {
try {
if (this.setControls()) {
// stop playing video, unbind playlist handlers
this.controls.stop();
this.unbindHandlers();
// remove experience, replace with original html
brightcove.removeExperience(this.id);
this.$player.append(_videosQueue[this.id].clone.clone());
// reset display back to starting content
this.$thumbs.removeClass('playing');
this.$subtitle.html(this.subtitleHtml);
this.$note.show();
Cufon.replaceAll();
}
} catch (ex) {
console.log(ex);
}
};
/**
* add all players on page to videos queue
* @namespace VideoPlayer
* @private
*/
function setupVideosQueue() {
$('.BrightcoveExperience').each(function () {
var $this = $(this),
playerID = $this.attr('id');
// test html5
//$this.append('<param name="forceHTML5" value="true" />');
// add secure parameter to videos if https
if (document.location.protocol === 'https:') {
//$this.append('<param name="secureConnections" value="true" />');
}
_videosQueue[playerID] = {clone: $this.clone()};
});
}
$(window).bind('setupVideosQueue', setupVideosQueue);
/**
* create brightcove video player
* @param {String} playerID The brightcove player id
* @namespace VideoPlayer
* @private
*/
function setupVideoPlayer (playerID) {
if (_videosQueue[playerID] && _videosQueue[playerID].skipInit) {
// skipping init for html5
_videosQueue[playerID].skipInit = false;
} else {
if (_videosQueue[playerID].player) {
_videosQueue[playerID].player.init();
} else {
_videosQueue[playerID].player = new VideoPlayer(playerID);
}
}
}
// brightcove on template loaded handler
window.onTemplateLoaded = function (id) {
setupVideoPlayer(id);
};
/**
* pause and reset all brightcove videos, before closing feature
* @namespace VideoPlayer
* @private
*/
function closeVideoPlayers () {
for (var i in _videosQueue) {
if (_videosQueue.hasOwnProperty(i) && _videosQueue[i].player) {
if (_videosQueue[i].player.$player.is(':visible')) {
_videosQueue[i].player.close();
}
}
}
}
$(window).bind('closeVideoPlayers', closeVideoPlayers);
/**
* create all visible video players
* @namespace VideoPlayer
* @private
*/
function createVideoPlayers() {
$('.BrightcoveExperience').filter(':visible').each(function () {
var player = this,
playerContainer = this.parentNode;
brightcove.createExperience(player, playerContainer, true);
});
}
$(window).bind('createVideoPlayers', createVideoPlayers);
}(jQuery, this, brightcove, APIModules));
/**
* Miscellaneous helpers
*
* Dependencies: cufon-yui.js
*
* @author Matthew Cobbs <matthew.cobbs@digitas.com>
*/
/*global Cufon */
(function (window, Cufon) {
// Cufon
Cufon.replaceAll = function () {
Cufon.replace('.gothamMedium', {fontFamily: 'Gotham-Medium'});
Cufon.replace('.gothamBold', {fontFamily: 'Gotham-Bold'});
Cufon.replace('.gothamBook', {fontFamily: 'Gotham-Book'});
};
Cufon.replaceAll();
}(this, Cufon));
/**
* jQuery.browser.mobile (http://detectmobilebrowser.com/)
*
* jQuery.browser.mobile will be true if the browser is a mobile device
*
**/
(function(a){jQuery.browser.mobile=/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|meego.+mobile|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))})(navigator.userAgent||navigator.vendor||window.opera);
// ## Onstar Tracking - Omniture Module
//
// Copyright (c) 2011 Digitas
// All Rights Reserved.
//
// Allows DOM event tracking through Omniture using JSON objects
// The typical approach is to pass a tracking object with IDs for each
// specific event type and action to track.
//
// *Dependencies*: [Omniture](http://www.omniture.com), [jQuery 1.4.2+](http://www.jquery.com), [Liferay](http://www.liferay.com)
//
// @name OnstarTracking
// @author Matthew Cobbs <matthew.cobbs@digitas.com>
// @modifiedBy Jair Reina <jair.reina@boszdigital.com>
//
/*global jQuery, s_account, s_gi, Liferay*/
(function ($, window, Liferay) {
var document = window.document, // set reference to window document
_s = null; // omniture tracking object
// ## Constructor and Prototype Setup
//
// Set up a private `OnstarTracking` constructor to be used to create
// the global `OnstarTracking` instance. This is followed by the
// prototype, which holds all of the shared methods and variables
// between each instance. The prototype is created using an
// immediately-invoked function expression that returns an object
// holding the publicly accessible member methods and properties.
//
// @param {Object} [options] Optional instance settings object
// @return {OnstarTracking}
// @constructor
var OnstarTracking = function (options) {
if (!(this instanceof OnstarTracking)) {
return new OnstarTracking(options); // make sure this is a new instance
} else {
this.lang = null; // language val for prop4
this.tracking = {}; // tracking data grouped into hashes by event type
this.events = {}; // a hash of all event types the document is listening for
this.settings = {}; // module settings
this.trackFilter = null; // OnstarTracking select filter
this.trackRegex = null; // OnstarTracking regex
return OnstarTracking.prototype.init.call(this, arguments);
}
};
OnstarTracking.prototype = (function () {
// *Declare Private Variables*
//
// These private variables are inaccessible to external code and will
// persist between different `OnstarTracking` instances
var _defaults = { // module defaults
defaultTrack: 'link', // default track type
defaultEvent: 'click', // default event type
defaultLang: 'us_en', // default langauge
trackClass: 'otrack', // OnstarTracking document class name
namespace: '.otrack', // event namespace
clearProps: "prop1 prop2 prop3 prop4 prop5 prop6 prop7 prop8 prop9 prop10 prop11 prop12 prop13 prop14 prop15 prop16 prop17 prop18 prop19 prop25 eVar22 events" // properties to clear before tacking events
};
// ###getLanguage
//
// *Get the language setting from Liferay*
//
// @return {String}
// @namespace OnstarTracking
// @private
function getLanguage () {
var liferayLang, lang, liferayToOmniture;
liferayToOmniture = {
'en_us': 'us_en',
'es_us': 'us_sp',
'en_ca': 'ca_en',
'fr_ca': 'ca_fr'
};
liferayLang = Liferay && Liferay.ThemeDisplay.getLanguageId().toLowerCase();
lang = liferayToOmniture[liferayLang] || this.settings.defaultLang;
return lang;
}
// ###getDeviceType
//
// *Gets the device type where the page is being rendered it could be:
// MOBILE
// DESKTOP
//
// @return {String}
// @deviceType Mobile Device Type
// @private
function getDeviceType () {
var deviceType = "DESKTOP";
if($.browser.mobile)
deviceType = "MOBILE";
return deviceType;
}
// `_tags` and `_tagsRegExp` are used to set dynamic properties at
// run time. Any of these tags can be used in any tracking object
// property
var _tagsRegExp = /{\w+\}/g;
var _propertyRegExp = /\jQuery:|\|/g;
var _idRegExp = /jQuery:(.*?)(\||$)/g;
// if somebody needs a custom tag, it should be defined here following the same pattern:
// "{tagName}: functionThatReturnsTheValueForThisTag"
var _tags = {
"{lang}": getLanguage,
"{deviceType}": getDeviceType,
};
// ###getTag
//
// *Get the value of a dynamic tag from the `_tags` object, using
// `val` as the index for lookup*
//
// @retrun {String}
// @namespace OnstarTracking
// @private
function getTagValue(val) {
var result = "",
fn;
if (_tags.hasOwnProperty(val)) {
fn = _tags[val];
result = fn();
}
return result;
}
// ###getLinkTrackVars
//
// *Get a list of link tracking props from `props` keys.*
// This is used to set the `linkTrackVars` property before making a
// call to Omniture
//
// @param {Object} props The properties object
// @return {String}
// @namespace OnstarTracking
// @private
function getLinkTrackVars (props) {
var linkVars = [], i;
for (i in props) {
if (props.hasOwnProperty(i)) {
linkVars.push(i);
}
}
return linkVars.join(',');
}
// ###clearTracking
//
// *Clear tracking variables.* Txhis is used to clear out the value of
// properties before each call to Omniture
//
// @namespace OnstarTracking
// @private
function clearTracking () {
var i, l, prop;
for (i = 0, l = this.settings.clearProps.length; i < l; i++) {
prop = this.settings.clearProps[i];
_s[prop] = "";
}
}
// ###trackEvent
//
// *Trigger omniture tracking event.* This function is used internally
// to pass a set of properties to track to Omniture
//
// @param {Object} props The event properties
// @param {Event} [e] Optional event object
// @namespace OnstarTracking
// @private
function trackEvent (props, e) {
if (!_s) {
_s = s_gi(s_account);
}
$.proxy(clearTracking, this)();
$.extend(_s, props);
if (props._track === 'page') {
_s.t();
} else {
_s.tl(true, 'o', 'link tracking');
}
if (window.console) {
console.log(props._track, props._event, props);
}
}
// ###addDocumentListener
//
// *Bind a new event type handler to the document.*
// This is called after the tracking action objects have been added
// to OnstarTracking. If the `type` has not been passed yet, a new
// delegated handler is attached to the document to watch for events
// of that type
//
// @param {String} type The event type name
// @namespace OnstarTracking
// @private
function addDocumentListener (type) {
var self = this;
if (!this.events.hasOwnProperty(type)) {
$(document).delegate(this.trackFilter, type + this.settings.namespace, function (e) {
// Match the tracking class
var match = this.className.match(self.trackRegex);
if (match) {
self.track(type, match[0], e);
}
});
// Add event type to hash to prevent adding another handler
// to the document
this.events[type] = true;
}
}
// ##Return the public interface
return {
// ###init
//
// *Sets or resets module settings using an options hash, sets the
// current language, and initializes the Omniture object.*
// This method can be used externally to update the internal options
// used by this module. For example, if there are additional properties
// to clear, you may pass an updated `clearProps` property
//
// @param {Object} options An object with module settings overrides
// @namespace OnstarTracking
init: function (options) {
this.settings = $.extend({}, _defaults, options || {});
if (typeof this.settings.clearProps === "string") {
this.settings.clearProps = this.settings.clearProps.split(" ");
}
this.lang = $.proxy(getLanguage, this)();
this.trackFilter = "." + this.settings.trackClass;
this.trackRegex = new RegExp(this.settings.trackClass + "\\-\\d+");
},
// ###add
//
// *Add a hash of tracking events to be monitored.*
// The keys of the object should be the tracking classes
// used in the document
//
// @param {Object} o The hash of tracking events
// @namespace OnstarTracking
// @example
// OnstarTracking.add({
// "otrack-00006": {
// "pageName": "ONSTAR | NEW SERVICES MODULE | CHEVROLET",
// "prop1": "NEW SERVICES MODULE",
// "prop2": "CHEVROLET",
// "prop3": "NEW SERVICES MODULE | CHEVROLET",
// "prop4": "<<language>>",
// "prop16": "NEW SERVICES MODULE | CHEVROLET | PAGE LOAD",
// "prop25": "ONSTAR",
// "_track": "page",
// "_event": "load"
// },
// "otrack-00010": {
// "prop1": "NEW SERVICES MODULE",
// "prop2": "CHEVROLET",
// "prop3": "NEW SERVICES MODULE | CHEVROLET",
// "prop4": "<<language>>",
// "prop16": "NEW SERVICES MODULE | CHEVROLET | EXPERIENCE ON",
// "getTagValue5": "ONSTAR"
// });
//
// This adds two actions to the `OnstarTracking` hash. The first object is tracked
// automatically on page load, because `_event = "load"`. The `_track` property is
// set to `"page"` to make this an `s.t()` call. The second object is tracked as a
// `"click"` action, because the `_event` default is `"click"`. Because there is no
// `_track` property on the second object, the default of an `s.tl()` call is used.
//
// Tracking objects can contain any of the properties used in Omniture tracking
// calls. `prop4` will be overwritten with the current language by this module.
// `linkTrackVars` is automatically compiled by the module, so it is not necessary
// to pass it in.
add : function (o) {
var i, props;
for (i in o) {
if (o.hasOwnProperty(i)) {
props = o[i]; // get the tracking event
props.prop4 = this.lang; // set language
props.linkTrackVars = getLinkTrackVars(props);
props._track = props._track || this.settings.defaultTrack; // set the track type
props._event = props._event || this.settings.defaultEvent; // set the event type
// Add tracking event to hash
this.tracking[props._event] = this.tracking[props._event] || {};
this.tracking[props._event][i] = props;
if (props._event === "load" && (document.getElementById(i))) {
// Immediately track load actions
this.track(props._event, i);
props._tracked = true;
} else {
// Otherwise, add listener
$.proxy(addDocumentListener, this)(props._event);
}
}
}
},
// ###remove
//
// *Remove tracking events.* If you pass no arguments, this method
// removes all tracking events from the module. If you pass only
// `eventType`, this method removes all tracking events with that
// type. If you pass both `eventType` and `eventID`, this method
// removes only that specific tracking event.
//
// @param {String} [eventType] The optional type of event (e.g. click)
// @param {String} [eventID] The optional id of the tracking event
// @namespace OnstarTracking
//
// @example OnstarTracking.remove('click', 'otrack-98765');
// @example OnstarTracking.remove('click');
// @example OnstarTracking.remove();
remove: function (eventType, eventID) {
var hash;
if (typeof eventType === "undefined" && typeof eventID === "undefined") {
this.tracking = {};
this.events = {};
$(document).unbind(this.trackFilter, this.settings.namespace);
} else if (typeof eventType !== "undefined" && typeof eventID === "undefined") {
delete this.tracking[eventType];
delete this.events[eventType];
$(document).undelegate(this.trackFilter, eventType + this.settings.namespace);
} else if (typeof eventType !== "undefined" && typeof eventID !== "undefined") {
hash = this.tracking[eventType];
if (hash) {
delete hash[eventID];
}
}
},
// ###track
//
// *Track an event by pulling the properties by `eventID`
// out of the `_tracking[eventType]` hash.*
// This method can also be used externally to track events
// without DOM interaction. This will trigger tracking on events
// already added to the `OnstarTracking` module
//
// @param {String} eventType The type of event (e.g. click)
// @param {String} eventID The id of the tracking event
// @param {Event} [e] Optional event object
// @namespace OnstarTracking
//
// @example OnstarTracking.track('click', 'otrack-98765');
track: function (eventType, eventID, e) {
var hash, props, i, target;
hash = this.tracking[eventType];
// Gets the element that has been clicked
if (typeof e != "undefined") {
target = (e.currentTarget) ? e.currentTarget : e.srcElement;
}
if (hash) {
props = hash[eventID];
if (props) {
// Deep copy of 'props'
var parsedProps = jQuery.extend(true, {}, props);
// replace dynamic tags
for (i in props) {
var propVal = props[i];
// props[i] can either be a string or a function
if (typeof propVal == "string") {
// If it has "[", it means we're asking for a property on the element
if (propVal.indexOf("[") != -1) {
parsedProps[i] = propVal.replace(_propertyRegExp, function (val) {
return target[val];
});
} else {
// If there's a jQuery:, it means we're asking for the contents of some element
// using a jQuery selector
if (propVal.indexOf("jQuery:") != -1) {
parsedProps[i] = propVal.replace(_idRegExp, function (val) {
val = val.replace("jQuery:", "").replace("|", "");
var text = $(val).text();
if (text == "") {
text = $(val).val();
}
return text;
});
} else {
parsedProps[i] = props[i].replace(_tagsRegExp, function (val) {
return getTagValue(val);
});
}
}
} else {
parsedProps[i] = (props[i](target)).toUpperCase();
}
}
$.proxy(trackEvent, this)(parsedProps, e);
}
}
}
};
})();
// Initialize the module instance and return to the window
window.OnstarTracking = new OnstarTracking();
// Set internal Omniture module reference
$(document).ready(function () {
_s = s_gi(s_account);
});
})(jQuery, this, Liferay);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment