/**
* Copyright 2006 - 2012 Eric D. Hough (http://ehough.com)
*
* This file is part of TubePress (http://tubepress.org) and is released
* under the General Public License (GPL) version 3
*
*/
/*global jQuery, getTubePressBaseUrl, alert, YT, Froogaloop, console */
/*jslint devel: true, browser: true, sloppy: false, white: true, maxerr: 50, indent: 4 */
/**
* Logger!
*/
var TubePressLogger = (function () {
'use strict';
/**
* Is the log on?
*/
var isLoggingRequested = location.search.indexOf('tubepress_debug=true') !== -1,
windowConsole = window.console,
isLoggingAvailable = typeof windowConsole !== 'undefined',
/**
* The log is on if it's been enabled and requested.
*/
isLoggingOn = function () {
return isLoggingRequested && isLoggingAvailable;
},
/**
* Output a message.
*/
log = function (msg) {
windowConsole.log(msg);
},
dir = function (obj) {
windowConsole.dir(obj);
};
return {
on : isLoggingOn,
log : log,
dir : dir
};
}());
/**
* Various Ajax utilities.
*/
var TubePressAjax = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variable declarations aide in compression. */
jquery = jQuery,
getText = 'GET',
functionText = 'function',
/**
* Similar to jQuery's "load" but tolerates non-200 status codes.
* https://github.com/jquery/jquery/blob/master/src/ajax.js#L168.
*/
load = function (url, targetDiv, selector, preLoadFunction, postLoadFunction) {
var completeCallback = function (res) {
var responseText = res.responseText,
html = selector ? jquery('
').append(responseText).find(selector) : responseText;
jquery(targetDiv).html(html);
/* did the user supply a post-load function? */
if (typeof postLoadFunction === functionText) {
postLoadFunction();
}
};
/** did the user supply a pre-load function? */
if (typeof preLoadFunction === functionText) {
preLoadFunction();
}
jquery.ajax({
url : url,
type : getText,
dataType : 'html',
complete : completeCallback
});
},
/**
* Similar to jQuery's "get" but ignores response code.
*/
get = function (url, data, success, dataType) {
jquery.ajax({
url : url,
type : getText,
data : data,
dataType : dataType,
complete : success
});
},
/**
* Fade to "white".
*/
applyLoadingStyle = function (targetDiv) {
jquery(targetDiv).fadeTo(0, 0.3);
},
/**
* Fade back to full opacity.
*/
removeLoadingStyle = function (targetDiv) {
jquery(targetDiv).fadeTo(0, 1);
},
/**
* Calls "load", but does some additional styling on the target element while it's processing.
*/
loadAndStyle = function (url, targetDiv, selector, preLoadFunction, postLoadFunction) {
applyLoadingStyle(targetDiv);
/** one way or another, we're removing the loading style when we're done... */
var post = function () {
removeLoadingStyle(targetDiv);
};
/** ... but maybe we want to do something else too */
if (typeof postLoadFunction === functionText) {
post = function () {
removeLoadingStyle(targetDiv);
postLoadFunction();
};
}
/** do the load. do it! */
load(url, targetDiv, selector, preLoadFunction, post);
};
return {
load : load,
applyLoadingStyle : applyLoadingStyle,
removeLoadingStyle : removeLoadingStyle,
loadAndStyle : loadAndStyle,
get : get
};
}());
/**
* Handles dynamic loading of CSS. To be removed...
*/
var TubePressCss = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
/*
* Dynamically load CSS into the DOM.
*/
var load = function (path) {
var fileref = document.createElement('link');
fileref.setAttribute('rel', 'stylesheet');
fileref.setAttribute('type', 'text/css');
fileref.setAttribute('href', path);
document.getElementsByTagName('head')[0].appendChild(fileref);
};
return {
load : load
};
}());
/**
* Events that TubePress fires.
*/
var TubePressEvents = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
return {
/** A gallery's primary video has changed. */
GALLERY_VIDEO_CHANGE : 'tubepressGalleryVideoChange',
/** Playback of a video started. */
PLAYBACK_STARTED : 'tubepressPlaybackStarted',
/** Playback of a video stopped. */
PLAYBACK_STOPPED : 'tubepressPlaybackStopped',
/** Playback of a video is buffering. */
PLAYBACK_BUFFERING : 'tubepressPlaybackBuffering',
/** Playback of a video is paused. */
PLAYBACK_PAUSED : 'tubepressPlaybackPaused',
/** Playback of a video has errored out. */
PLAYBACK_ERROR : 'tubepressPlaybackError',
/** An embedded video has been loaded. */
EMBEDDED_LOAD : 'tubepressEmbeddedLoad',
/** A new set of thumbnails has entered the DOM. */
NEW_THUMBS_LOADED : 'tubepressNewThumbnailsLoaded',
/** An entirely new gallery has entered the DOM. */
NEW_GALLERY_LOADED : 'tubepressNewGalleryLoaded',
/** A TubePress player is being invoked. */
PLAYER_INVOKE : 'tubepressPlayerInvoke',
/** A TubePress player is being populated. */
PLAYER_POPULATE : 'tubepressPlayerPopulate'
};
}());
var TubePressGallery = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var galleries = {},
docElement = jQuery(document),
cssLoaded = {},
events = TubePressEvents,
/**
* Does the gallery use Ajax pagination?
*/
isAjaxPagination = function (galleryId) {
return galleries[galleryId].ajaxPagination;
},
/**
* Does the gallery use auto-next?
*/
isAutoNext = function (galleryId) {
return galleries[galleryId].autoNext;
},
/**
* Does the gallery use fluid thumbs?
*/
isFluidThumbs = function (galleryId) {
return galleries[galleryId].fluidThumbs;
},
/**
* What's the embedded height for the video player of this gallery?
*/
getEmbeddedHeight = function (galleryId) {
return galleries[galleryId].embeddedHeight;
},
/**
* What's the embedded width for the video player of this gallery?
*/
getEmbeddedWidth = function (galleryId) {
return galleries[galleryId].embeddedWidth;
},
/**
* What's the gallery's player location name?
*/
getPlayerLocationName = function (galleryId) {
return galleries[galleryId].playerLocationName;
},
/**
* What's the sequence of videos for this gallery?
*/
getSequence = function (galleryId) {
return galleries[galleryId].sequence;
},
/**
* What's the shortcode for this gallery?
*/
getShortcode = function (galleryId) {
return galleries[galleryId].shortcode;
},
/**
* Deprecated. To be removed...
*/
getThemeCss = function (galleryId) {
return galleries[galleryId].themeCSS;
},
/**
* Performs gallery initialization on jQuery(document).ready().
*/
docReadyInit = function (galleryId, params) {
/** Save the params. */
galleries[galleryId] = params;
/** Deprecated theme handling stuff. To be removed... */
var theme = decodeURIComponent(getThemeCss(galleryId));
if (theme !== '' && cssLoaded[theme] !== true) {
TubePressCss.load(getTubePressBaseUrl() + theme);
cssLoaded[theme] = true;
}
/** Trigger an event after we've booted. */
docElement.trigger(events.NEW_GALLERY_LOADED, galleryId);
},
/**
* Register a TubePress gallery.
*/
init = function (galleryId, params) {
docElement.ready(function () {
docReadyInit(galleryId, params);
});
};
return {
isAjaxPagination : isAjaxPagination,
isAutoNext : isAutoNext,
isFluidThumbs : isFluidThumbs,
getEmbeddedHeight : getEmbeddedHeight,
getEmbeddedWidth : getEmbeddedWidth,
getPlayerLocationName : getPlayerLocationName,
getSequence : getSequence,
getShortcode : getShortcode,
init : init
};
}());
/**
* Handles player-related functionality (popup, Shadowbox, etc)
*/
var TubePressPlayers = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variable declarations help compression. */
jquery = jQuery,
documentElement = jquery(document),
tubepressGallery = TubePressGallery,
tubepressEvents = TubePressEvents,
decodeUri = decodeURIComponent,
/** Keep track of the players we've loaded. */
loadedPlayers = {},
/**
* Find the player required for a gallery and load the JS.
*/
bootPlayer = function (e, galleryId) {
var playerName = tubepressGallery.getPlayerLocationName(galleryId),
path = getTubePressBaseUrl() + '/sys/ui/static/players/' + playerName + '/' + playerName + '.js';
/** don't load a player twice... */
if (loadedPlayers[playerName] !== true) {
loadedPlayers[playerName] = true;
jquery.getScript(path);
}
},
/**
* Does this player require population by TubePress?
*/
requiresPopulation = function (playerName) {
return playerName !== 'vimeo' && playerName !== 'youtube' && playerName !== 'solo' && playerName !== 'static';
},
/**
* Load up a TubePress player with the given video ID.
*/
invokePlayer = function (e, galleryId, videoId) {
var playerName = tubepressGallery.getPlayerLocationName(galleryId),
height = tubepressGallery.getEmbeddedHeight(galleryId),
width = tubepressGallery.getEmbeddedWidth(galleryId),
shortcode = tubepressGallery.getShortcode(galleryId),
callback = function (data) {
var result = jquery.parseJSON(data.responseText),
title = decodeUri(result.title),
html = decodeUri(result.html);
documentElement.trigger(tubepressEvents.PLAYER_POPULATE + playerName, [ title, html, height, width, videoId, galleryId ]);
},
dataToSend = {
tubepress_video : videoId,
tubepress_shortcode : shortcode
},
url = getTubePressBaseUrl() + '/sys/scripts/ajax/playerHtml.php';
/** Announce we're gonna invoke the player... */
documentElement.trigger(tubepressEvents.PLAYER_INVOKE + playerName, [ videoId, galleryId, width, height ]);
/** If this player requires population, go fetch the HTML for it. */
if (requiresPopulation(playerName)) {
/* ... and fetch the HTML for it */
TubePressAjax.get(url, dataToSend, callback, 'json');
}
};
/** When we see a new gallery... */
documentElement.bind(tubepressEvents.NEW_GALLERY_LOADED, bootPlayer);
/** When a user clicks a thumbnail... */
documentElement.bind(tubepressEvents.GALLERY_VIDEO_CHANGE, invokePlayer);
}());
/**
* Sequencing support for TubePress.
*/
var TubePressSequencer = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variable declarations aide in compression. */
tubepressGallery = TubePressGallery,
jquery = jQuery,
docElement = jquery(document),
events = TubePressEvents,
logger = TubePressLogger,
isCurrentlyPlayingVideo = 'isCurrentlyPlayingVideo',
currentVideoId = 'currentVideoId',
/** Galleries that we track. */
galleries = {},
/**
* Searches through our galleries for one that matches the given.
*/
findGalleryThatMatchesTest = function (test) {
var galleryId;
for (galleryId in galleries) {
if (galleries.hasOwnProperty(galleryId)) {
if (test(galleryId)) {
return galleryId;
}
}
}
return undefined;
},
/**
* Find the gallery with the given video loaded up.
*/
findGalleryIdWithVideoIdAsCurrent = function (videoId) {
var test = function (galleryId) {
var gall = galleries[galleryId];
return gall[currentVideoId] === videoId;
};
return findGalleryThatMatchesTest(test);
},
/**
* Find the gallery that is currently playing the given video.
*/
findGalleryIdCurrentlyPlayingVideo = function (videoId) {
var test = function (galleryId) {
var gall = galleries[galleryId],
isCurrentlyPlaying = gall[currentVideoId] === videoId && gall[isCurrentlyPlayingVideo];
if (isCurrentlyPlaying) {
return galleryId;
}
};
return findGalleryThatMatchesTest(test);
},
/**
* When a new gallery is loaded...
*/
onNewGalleryLoaded = function (e, galleryId) {
var gall = {},
sequence = tubepressGallery.getSequence(galleryId);
gall[isCurrentlyPlayingVideo] = false;
/**
* If this gallery has a sequence,
* save the first video as the "current" video.
*/
if (sequence) {
gall[currentVideoId] = sequence[0];
}
/** Record it. */
galleries[galleryId] = gall;
if (logger.on()) {
logger.log('Gallery ' + galleryId + ' loaded');
}
},
/**
* Set a video as "current" for a gallery.
*/
changeToVideo = function (galleryId, videoId) {
/** Save it as current. */
galleries[galleryId][currentVideoId] = videoId;
/** Announce the change. */
docElement.trigger(events.GALLERY_VIDEO_CHANGE, [ galleryId, videoId] );
},
/**
* Go to the next video in the gallery.
*/
next = function (galleryId) {
/** Get the gallery's sequence. This is an array of video ids. */
var sequence = tubepressGallery.getSequence(galleryId),
vidId = galleries[galleryId][currentVideoId],
index = jquery.inArray(vidId, sequence),
i = index,
lastIndex = sequence ? sequence.length - 1 : index;
/** Sorry, we don't know anything about this video id, or we've reached the end of the gallery. */
if (index === -1 || index === lastIndex) {
return;
}
/** Start the next video in line. */
changeToVideo(galleryId, sequence[i + 1]);
},
/** Play the previous video in the gallery. */
prev = function (galleryId) {
/** Get the gallery's sequence. This is an array of video ids. */
var sequence = tubepressGallery.getSequence(galleryId),
vidId = galleries[galleryId][currentVideoId],
index = jquery.inArray(vidId, sequence),
i = index;
/** Sorry, we don't know anything about this video id, or we're at the start of the gallery. */
if (index === -1 || index === 0) {
return;
}
/** Start the previous video in line. */
changeToVideo(galleryId, sequence[i + 1]);
},
/**
* A video on the page has started.
*/
onPlaybackStarted = function (e, videoId) {
var matchingGalleryId = findGalleryIdWithVideoIdAsCurrent(videoId);
/**
* If we don't have a gallery assigned to this video, we don't really care.
*/
if (! matchingGalleryId) {
return;
}
/**
* Record the video as playing.
*/
galleries[matchingGalleryId][isCurrentlyPlayingVideo] = true;
galleries[matchingGalleryId][currentVideoId] = videoId;
if (logger.on()) {
logger.log('Playback of ' + videoId + ' started for gallery ' + matchingGalleryId);
}
},
/**
* A video on the page has stopped.
*/
onPlaybackStopped = function (e, videoId) {
var matchingGalleryId = findGalleryIdCurrentlyPlayingVideo(videoId);
/**
* If we don't have a gallery assigned to this video, we don't really care.
*/
if (! matchingGalleryId) {
return;
}
/**
* Record the video as not playing.
*/
galleries[matchingGalleryId][isCurrentlyPlayingVideo] = false;
if (logger.on()) {
logger.log('Playback of ' + videoId + ' stopped for gallery ' + matchingGalleryId);
}
if (tubepressGallery.isAutoNext(matchingGalleryId) && tubepressGallery.getSequence(matchingGalleryId)) {
if (logger.on()) {
logger.log('Auto-starting next for gallery ' + matchingGalleryId);
}
/** Go to the next one! */
next(matchingGalleryId);
}
};
/** We want to keep track of all galleries that are loaded. */
docElement.bind(events.NEW_GALLERY_LOADED, onNewGalleryLoaded);
/** We would like to be notified when a video starts */
docElement.bind(events.PLAYBACK_STARTED, onPlaybackStarted);
/** We would like to be notified when a video ends, in the case of auto-next. */
docElement.bind(events.PLAYBACK_STOPPED, onPlaybackStopped);
return {
changeToVideo : changeToVideo,
next : next,
prev : prev
};
}());
/**
* Handles basic thumbnail tasks.
*/
var TubePressThumbs = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variables aide in compression. */
jquery = jQuery,
events = TubePressEvents,
docElement = jquery(document),
math = Math,
/** Events we're interested in. */
eventsToBindTo = events.NEW_THUMBS_LOADED + ' ' + events.NEW_GALLERY_LOADED,
/**
* Get the jQuery selector where the thumbs live.
*/
//TODO: this is hard-coded - need to get rid of that.
getThumbAreaSelector = function (galleryId) {
return "#tubepress_gallery_" + galleryId + "_thumbnail_area";
},
/**
* Get the jQuery reference to where the thumbnails live.
*/
getThumbArea = function (galleryId) {
return jquery(getThumbAreaSelector(galleryId));
},
/**
* Parse the gallery ID from the "rel" attribute.
*/
getGalleryIdFromRelSplit = function (relSplit) {
return relSplit[3];
},
/**
* Parse the video ID from the "rel" attribute.
*/
getVideoIdFromIdAttr = function (id) {
var end = id.lastIndexOf('_');
return id.substring(16, end);
},
/**
* Get the thumbnail width.
*/
getThumbWidth = function (galleryId) {
return getThumbArea(galleryId).find('img:first').width();
},
/**
* Click listener callback.
*/
clickListener = function () {
var rel_split = jquery(this).attr('rel').split('_'),
galleryId = getGalleryIdFromRelSplit(rel_split),
videoId = getVideoIdFromIdAttr(jquery(this).attr('id'));
/** Tell the gallery to change it's video. */
TubePressSequencer.changeToVideo(galleryId, videoId);
},
/** http://www.sohtanaka.com/web-design/smart-columns-w-css-jquery/ */
makeThumbsFluid = function (galleryId) {
getThumbArea(galleryId).css({ 'width' : '100%' });
var gallerySelector = getThumbAreaSelector(galleryId),
columnWidth = getThumbWidth(galleryId),
gallery = jquery(gallerySelector),
colWrap = gallery.width(),
colNum = math.floor(colWrap / columnWidth),
colFixed = math.floor(colWrap / colNum),
thumbs = jquery(gallerySelector + ' div.tubepress_thumb');
gallery.css({ 'width' : '100%'});
gallery.css({ 'width' : colWrap });
thumbs.css({ 'width' : colFixed});
},
/**
* What page is the gallery on?
*/
//TODO: this is way too fragile.
getCurrentPageNumber = function (galleryId) {
var page = 1,
paginationSelector = 'div#tubepress_gallery_' + galleryId + ' div.tubepress_thumbnail_area:first > div.pagination:first > span.current',
current = jquery(paginationSelector);
if (current.length > 0) {
page = current.html();
}
return page;
},
/**
* Callback for thumbnail loads.
*/
thumbBinder = function (e, galleryId) {
/* add a click handler to each link in this gallery */
jquery("#tubepress_gallery_" + galleryId + " a[id^='tubepress_']").click(clickListener);
/* fluid thumbs if we need it */
if (TubePressGallery.isFluidThumbs(galleryId)) {
makeThumbsFluid(galleryId);
}
};
docElement.bind(eventsToBindTo, thumbBinder);
/* return only public functions */
return {
getCurrentPageNumber : getCurrentPageNumber,
getGalleryIdFromRelSplit : getGalleryIdFromRelSplit,
getThumbAreaSelector : getThumbAreaSelector,
getVideoIdFromIdAttr : getVideoIdFromIdAttr
};
}());
/**
* Functions for handling Ajax pagination.
*/
var TubePressAjaxPagination = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variable declarations aide in compression. */
jquery = jQuery,
docElement = jquery(document),
events = TubePressEvents,
gallery = TubePressGallery,
/** Events we're interested in. */
eventsToBindTo = events.NEW_THUMBS_LOADED + ' ' + events.NEW_GALLERY_LOADED,
/**
* After we've loaded a new set of thumbs.
*/
postLoad = function (galleryId) {
docElement.trigger(TubePressEvents.NEW_THUMBS_LOADED, galleryId);
},
/** Handles an ajax pagination click. */
processClick = function (anchor, galleryId) {
var baseUrl = getTubePressBaseUrl(),
shortcode = gallery.getShortcode(galleryId),
page = anchor.attr('rel'),
thumbnailArea = TubePressThumbs.getThumbAreaSelector(galleryId),
postLoadCallback = function () { postLoad(galleryId); },
pageToLoad = baseUrl + '/sys/scripts/ajax/shortcode_printer.php?shortcode=' + shortcode + '&tubepress_' + page + '&tubepress_galleryId=' + galleryId,
remotePageSelector = thumbnailArea + ' > *';
TubePressAjax.loadAndStyle(pageToLoad, thumbnailArea, remotePageSelector, '', postLoadCallback);
},
/** Initializes pagination HTML for Ajax. */
addClickHandlers = function (galleryId) {
var clickCallback = function () {
processClick(jquery(this), galleryId);
};
jquery('#tubepress_gallery_' + galleryId + ' div.pagination a').click(clickCallback);
},
/**
* Adds click handlers to galleries with Ajax pagination.
*/
paginationBinder = function (e, galleryId) {
if (gallery.isAjaxPagination(galleryId)) {
addClickHandlers(galleryId);
}
};
/** Sets up new thumbnails for ajax pagination */
docElement.bind(eventsToBindTo, paginationBinder);
}());
/**
* Browser quirks and small performance improvements.
*/
var TubePressCompat = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var jquery = jQuery,
init = function () {
/* caching script loader */
jquery.getScript = function (url, callback, cache) {
jquery.ajax({ type: 'GET', url: url, success: callback, dataType: 'script', cache: cache });
};
};
return { init: init };
}());
/**
* Provides auto-sequencing capability for TubePress.
*/
var TubePressPlayerApi = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var
/** These variable declarations aide in compression. */
jquery = jQuery,
documentElement = jquery(document),
events = TubePressEvents,
undef = 'undefined',
logger = TubePressLogger,
/** YouTube variables. */
loadingYouTubeApi = false,
youTubePrefix = 'tubepress-youtube-player-',
youTubePlayers = {},
youTubeIdPattern = /[a-z0-9\-_]{11}/i,
/** Vimeo variables. */
loadingVimeoApi = false,
vimeoPrefix = 'tubepress-vimeo-player-',
vimeoPlayers = {},
vimeoIdPattern = /[0-9]+/,
/**
* Is the given video ID from YouTube?
*/
isYouTubeVideoId = function (videoId) {
return youTubeIdPattern.test(videoId);
},
/**
* Is the given video ID from Vimeo?
*/
isVimeoVideoId = function (videoId) {
return vimeoIdPattern.test(videoId);
},
/**
* Helper method to trigger events on jQuery(document).
*/
triggerEvent = function (eventName, videoId) {
if (logger.on()) {
logger.log('Firing ' + eventName + ' for ' + videoId);
}
documentElement.trigger(eventName, videoId);
},
/**
* A video has started.
*/
fireVideoStartedEvent = function (videoId) {
triggerEvent(events.PLAYBACK_STARTED, videoId);
},
/**
* A video has stopped.
*/
fireVideoStoppedEvent = function (videoId) {
triggerEvent(events.PLAYBACK_STOPPED, videoId);
},
/**
* A video is buffering.
*/
fireVideoBufferingEvent = function (videoId) {
triggerEvent(events.PLAYBACK_BUFFERING, videoId);
},
/**
* A video has paused.
*/
fireVideoPausedEvent = function (videoId) {
triggerEvent(events.PLAYBACK_PAUSED, videoId);
},
/**
* A video has encountered an error.
*/
fireVideoErrorEvent = function (videoId) {
triggerEvent(events.PLAYBACK_ERROR, videoId);
},
/**
* Pulls out the video ID from a YouTube event.
*/
getVideoIdFromYouTubeEvent = function (event) {
var domId = event.target.a.id,
vId = domId.replace(youTubePrefix, ''),
player = youTubePlayers[vId],
url, loadedId, ampersandPosition;
if (typeof player.getVideoUrl !== 'function') {
return null;
}
//noinspection JSUnresolvedFunction
url = player.getVideoUrl();
loadedId = url.split('v=')[1];
ampersandPosition = loadedId.indexOf('&');
if (ampersandPosition !== -1) {
loadedId = loadedId.substring(0, ampersandPosition);
}
return loadedId;
},
/**
* Pulls out the video ID from a Vimeo event.
*/
getVideoIdFromVimeoEvent = function (event) {
return event.replace(vimeoPrefix, '');
},
/**
* Utility to wait for test() to be true, then call callback()
*/
callWhenTrue = function (callback, test, delay) {
/** It's ready... */
if (test() === true) {
callback();
return;
}
/** Set up a timeout callback. */
var func = function () {
callWhenTrue(callback, test, delay);
};
/** Keep waiting... */
setTimeout(func, delay);
},
/**
* Is the YouTube API available yet?
*/
isYouTubeApiAvailable = function () {
return typeof YT !== undef && typeof YT.Player !== undef;
},
/**
* Is the Vimeo API available yet?
*/
isVimeoApiAvailable = function () {
return typeof Froogaloop !== undef;
},
/**
* Load the YouTube API, if necessary.
*/
loadYouTubeApi = function () {
if (! loadingYouTubeApi && ! isYouTubeApiAvailable()) {
if (logger.on()) {
logger.log('Loading YT API');
}
loadingYouTubeApi = true;
jquery.getScript('http://www.youtube.com/player_api');
}
},
/**
* Load the Vimeo API, if necessary.
*/
loadVimeoApi = function () {
if (! loadingVimeoApi && ! isVimeoApiAvailable()) {
if (logger.on()) {
logger.log('Loading Vimeo API');
}
loadingVimeoApi = true;
jquery.getScript('http://a.vimeocdn.com/js/froogaloop2.min.js');
}
},
/**
* The YouTube player will call this method when a player event
* fires.
*/
onYouTubeStateChange = function (event) {
var videoId = getVideoIdFromYouTubeEvent(event),
eventData = event.data,
playerState = YT.PlayerState;
/**
* If we can't parse the event, just bail.
*/
if (videoId === null) {
return;
}
switch (eventData) {
case playerState.PLAYING:
fireVideoStartedEvent(videoId);
break;
case playerState.PAUSED:
fireVideoPausedEvent(videoId);
break;
case playerState.ENDED:
fireVideoStoppedEvent(videoId);
break;
case playerState.BUFFERING:
fireVideoBufferingEvent(videoId);
break;
default:
if (logger.on()) {
logger.log('Unknown YT event');
logger.dir(event);
}
//unknown event
break;
}
},
/**
* YouTube will call this when a player hits an error.
*/
onYouTubeError = function (event) {
var videoId = getVideoIdFromYouTubeEvent(event);
if (videoId === null) {
return;
}
if (logger.on()) {
logger.log('YT error');
logger.dir(event);
}
fireVideoErrorEvent(videoId);
},
/**
* Vimeo will call then when a video starts.
*/
onVimeoPlay = function (event) {
var videoId = getVideoIdFromVimeoEvent(event);
fireVideoStartedEvent(videoId);
},
/**
* Vimeo will call then when a video pauses.
*/
onVimeoPause = function (event) {
var videoId = getVideoIdFromVimeoEvent(event);
fireVideoPausedEvent(videoId);
},
/**
* Vimeo will call then when a video ends.
*/
onVimeoFinish = function (event) {
var videoId = getVideoIdFromVimeoEvent(event);
fireVideoStoppedEvent(videoId);
},
/**
* A Vimeo player is ready for action.
*/
onVimeoReady = function (playerId) {
var froog = vimeoPlayers[playerId];
froog.addEvent('play', onVimeoPlay);
froog.addEvent('pause', onVimeoPause);
froog.addEvent('finish', onVimeoFinish);
},
/**
* Registers a YouTube player for use with the TubePress API.
*/
registerYouTubeVideo = function (videoId) {
/** Load 'er up. */
loadYouTubeApi();
/** This stuff will execute once the TubePress API is loaded. */
var callback = function () {
if (logger.on()) {
logger.log('Register YT video ' + videoId + ' with TubePress');
}
youTubePlayers[videoId] = new YT.Player(youTubePrefix + videoId, {
events: {
'onError' : onYouTubeError,
'onStateChange' : onYouTubeStateChange
}
});
};
/** Execute it when YouTube is ready. */
callWhenTrue(callback, isYouTubeApiAvailable, 300);
},
/**
* Registers a Vimeo player for use with the TubePress API.
*/
registerVimeoVideo = function (videoId) {
/** Load up the API. */
loadVimeoApi();
var playerId = vimeoPrefix + videoId,
iframe = document.getElementById(playerId),
callback = function () {
var froog;
if (logger.on()) {
logger.log('Register Vimeo video ' + videoId + ' with TubePress');
}
/** Create and save the player. */
froog = new Froogaloop(iframe);
vimeoPlayers[playerId] = froog;
froog.addEvent('ready', onVimeoReady);
};
/** Execute it when Vimeo is ready. */
callWhenTrue(callback, isVimeoApiAvailable, 800);
},
/**
* Registers a play for use with the TubePress API, but only
* when jQuery(document).ready() has been called.
*/
docReadyRegister = function (videoId) {
if (isYouTubeVideoId(videoId)) {
registerYouTubeVideo(videoId);
} else if (isVimeoVideoId(videoId)) {
registerVimeoVideo(videoId);
}
/** Notify anyone that's interested. */
triggerEvent(events.EMBEDDED_LOAD, videoId);
},
/**
* Registers an arbitrary video for use with the TubePress API.
*/
register = function (videoId) {
documentElement.ready(function () {
try {
docReadyRegister(videoId);
} catch (e) {
logger.log('Error when registering: ' + e);
}
});
};
return {
register : register,
isYouTubeVideoId : isYouTubeVideoId,
isVimeoVideoId : isVimeoVideoId,
onYouTubeStateChange : onYouTubeStateChange,
onYouTubeError : onYouTubeError,
onVimeoPlay : onVimeoPlay,
onVimeoPause : onVimeoPause,
onVimeoFinish : onVimeoFinish,
onVimeoReady : onVimeoReady
};
}());
/**
* Handles Ajax interactive searching.
*/
var TubePressAjaxSearch = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var performSearch = function (urlEncodedShortcode, urlEncodedSearchTerms, targetDomSelector, galleryId) {
/** These variable declarations aide in compression. */
var jquery = jQuery,
logger = TubePressLogger,
/** Some vars we'll need later. */
callback,
ajaxResultSelector,
finalAjaxContentDestination,
/** The Ajax response results that we're interested in. */
gallerySelector = '#tubepress_gallery_' + galleryId,
/** Does a gallery with this ID already exist? */
galleryExists = jquery(gallerySelector).length > 0,
/** Does the target DOM exist? */
targetDomExists = targetDomSelector && targetDomSelector !== '' && jquery(targetDomSelector).length > 0;
/** We have three cases to handle... */
if (galleryExists) {
//CASE 1: gallery already exists
/** Stick the thumbs into the existing thumb area. */
finalAjaxContentDestination = TubePressThumbs.getThumbAreaSelector(galleryId);
/** We want just the new thumbnails. */
ajaxResultSelector = finalAjaxContentDestination + ' > *';
/** Announce the new thumbs */
callback = function () {
jquery(document).trigger(TubePressEvents.NEW_THUMBS_LOADED, galleryId);
};
} else {
if (targetDomExists) {
//CASE 2: TARGET SELECTOR EXISTS AND GALLERY DOES NOT EXIST
/** Stick the gallery into the target DOM. */
finalAjaxContentDestination = targetDomSelector;
} else {
//CASE 3: TARGET SELECTOR DOES NOT EXIST AND GALLERY DOES NOT EXIST
if (logger.on()) {
logger.log('Bad target selector and missing gallery');
}
return;
}
}
if (logger.on()) {
logger.log('Final dest: ' + finalAjaxContentDestination);
logger.log('Ajax selector: ' + ajaxResultSelector);
}
TubePressAjax.loadAndStyle(getTubePressBaseUrl() + '/sys/scripts/ajax/shortcode_printer.php?shortcode='
+ urlEncodedShortcode + '&tubepress_search=' + urlEncodedSearchTerms, finalAjaxContentDestination, ajaxResultSelector, null, callback);
};
return { performSearch : performSearch };
}());
/**
* Dependency checks for TubePress.
*/
var TubePressDepCheck = (function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
var init = function () {
var version = jQuery.fn.jquery,
windowConsole = window.console;
if (/1\.6|7|8|9\.[0-9]+/.test(version) === false) {
/** Try to log it... */
if (typeof windowConsole !== 'undefined') {
windowConsole.log("TubePress requires jQuery 1.6 or higher. This page is running version " + version);
}
}
};
return { init : init };
}());
/**
* Primary TubePress boot function.
*/
var tubePressBoot = function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
TubePressCompat.init();
TubePressDepCheck.init();
};
/**
* Append our init method to after all the other (potentially full of errors) ready blocks have
* run. http://stackoverflow.com/questions/1890512/handling-errors-in-jquerydocument-ready
*/
if (!jQuery.browser.msie) {
var oldReady = jQuery.ready;
jQuery.ready = function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
try {
oldReady.apply(this, arguments);
} catch (e) {
/** Try to log it. */
if (typeof console !== 'undefined') {
console.log("Caught exception when booting TubePress: " + e);
}
}
tubePressBoot();
};
jQuery.ready.promise = oldReady.promise;
} else {
jQuery(document).ready(function () {
/** http://www.yuiblog.com/blog/2010/12/14/strict-mode-is-coming-to-town/ */
'use strict';
tubePressBoot();
});
}