Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adammw/5633645 to your computer and use it in GitHub Desktop.
Save adammw/5633645 to your computer and use it in GitHub Desktop.
if (window.ninemsn.portal.common.video.jqueryNoConflict) {
window.ninemsn.portal.common.video.$ = window.jQuery.noConflict(true);
}
(function ($, ninemsn) {
var video = ninemsn.portal.common.video; // used as a short-cut to the video namespace
video.enumerations = video.enumerations || {
account: {
ninemsn: "ninemsn",
ninemsnCatchup: "ninemsnCatchup",
msnNZ: "msnNZ",
thirdParty: "thirdParty"
}
};
video.enumerations.data = video.enumerations.data || {
adapter: {
msn: "msn",
Brightcove: "brightcove",
CCast: "ccast"
},
method: {
ID: "id",
IDs: "ids",
Tags: "tags",
Search: "search",
Related: "related"
},
searchOperator: {
All: "ALL",
Any: "ANY",
Exact: "EXACT"
}
};
video.enumerations.event = video.enumerations.event || {
player: {
loading: "player:loading",
loaded: "player:loaded",
error: "player:error"
},
video: {
loading: "video:loading",
loaded: "video:loaded",
opening: "video:opening",
buffering: "video:buffering",
playing: "video:playing",
paused: "video:paused",
stopped: "video:stopped",
playCompleted: "video:playCompleted",
changed: "video:changed",
error: "video:error"
},
ad: {
opening: "ad:opening",
playing: "ad:playing",
paused: "ad:paused",
playCompleted: "ad:playCompleted",
error: "ad:error"
}
};
video.enumerations.player = video.enumerations.player || {
adapter: {
msn: "msn",
Brightcove: "brightcove",
ads: {
freewheel: "freewheel"
}
},
type: {
Flash: "flash",
Silverlight: "silverlight",
HTML5: "html5"
}
};
video.enumerations.widget = video.enumerations.widget || {
type: {
leadWithImage: "leadWithImage",
list: "list",
playlist: "playlist",
suggestedVideos: "suggestedVideos"
}
};
video.Data = video.Data || function (dataConfig) {
/// <summary>Creates a new ninemsn.portal.common.video.Data object</summary>
/// <param name="config" optional="true" type="Object"></param>
/// <returns type="ninemsn.portal.common.video.Data" />
// Ensure we are working with an instance of the object
var _context = (this instanceof video.Data) ? this : new video.Data(dataConfig);
// stores the data adapter object
var _adapter;
// stores the config object
var _config = {
// default settings
account: video.enumerations.account.ninemsn,
adapter: video.enumerations.data.adapter.msn,
paging: {
page: 1,
size: 10
},
cache: true
};
_context.dispose = function () {
/// <summary>
/// In addition to the element itself, all bound events and data associated with the element is removed.
/// </summary>
_context.logger.debug("is being disposed of");
if (_adapter.dispose != null) {
_adapter.dispose();
}
_adapter = null;
_config = null;
_context = null;
};
(function () {
// Apply brightcove adapter if account = ninemsnCatchup
if (dataConfig.hasOwnProperty("account") && dataConfig["account"] == video.enumerations.account.ninemsnCatchup) {
_config.adapter = video.enumerations.data.adapter.Brightcove;
}
// Merge the default settings with the supplied configuration
_config = $.extend(true, _config, dataConfig); // the configuration of the data object
// Create a new config getter
_context.config = new video.utils.Config(_context, _config);
// Attach the logger object
_context.logger = new video.utils.Logger(
$.extend(
true,
{
name: "ninemsn.portal.common.video.Data"
},
_context.config("logger")
)
);
// init the data adapter
if (_dataAdapters.hasOwnProperty(_config["adapter"])) {
_adapter = new _dataAdapters[_config["adapter"]](_context);
} else {
_context.logger.error("'" + _config["adapter"] + "' is an unknown Data adapter");
}
})();
};
var _dataAdapters = _dataAdapters || {
/// <summary>Namespace for ninemsn video data adapters (MSN, Service Framework, etc.)</summary>
};
_dataAdapters[video.enumerations.data.adapter.msn] = _dataAdapters[video.enumerations.data.adapter.msn] || function (dataContext) {
var _context = dataContext;
var _config = $.extend(
true,
{
// default settings
baseUrl: "http://edge1.catalog.video.msn.com/",
fileFilter: 80
},
_context.config("msn")
); // the configuration of the player
var _cacheKey = "{market}_{method}_{params}_{page}_{pageSize}_{sortField}_{sortDirection}_{fileFilter}";
var _jqxhr;
var _methods = {};
var _translations = {
market: {
// Market (ninemsn > msn)
ninemsn: "en-au", ninemsnCatchup: "alt2-en-au", msnNZ: "en-nz", thirdParty: "alt-en-au"
},
sort_by: {
// Sort By (ninemsn > msn)
ID: "VideoID", START_DATE: "ActiveStartDate"
},
sort_order: {
// Sort Order (ninemsn > msn)
ASC: 1, DESC: -1
},
search_operator: {
// Search Operator (ninemsn > msn)
ALL: 0, ANY: 1, EXACT: 2
}
};
var normalise = function (data, callback) {
if (data != null) {
var response = {
pageNumber: (function () { return data.hasOwnProperty("$ind") ? parseInt(data.$ind) : null; })(),
pageSize: (function () { return data.hasOwnProperty("$ps") ? parseInt(data.$ps) : null; })(),
totalVideos: (function () { return data.hasOwnProperty("$total") ? parseInt(data.$total) : null; })(),
videos: []
};
if (response.pageSize != null && response.pageNumber != null) {
// correct the page number
response.pageNumber = response.pageNumber - 1;
response.pageNumber = response.pageNumber + response.pageSize;
response.pageNumber = response.pageNumber / response.pageSize;
}
if (data.hasOwnProperty("video")) {
// multiple videos in the response
for (var videoItem in data.video) {
videoItem = data.video[videoItem];
if (typeof (videoItem) == "object") {
response.videos.push(
createVideoObject(videoItem)
);
}
}
} else {
// single video in the response (always return an array)
response.videos = [createVideoObject(data)];
}
// Return the normalised data
callback(response);
} else {
_context.logger.warn("No data in the response");
}
};
var createVideoObject = function (data) {
var videoObject = {
id: data.uuid.$,
title: data.title.$,
description: data.description.$,
duration: data.durationSecs.$,
publishDate: video.utils.createUtcDateFromString(data.startDate.$),
source: data.source.$friendlyName,
reporting: {
plays: { total: -1 }
},
account: video.utils.msn.getAccountFromMarket(data.tags.tag[0].$market),
rawObject: data
};
// Get the image
videoObject.image = function (width, height) {
return "http://img2.catalog.video.msn.com/image.aspx?uuid=" + videoObject.id + "&w=" + width + "&h=" + height;
};
// Get the reporting stats
if (data.hasOwnProperty("usage") && data.usage.hasOwnProperty("usageItem")) {
for (var i = 0; i < data.usage.usageItem.length; i++) {
var item = data.usage.usageItem[i];
// Plays
if (parseInt(item.$counterType) == 1) {
videoObject.reporting.plays.total = parseInt(item.$totalCount);
}
}
}
return videoObject;
};
/*
MSN Caches the data on distinct url's which means
that if we have a random callbackName the data is never cached.
This cache key is used to provide a consistent callbackName
*/
var buildCacheKey = function (key, value) {
if (_cacheKey.indexOf(key) > -1) {
_cacheKey = _cacheKey.replace(key, value);
}
};
var getCleanCacheKey = function () {
// cleanup the cache key
_cacheKey = _cacheKey.replace(/[^A-Za-z0-9_]/ig, "");
if (typeof window[_cacheKey] == "function") {
_context.logger.debug("Cache Key in already in use", _cacheKey);
_cacheKey = _cacheKey + "_rand" + (Math.floor(Math.random() * 1100));
}
_context.logger.debug("Cache Key", _cacheKey);
return _cacheKey;
};
var request = function (query) {
query = _config.baseUrl + query;
if (_context.config("paging") != null) {
// Page size
var pageSize = _context.config("paging.size");
if (pageSize != null) {
query += "&ps=" + pageSize;
buildCacheKey("{pageSize}", pageSize);
// Page number
var pageNumber = _context.config("paging.page");
if (pageNumber != null) {
var indent = (pageNumber * pageSize);
indent = (indent - pageSize);
indent++;
query += "&ind=" + indent;
buildCacheKey("{page}", indent);
}
}
}
/*
File filter:
Allows you to filter your return results based on pre-defined filters e.g. playable on mobile
*/
if (_config["fileFilter"] != null) {
query += "&ff=" + _config["fileFilter"];
buildCacheKey("{fileFilter}", _config["fileFilter"]);
}
// Sorting
if (_context.config("sort") != null) {
var sort = _context.config("sort");
var fields = "";
var directions = "";
var translate = function (item) {
// Translate the field
item.by = (_translations.sort_by.hasOwnProperty(item.by) ? _translations.sort_by[item.by] : item.by);
fields += (fields == "") ? item.by : "," + item.by;
// Translate the direction
item.order = (_translations.sort_order.hasOwnProperty(item.order) ? _translations.sort_order[item.order] : item.order);
directions += (directions == "") ? item.order : "," + item.order;
};
if (sort instanceof Array) {
for (var i = 0; i < sort.length; i++) {
translate(sort[i]);
}
} else {
translate(sort);
}
if (fields != "") {
query += "&sf=" + fields;
buildCacheKey("{sortField}", fields);
}
if (directions != "") {
query += "&sd=" + directions;
buildCacheKey("{sortDirection}", directions);
}
}
query += "&responseEncoding=json&callbackName=?";
_context.logger.log("Request", query);
// Execute the query against the MSN catalogue
_jqxhr = $.ajax({
url: query,
dataType: "jsonp",
cache: _context.config("cache"),
jsonpCallback: getCleanCacheKey(),
success: (function (data) {
_context.logger.log("Request Complete", data);
normalise(data, _context.config("success"));
}),
error: (
// Supported as of jQuery 1.5
function (msg) {
_context.logger.error("Data request failed - " + msg.status, msg);
// If a custom error handler has been assigned, raise it
if (_context.config("error") != null) {
_context.config("error")(msg);
}
}
)
});
};
_methods[video.enumerations.data.method.ID] = function () {
buildCacheKey("{params}", _context.config("filter.id"));
request("videobyuuid.aspx?uuid=" + _context.config("filter.id"));
};
_methods[video.enumerations.data.method.IDs] = function () {
var ids = "";
var uuids = _context.config("filter.ids");
for (var id in uuids) {
ids += (ids == "") ? uuids[id] : "," + uuids[id];
}
buildCacheKey("{params}", ids);
request("videobyuuids.aspx?uuids=" + ids);
};
_methods[video.enumerations.data.method.Tags] = function () {
var namespaces = "";
var values = "";
var tags = _context.config("filter.tags");
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
if (!(tag.value instanceof Array)) {
tag.value = new Array(tag.value);
}
for (var t = 0; t < tag.value.length; t++) {
namespaces += (namespaces == "") ? tag.name : "," + tag.name;
values += (values == "") ? tag.value[t] : "," + tag.value[t];
}
}
buildCacheKey("{params}", namespaces + "_" + values);
request("videobytag.aspx?mk=" + _config.market + "&ns=" + namespaces + "&tag=" + values);
};
_methods[video.enumerations.data.method.Search] = function () {
var term = _context.config("filter.term");
var termResult = "";
var operator = _context.config("filter.operator");
var i;
if (term instanceof Array) {
for (i = 0; i < term.length; i++) {
termResult += (termResult == "") ? term[i] : " " + term[i];
}
} else {
termResult = term;
}
// handle tags in search
var namespaces = "";
var values = "";
var tags = _context.config("filter.tags");
if (tags != null) {
for (i = 0; i < tags.length; i++) {
var tag = tags[i];
if (!(tag.value instanceof Array)) {
tag.value = new Array(tag.value);
}
for (var t = 0; t < tag.value.length; t++) {
namespaces += (namespaces == "") ? tag.name : "," + tag.name;
values += (values == "") ? tag.value[t] : "," + tag.value[t];
}
}
}
var tagQuery = namespaces.length > 0 ? "&ns=" + namespaces + "&tag=" + values : "";
// Translate the operator
operator = (_translations.search_operator.hasOwnProperty(operator) ? _translations.search_operator[operator] : "0");
buildCacheKey("{params}", term + "_" + namespaces + "_" + values + "_" + operator);
request("search.aspx?mk=" + _config.market + "&q=" + encodeURIComponent(termResult) + "&op=" + operator + tagQuery);
};
_methods[video.enumerations.data.method.Related] = function () {
buildCacheKey("{params}", _context.config("filter.id"));
request("relatedvideos.aspx?mk=" + _config.market + "&uuids=" + _context.config("filter.id"));
};
this.dispose = function () {
_context.logger.log("Closing any active MSN data requests");
if (_jqxhr != null) {
_jqxhr.abort();
}
};
(function () {
if (_context.config("account") != null) {
// Set the account
if (_translations.market.hasOwnProperty(_context.config("account"))) {
_config["market"] = _translations.market[_context.config("account")];
buildCacheKey("{market}", _config["market"]);
} else {
_context.logger.error("The supplied account is not supported on this adapter", _context.config("account"));
}
} else {
_context.logger.error("Account has not been set on the adapter");
}
// Execute the method
if (_methods.hasOwnProperty(_context.config("method"))) {
buildCacheKey("{method}", _context.config("method"));
_methods[_context.config("method")]();
} else {
_context.logger.error("Data method not implemented", _context.config("data"));
}
})();
};
_dataAdapters[video.enumerations.data.adapter.Brightcove] = _dataAdapters[video.enumerations.data.adapter.Brightcove] || function (dataContext) {
var _context = dataContext;
var _config = $.extend(
true,
{
// default settings
baseUrl: "http://api.brightcove.com/services/library?command=",
videoFields: "&video_fields=id,referenceId,version,name,shortDescription,publishedDate,startDate,endDate,length,itemState,thumbnailURL,videoStillURL,playsTotal",
customFields: "&custom_fields=genre,network,provider,series,season,episode,originalairdate,classification",
item_count: "&get_item_count=true"
},
_context.config("brightcove")
); // the configuration of the player
var _jqxhr;
var _methods = {};
var _translations = {
market: {
// Market (ninemsn > msn)
ninemsn: "en-au", ninemsnCatchup: "alt2-en-au", msnNZ: "en-nz", thirdParty: "alt-en-au"
},
sort_by: {
// Sort By (ninemsn > brightcove)
ActiveStartDate: "START_DATE", monthlyCount: "PLAYS_TOTAL"
},
search_operator: {
// Search Operator (ninemsn > msn)
ALL: "all", ANY: "any", NONE: "none", EXACT: "exact"
}
};
var normalise = function (data, callback) {
if (data != null) {
var response = {
pageNumber: (function () { return data.hasOwnProperty("page_number") ? parseInt(data.page_number) : null; })(),
pageSize: (function () { return data.hasOwnProperty("page_size") ? parseInt(data.page_size) : null; })(),
totalVideos: (function () { return data.hasOwnProperty("total_count") ? parseInt(data.total_count) : null; })(),
videos: []
};
if (response.pageSize != null && response.pageNumber != null) {
// correct the page number
response.pageNumber = response.pageNumber + 1;
}
if (data.hasOwnProperty("items")) {
// multiple videos in the response
for (var videoItem in data.items) {
videoItem = data.items[videoItem];
if (typeof (videoItem) == "object") {
response.videos.push(
createVideoObject(videoItem)
);
}
}
} else {
// single video in the response (always return an array)
if (data.hasOwnProperty("error")) {
_context.logger.error(data.error);
}
else {
response.videos = [createVideoObject(data)];
}
}
// Return the normalised data
callback(response);
} else {
_context.logger.warn("No data in the response");
}
};
var createVideoObject = function (data) {
var videoObject = {
id: data.id,
title: data.name,
description: data.shortDescription,
duration: data.length / 1000,
publishDate: data.startDate != null ? new Date(parseInt(data.startDate)) : new Date(parseInt(data.publishedDate)),
source: data && data.customFields && data.customFields.series,
reporting: {
plays: { total: data.playsTotal || 0 }
},
account: _context.config("account"),
rawObject: data
};
videoObject.image = function (width, height) {
return "http://images.ninemsn.com.au/resizer.aspx?width=" + width + "&height=" + height + "&url=" + data.videoStillURL;
};
return videoObject;
};
var request = function (query) {
query = _config.baseUrl + query;
if (_context.config("paging") != null) {
// Page size
var pageSize = _context.config("paging.size");
if (pageSize != null) {
query += "&page_size=" + pageSize;
// Page number
var pageNumber = _context.config("paging.page");
if (pageNumber != null) {
query += "&page_number=" + (pageNumber - 1);
}
}
}
// Sorting
if (_context.config("sort") != null) {
var sort = _context.config("sort");
var sortby = "";
var directions = "";
var translate = function (item) {
// Translate the sort field
item.by = (_translations.sort_by.hasOwnProperty(item.by) ? _translations.sort_by[item.by] : item.by);
sortby += (sortby == "") ? item.by + ":" + item.order : "," + item.by + ":" + item.order;
};
if (sort instanceof Array) {
for (var i = 0; i < sort.length; i++) {
translate(sort[i]);
}
} else {
translate(sort);
}
if (sortby != "") {
query += "&sort_by=" + sortby;
}
}
query += "&token=" + _config.token + _config.videoFields + _config.customFields + _config.item_count;
query += "&callback=?";
_context.logger.log("Request", query);
// Execute the query against the MSN catalogue
_jqxhr = $.ajax({
url: query,
dataType: "jsonp",
cache: _context.config("cache"),
success: (function (data) {
_context.logger.log("Request Complete", data);
normalise(data, _context.config("success"));
}),
error: (
// Supported as of jQuery 1.5
function (msg) {
_context.logger.error("Data request failed - " + msg.status, msg);
// If a custom error handler has been assigned, raise it
if (_context.config("error") != null) {
_context.config("error")(msg);
}
}
)
});
};
_methods[video.enumerations.data.method.ID] = function () {
request("find_video_by_id&video_id=" + _context.config("filter.id"));
};
_methods[video.enumerations.data.method.IDs] = function () {
var ids = "";
var uuids = _context.config("filter.ids");
for (var id in uuids) {
ids += (ids == "") ? uuids[id] : "," + uuids[id];
}
request("find_videos_by_ids&video_ids=" + ids);
};
_methods[video.enumerations.data.method.Tags] = function () {
var operator = _context.config("filter.operator");
var tagQuery = "";
var tags = _context.config("filter.tags");
// Translate the operator
operator = (_translations.search_operator.hasOwnProperty(operator) ? _translations.search_operator[operator] : "all");
// Add Exact Attribute
if (operator == _translations.search_operator.EXACT) {
tagQuery += "exact=true";
operator = _translations.search_operator.ALL;
}
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
if (!(tag.value instanceof Array)) {
tag.value = new Array(tag.value);
}
for (var t = 0; t < tag.value.length; t++) {
var oneTag = operator + "=" + tag.name + ":" + tag.value[t];
tagQuery += (tagQuery == "") ? oneTag : "&" + oneTag;
}
}
request("search_videos&" + tagQuery);
};
_methods[video.enumerations.data.method.Search] = function () {
var term = _context.config("filter.term");
var termResult = "";
var operator = _context.config("filter.operator");
var i;
// Translate the operator
operator = (_translations.search_operator.hasOwnProperty(operator) ? _translations.search_operator[operator] : "all");
if (term instanceof Array) {
for (i = 0; i < term.length; i++) {
var ontTerm = operator + "=" + term[i];
termResult += (termResult == "") ? ontTerm : "&" + ontTerm;
}
} else {
termResult = operator + "=" + term;
}
request("search_videos&" + termResult);
};
_methods[video.enumerations.data.method.Related] = function () {
request("find_related_videos&video_id=" + _context.config("filter.id"));
};
var setAccountOverrides = function () {
/// <summary>Updates the config object to include account specific overrides</summary>
if (_context.config("account") != null) {
var _accountOverrides = {};
// ninemsn catchup
_accountOverrides[video.enumerations.account.ninemsnCatchup] = function () {
_config["token"] = "ogxhPgSphIVa2hhxbi9oqtYwtg032io4B4-ImwddYliFWHqS0UfMEw..";
};
_accountOverrides[video.enumerations.account.ninemsn] = function () {
_config["token"] = "Vb3fqavTKFDDZbnnGGtbhKxam7uHduOnob-2MJlpHmUnzSMWbDe5bg..";
};
if (_accountOverrides.hasOwnProperty(_context.config("account"))) {
_accountOverrides[_context.config("account")]();
} else {
_context.logger.error("The supplied account is not supported on this adapter", _context.config("account"));
}
} else {
_context.logger.error("Account has not been set on the adapter");
}
};
this.dispose = function () {
_context.logger.log("Closing any active MSN data requests");
if (_jqxhr != null) {
_jqxhr.abort();
}
};
(function () {
// Set the account overrides
setAccountOverrides();
// Execute the method
if (_methods.hasOwnProperty(_context.config("method"))) {
_methods[_context.config("method")]();
} else {
_context.logger.error("Data method not implemented", _context.config("data"));
}
})();
};
_dataAdapters[video.enumerations.data.adapter.CCast] = _dataAdapters[video.enumerations.data.adapter.CCast] || function (dataContext) {
var _context = dataContext;
var _config = $.extend(
true,
{
// default settings
// CCast proxy base url, support jsonp Callback, callback parameter: ?&callback=
baseUrl: "http://soocache.elasticbeanstalk.com/CCastTimeline/GetVideosByEpisode"
},
_context.config("ccast")
); // the configuration of the data adapter
var _jqxhr;
var _methods = {};
var normalise = function (data, callback) {
if (data != null) {
var response = {
videos: []
};
var episodeId = data.episode.id;
if (data.hasOwnProperty("events")) {
var possibleImgFormats = data.defaultValues.possibleImageFormats;
// multiple videos in the response
for (var event in data.events) {
event = data.events[event];
if (event.evsContent && event.evsContent.detail && event.evsContent.detail.camList) {
for (var cam in event.evsContent.detail.camList) {
cam = event.evsContent.detail.camList[cam];
if (typeof (cam) == "object" && cam.available) {
response.videos.push(
createVideoObject(cam, event, possibleImgFormats, episodeId)
);
}
}
}
}
}
// Return the normalised data
callback(response);
} else {
_context.logger.warn("No data in the response");
}
};
var getImgFormatFromLookup = function (possibleImgFormats, lookupName) {
for (var imgFormat in possibleImgFormats) {
imgFormat = possibleImgFormats[imgFormat];
if (imgFormat.lookupName == lookupName) {
return imgFormat;
}
}
return null;
};
var createVideoObject = function (cam, event, possibleImgFormats, episodeId) {
var videoObject = {
id: cam.video.name,
title: event.evsContent.title,
description: event.evsContent.description,
//duration: null,
publishDate: new Date(event.tcInDate + " " + event.tcInTime.substring(0, 2) + ":" + event.tcInTime.substring(2, 4) +
":" + event.tcInTime.substring(4, 6) + ":" + event.tcInTime.substring(6, 8)),
source: episodeId,
tags: [{ name: 'eventId', value: event.id }, { name: 'camId', value: cam.id}]
/*
reporting: {
plays: { total: cam.video.ratings.total || 0 }
},
account: _context.config("account"),
rawObject: cam
*/
};
// Push event keywords
for (var keyword in event.evsContent.keywordList) {
keyword = event.evsContent.keywordList[keyword];
videoObject.tags.push({ name: keyword.type.toLowerCase(), value: keyword.value });
}
// Get largest possible image format
var largestImgFormat = { width: 0 };
for (var imgFormat in cam.video.videoThumb.availableImageFormats) {
imgFormat = cam.video.videoThumb.availableImageFormats[imgFormat];
imgFormat = getImgFormatFromLookup(possibleImgFormats, imgFormat.lookupName);
if (imgFormat.width > largestImgFormat.width) {
largestImgFormat = imgFormat;
}
}
videoObject.image = function (width, height) {
return "http://images.ninemsn.com.au/resizer.aspx?width=" + width + "&height=" + height + "&url=" +
largestImgFormat.deliveries[0].url + cam.video.name.substring(0, 3) + "/" + cam.video.name.substring(3, 6) +
"/" + cam.video.name.substring(6, 9) + "/" + cam.video.name + "_" + largestImgFormat.profile + "." +
largestImgFormat.extension;
};
return videoObject;
};
var request = function (query) {
query = _config.baseUrl + query;
query += "&callback=?";
_context.logger.log("Request", query);
// Execute the query against the CCast API catalogue cached Proxy
_jqxhr = $.ajax({
url: query,
dataType: "jsonp",
cache: _context.config("cache"),
success: (function (data) {
_context.logger.log("Request Complete", data);
normalise(data, _context.config("success"));
}),
error: (
// Supported as of jQuery 1.5
function (msg) {
_context.logger.error("Data request failed - " + msg.status, msg);
// If a custom error handler has been assigned, raise it
if (_context.config("error") != null) {
_context.config("error")(msg);
}
}
)
});
};
_methods[video.enumerations.data.method.Tags] = function () {
var appId = "", episodeId = "";
var tags = _context.config("filter.tags");
for (var i = 0; i < tags.length; i++) {
var tag = tags[i];
if (tag.name == 'applicationId') {
appId = tag.value;
}
if (tag.name == 'episodeId') {
episodeId = tag.value;
}
}
request("?applicationId=" + appId + "&episodeId=" + episodeId);
};
this.dispose = function () {
_context.logger.log("Closing any active data requests");
if (_jqxhr != null) {
_jqxhr.abort();
}
};
(function () {
// Set the account overrides
//setAccountOverrides();
// Execute the method
if (_methods.hasOwnProperty(_context.config("method"))) {
_methods[_context.config("method")]();
} else {
_context.logger.error("Data method not implemented", _context.config("data"));
}
})();
};
video.Player = video.Player || function (playerConfig) {
/// <summary>Creates a new ninemsn.portal.common.video.Player object</summary>
/// <param name="config" optional="true" type="Object"></param>
/// <returns type="ninemsn.portal.common.video.Player" />
// Ensure we are working with an instance of the object
var _context = (this instanceof video.Player) ? this : new video.Player(playerConfig);
// the player as a jQuery object, all events are attached to this
var _player;
// stores the player adapter object
var _adapter;
// stores the config object
var _config = {
// Account
account: video.enumerations.account.ninemsn,
// Adapter to use
adapter: video.enumerations.player.adapter.msn,
// Width/Height
width: 640,
height: 360
};
_context.on = function (event, handler) {
/// <summary>
/// Attach an event handler function for one or more events to the selected elements.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false.</param>
_context.logger.debug("on", { event: event, handler: handler });
if (_player != null) {
// As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document
// If .on() is support use it, otherwise use the old .bind() method
if (typeof (_player.on) != "undefined") {
_player.on(event, handler);
} else {
_player.bind(event, handler);
}
} else {
_context.logger.error("The player object is undefined");
}
};
_context.one = function (event, handler) {
/// <summary>
/// Attach a handler to an event for the elements. The handler is executed at most once per element.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false.</param>
_context.logger.debug("one", { event: event, handler: handler });
if (_player != null) {
// Executes once and then removes itself
_player.one(event, handler);
}
};
_context.off = function (event, handler) {
/// <summary>
/// Remove an event handler.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A handler function previously attached for the event(s), or the special value false.</param>
_context.logger.debug("off", { event: event, handler: handler });
if (_player != null) {
// As of jQuery 1.7, the .off() method is the preferred method for removing event handlers
// If .off() is support use it, otherwise use the old .unbind() method
if (typeof (_player.off) != "undefined") {
_player.off(event, handler);
} else {
_player.unbind(event, handler);
}
}
};
_context.trigger = function (event, data) {
/// <summary>
/// Execute all handlers and behaviours attached to the matched elements for the given event object.
/// </summary>
/// <param name="event" type="String">The event type, such as "video:loaded" or "ad:paused".</param>
/// <param name="data" optional="true" type="Object">Additional data passed to the event handler as additional arguments</param>
if (_player != null) {
_context.logger.log(event, data);
_player.trigger(event, data);
}
};
_context.send = function (type, value) {
/// <summary>
/// Sends a message to the inner object.
/// </summary>
/// <param name="type" type="String">The type of message to send, such as “PLAY”</param>
/// <param name="value" optional="true" type="Object">The value to send with the message</param>
_context.logger.log("send", { type: type, value: value });
if (_adapter != null) {
_adapter.send(type, value);
} else {
_context.logger.warn(_context.config("adapter") + " does not implement 'send'");
}
};
_context.get = function (property) {
/// <summary>
/// Get the value of the given property.
/// </summary>
/// <param name="property" type="String">The property to return, such as “VOLUME”</param>
_context.logger.log("get", property);
if (_adapter != null) {
return _adapter.get(property);
} else {
_context.logger.warn(_context.config("adapter") + " does not implement 'get'");
return null;
}
};
_context.dispose = function () {
/// <summary>
/// In addition to the element itself, all bound events and data associated with the element is removed.
/// </summary>
_context.logger.debug("is being disposed of");
if (_adapter != null && _adapter.dispose != null) {
_adapter.dispose();
}
_adapter = null;
_player.empty(); // Remove the player from the page
_player = null;
// Remove from the list of object
delete video.objects[_config["outputLocation"]];
_context = null;
};
(function () {
// Apply Brightcove adapter if account = ninemsnCatchup
if (playerConfig.hasOwnProperty("account") && playerConfig["account"] == video.enumerations.account.ninemsnCatchup) {
_config.adapter = video.enumerations.player.adapter.Brightcove;
}
// Merge the default settings with the supplied configuration
_config = $.extend(true, _config, playerConfig);
// Create a new config getter
_context.config = new video.utils.Config(_context, _config);
// Attach the logger object
_context.logger = new video.utils.Logger(
$.extend(
true,
{
name: (function () {
return "ninemsn.portal.common.video.Player | " + _context.config("outputLocation");
})()
},
_context.config("logger")
)
);
// Raise warning if user trying to turn off ADs
if (!!(_context.config("ads"))) {
if (_context.config("ads").hasOwnProperty("enabled") && _context.config("ads").enabled == false) {
_context.logger.warn("ads:{enabled:false} (Turn off AD) feature is no longer supported. ADs are managed at Freewheel level.");
}
}
// Get the player as a jQuery object
_player = $("#" + _context.config("outputLocation"));
// Create the player object using the specified adapter
if (_playerAdapters.hasOwnProperty(_config["adapter"])) {
// Apply get targeting string to longform
if (_config.adapter == video.enumerations.player.adapter.Brightcove) {
$.when(video.utils.GetTargetString()).then(
function (adObj) { // defered Success call back, override context config with Target String
_config = $.extend(true, _config, adObj);
_context.config = new video.utils.Config(_context, _config);
_adapter = new _playerAdapters[_config["adapter"]](_context);
},
function () { // Fail call back
_adapter = new _playerAdapters[_config["adapter"]](_context);
}
);
}
else {
_adapter = new _playerAdapters[_config["adapter"]](_context);
}
} else {
_context.logger.error("'" + _config["adapter"] + "' is an unknown Player adapter");
}
// Add the player to the list of video objects on the page
video.objects[_config["outputLocation"]] = _context;
})();
};
var _playerAdapters = _playerAdapters || {
/// <summary>Namespace for ninemsn video player adapters (MSN, Brightcove, YouTube, etc.)</summary>
};
_playerAdapters[video.enumerations.player.adapter.msn] = _playerAdapters[video.enumerations.player.adapter.msn] || function (playerContext) {
/// <summary>Creates a new ninemsn.portal.common.video.player.adapters.msn objec</summary>
/// <returns type="ninemsn.portal.common.video.player">A MSN video player object</returns>
// Get the player's context
var _context = playerContext;
// Is the player loaded?
var _loaded = false;
// There is no common way to get/send messages to a player
// These are the translations for the MSN video player
var _translations = {
market: {
// Market (ninemsn > msn)
ninemsn: "en-au", ninemsnCatchup: "alt2-en-au", msnNZ: "en-nz", thirdParty: "alt-en-au"
},
send: {
// Send (ninemsn > msn)
PLAY: "playVideo", PAUSE: "pauseVideo", STOP: "stopVideo", SEEK: "seekVideo",
VOLUME: "setVolume", MUTE: "setVolume", LOAD: "loadVideo"
},
get: {
// Get (ninemsn > msn)
VOLUME: "volume", MUTED: "volume", POSITION: "currentVideoPosition", DURATION: "currentVideoPosition",
STATUS: "playbackStatus", META: "currentVideo", FULLSCREEN: "isFullScreen"
},
event: {
// Events (msn > ninemsn)
adOpening: video.enumerations.event.ad.opening, adPlaying: video.enumerations.event.ad.playing, adPaused: video.enumerations.event.ad.paused,
adPlayFailed: video.enumerations.event.ad.error, adPlayCompleted: video.enumerations.event.ad.playCompleted,
loading: video.enumerations.event.video.loading, loaded: video.enumerations.event.video.loaded, ready: video.enumerations.event.video.loaded,
videoChanged: video.enumerations.event.video.changed, videoOpening: video.enumerations.event.video.opening, videoPlaying: video.enumerations.event.video.playing,
videoPaused: video.enumerations.event.video.paused, playbackStopped: video.enumerations.event.video.stopped, videoBuffering: video.enumerations.event.video.buffering,
playbackCompleted: video.enumerations.event.video.playCompleted, videoPlayFailed: video.enumerations.event.video.error
},
sort_by: {
// Sort By (ninemsn > msn)
ID: "VideoID", START_DATE: "Date"
},
sort_order: {
// Sort Order (ninemsn > msn)
ASC: "Ascending", DESC: "Descending"
}
};
// The ID of the player object
var _id;
/// The default configuration of the player extended by the supplied settings
var _config = $.extend(
true,
{
// default settings
overflow: "hidden",
defaultDomain: {
loadCss: "false"
},
playerOverrides: {
MsnPlayerBaseLinkOverride: (function () { return location.protocol + "//" + location.host + "/video/"; } ())
}
},
_context.config("msn")); // the configuration of the player
var _outputLocation; // The ID of the HTML element where the player is rendered
var _videoFilter = {};
var _videoLoaded = false;
_videoFilter[video.enumerations.data.method.ID] = function () {
return {
type: "Uuid",
uuids: [_context.config("data.filter.id")]
};
};
_videoFilter[video.enumerations.data.method.IDs] = function () {
return {
type: "Uuid",
uuids: _context.config("data.filter.ids")
};
};
_videoFilter[video.enumerations.data.method.Tags] = function () {
var tags = [];
for (var i = 0; i < _context.config("data.filter.tags").length; i++) {
var tag = _context.config("data.filter.tags")[i];
if (!(tag.value instanceof Array)) {
tag.value = new Array(tag.value);
}
for (var t = 0; t < tag.value.length; t++) {
tags.push({
"$namespace": tag.name,
"$": tag.value[t]
});
}
}
return {
type: "tag",
tags: tags
};
};
_videoFilter[video.enumerations.data.method.Search] = function () {
return {
type: "search",
search: _context.config("data.filter.term")
};
};
var setMarketOverrides = function () {
/// <summary>Updates the config object to include market specific overrides</summary>
if (_context.config("account") != null) {
var _marketOverrides = {};
// ninemsn
_marketOverrides[video.enumerations.account.ninemsn] = function () {
_config["configName"] = "NetworkVideoPlayerFreewheel";
_config["defaultDomain"] = $.extend(true, _config["defaultDomain"], {
csid: 'ux-en-au'
});
_config["playerOverrides"] = $.extend(true, _config["playerOverrides"], {
widgetID: "network_video_player_freewheel"
});
};
// ninemsn catchup
_marketOverrides[video.enumerations.account.ninemsnCatchup] = function () {
_config["configName"] = "NetworkVideoPlayerFreewheel";
_config["defaultDomain"] = $.extend(true, _config["defaultDomain"], {
csid: 'ux-alt2-en-au'
});
_config["playerOverrides"] = $.extend(true, _config["playerOverrides"], {
widgetID: "network_video_player_freewheel"
});
};
// msn nz
_marketOverrides[video.enumerations.account.msnNZ] = function () {
_config["configName"] = "NetworkVideoPlayer";
_config["defaultDomain"] = $.extend(true, _config["defaultDomain"], {
csid: 'ux-en-nz'
});
_config["playerOverrides"] = $.extend(true, _config["playerOverrides"], {
widgetID: "network_video_player"
});
};
// third Party
_marketOverrides[video.enumerations.account.thirdParty] = function () {
_config["configName"] = "ThirdPartyVideoPlayerFreewheel";
_config["defaultDomain"] = $.extend(true, _config["defaultDomain"], {
csid: 'ux-alt-en-au'
});
_config["playerOverrides"] = $.extend(true, _config["playerOverrides"], {
widgetID: "third_party_video_player_freewheel"
});
};
if (_marketOverrides.hasOwnProperty(_context.config("account"))) {
_marketOverrides[_context.config("account")]();
} else {
_context.logger.error("The supplied account is not supported on this adapter", _context.config("account"));
}
} else {
_context.logger.error("Account has not been set on the adapter");
}
};
var getPlayerOverrides = function () {
/// <summary>Converts standard config items to MSN specific player overrides</summary>
/// <returns type="Object">Player overrides specific to the MSN player</returns>
var _playerOverrides = {};
var _widgetId = _config["playerOverrides"]["widgetID"];
var i;
var _ads = _context.config("ads") || {};
// Configure the advertising
// Are ads enabled?
if (_ads.enabled === false) {
_playerOverrides["AdsAllowed"] = (_ads.enabled ? "VideoContent" : "NoAds");
_playerOverrides["HTML5AdPolicy"] = (_ads.enabled ? "VideoContent" : "NoAds");
} else {
var userConfig = _ads.freewheel || {};
var freewheelConfig = _playerAdapters[video.enumerations.player.adapter.ads.freewheel];
var siteConfig = $.extend({}, _context.config("tracking"), _context.config("networkLocation"));
_playerOverrides["FWSiteSectionId"] = userConfig.siteSection || freewheelConfig.getSiteSection(siteConfig.site, siteConfig.section);
_playerOverrides["FWNetworkId"] = userConfig.networkId || freewheelConfig.getNetworkId();
_playerOverrides["FWServer"] = userConfig.serverUrl || freewheelConfig.getServerUrl();
if (_ads.hasOwnProperty("companions")) {
for (i = 0; i < _ads.companions.length; i++) {
var companion = _ads.companions[i];
if (companion.width == 300 && companion.height == 60) {
_playerOverrides["DisplayAdBanner"] = true;
_playerOverrides["BannerAdDivId"] = companion.outputLocation;
}
}
}
}
// / Configure the advertising
if (_context.config("data") != null) {
// Set the data source
if (_videoFilter.hasOwnProperty(_context.config("data.method"))) {
_playerOverrides[_widgetId + ".DefaultVideo"] = {
videoQuery: {
videoFilter: _videoFilter[_context.config("data.method")]()
}
};
// Sorting
if (_context.config("data.sort") != null) {
var sort = _context.config("data.sort");
var fields = "";
var directions = "";
var translate = function (item) {
// Translate the field
item.by = (_translations.sort_by.hasOwnProperty(item.by) ? _translations.sort_by[item.by] : item.by);
fields += (fields == "") ? item.by : "," + item.by;
// Translate the direction
item.order = (_translations.sort_order.hasOwnProperty(item.order) ? _translations.sort_order[item.order] : item.order);
directions += (directions == "") ? item.order : "," + item.order;
};
if (sort instanceof Array) {
for (i = 0; i < sort.length; i++) {
translate(sort[i]);
}
} else {
translate(sort);
}
_playerOverrides[_widgetId + ".DefaultVideo"].videoQuery.videoFilter["videoSort"] = {
sortField: fields,
sortDirection: directions
};
}
} else {
_context.logger.error("Data method not implemented", _context.config("data"));
}
} else {
_context.logger.warn("An empty data object was supplied to the player.");
}
// Set the player width/height
_playerOverrides[_widgetId + ".Width"] = _context.config("width");
_playerOverrides[_widgetId + ".Height"] = _context.config("height");
// Autoplay the video?
var _autoPlay = _context.config("autoPlay");
if (_autoPlay != null) {
_playerOverrides["AutoPlayVideo"] = _autoPlay;
}
// Enable closed captioning?
var _closedCaptions = _context.config("closedCaptions");
if (_closedCaptions != null) {
_playerOverrides["MsnPlayerDisplayCC"] = _closedCaptions;
}
// Setup the inbuilt player tracking
var _tracking = _context.config("tracking");
if (_tracking != null) {
if (_tracking.hasOwnProperty("site")) {
_playerOverrides["PlayerChannel"] = _tracking.site.replace(' ', '_');
}
if (_tracking.hasOwnProperty("hierarchy")) {
var _hierarchy = "";
for (i = 0; i < _tracking.hierarchy.length; i++) {
var level = _tracking.hierarchy[i].replace(' ', '_');
_hierarchy += (_hierarchy == "") ? level : "^" + level;
}
_playerOverrides["PlayerLocation"] = _hierarchy;
}
}
// Apply any supplied player overrides
_playerOverrides = $.extend(true, _config["playerOverrides"], _playerOverrides);
_context.logger.debug("Player Overrides", _playerOverrides);
return _playerOverrides;
};
var eventFired = function (playerId) {
/// <summary>Handles MSN player events and raises them as ninemsn video events</summary>
/// <returns type="Object" />
/// <private />
var _playerId = playerId;
var _playerEvents = {
// Flash/Silverlight video changed event
currentVideoChanged: function (event) {
if (event.param.hasOwnProperty("status") && event.param.status == "success") {
_context.trigger(video.enumerations.event.video.changed, _context.get("META"));
} else if (event.param.status == "error") {
_context.trigger(video.enumerations.event.video.error);
}
},
// HTML video changed event
currentVideoDataUpdated: function (event) {
if (event.param.status == "success") {
_context.trigger(video.enumerations.event.video.changed, createVideoObject(event.param.video));
} else if (event.param.status == "error") {
_context.trigger(video.enumerations.event.video.error);
}
},
playbackStatusChanged: function (event) {
var _playbackEvents = {
adOpening: function () {
_context.trigger(video.enumerations.event.ad.opening);
},
adPlaying: function () {
_context.trigger(video.enumerations.event.ad.playing);
},
adPaused: function () {
_context.trigger(video.enumerations.event.ad.paused);
},
adPlayFailed: function () {
_context.trigger(video.enumerations.event.ad.error);
},
adPlayCompleted: function () {
_context.trigger(video.enumerations.event.ad.playCompleted);
},
loading: function () {
_context.trigger(video.enumerations.event.video.loading);
},
loaded: function () {
_context.trigger(video.enumerations.event.video.loaded, _context.get("META"));
_videoLoaded = true;
},
ready: function () {
_context.trigger(video.enumerations.event.video.loaded, _context.get("META"));
_videoLoaded = true;
},
videoOpening: function () {
_context.trigger(video.enumerations.event.video.opening);
},
videoPlaying: function () {
_context.trigger(video.enumerations.event.video.playing);
},
videoPaused: function () {
_context.trigger(video.enumerations.event.video.paused, _context.get("POSITION"));
},
playbackStopped: function () {
_context.trigger(video.enumerations.event.video.stopped);
},
videoBuffering: function () {
_context.trigger(video.enumerations.event.video.buffering);
},
playbackCompleted: function () {
_context.trigger(video.enumerations.event.video.playCompleted);
},
videoPlayFailed: function () {
_context.trigger(video.enumerations.event.video.error);
}
};
if (_playbackEvents.hasOwnProperty(event.param.status)) {
_playbackEvents[event.param.status](event);
} else {
_context.logger.warn("'" + event.param.status + "' is an unhandled playback status");
}
}
};
return function (event) {
if (event.sourceId == _playerId) {
if (_playerEvents.hasOwnProperty(event.type)) {
_playerEvents[event.type](event);
} else {
_context.logger.warn(event.type + " is an unhandled event type");
}
}
};
};
var createVideoObject = function (data) {
/// <summary>Converts the MSN video object to a ninemsn video object</summary>
/// <returns type="Object" />
/// <private />
var videoObject = null;
if (data != null && data != "undefined") {
videoObject = {
id: data.uuid,
title: data.title,
description: data.description,
duration: data.durationSecs,
publishDate: video.utils.createUtcDateFromString(data.startDate),
source: data.sourceFriendly,
reporting: {}, // The MSN player does not return usage data
account: video.utils.msn.getAccountFromMarket(data.tags[0].mk),
rawObject: data
};
videoObject.image = function (width, height) {
return "http://img2.catalog.video.msn.com/image.aspx?uuid=" + videoObject.id + "&w=" + width + "&h=" + height;
};
} else {
_context.logger.warn("Cannot normalise, supplied data was invalid", data);
}
return videoObject;
};
var _messageReceivers = [];
var addMessageReceiver = function (eventType, callback) {
/// <summary>Attatches a message receiver to the player</summary>
window.MsnVideo2.addMessageReceiver({ eventType: eventType, widgetId: _outputLocation, widgetGroup: null, funcCb: callback });
// Add it to the array so we can remove it later (if the player is disposed of)
_messageReceivers.push({ eventType: eventType, widgetId: _outputLocation, widgetGroup: null, funcCb: callback });
};
var attachEventHandlers = function () {
/// <summary>Attatches the event handlers to the player</summary>
/// <private />
// Ensure this event is only raised one
window.$vxp("#" + _outputLocation).unbind("playerReady", attachEventHandlers);
// Get the player as a MSN VxP object
var _player = window.$vxp("#" + _id);
// Create the callback handler
var _callback = new eventFired(_id);
// Get the player type (Flash, Silverlight, HTML)
var _playerType = _context.get("TYPE");
// Only attach the handlers if we know the type of player
if (_playerType != null) {
_context.logger.log("Type: " + _playerType);
// The event handlers vary based on the player type
if (_playerType != video.enumerations.player.type.HTML5) {
// Flash/Silverlight player events
addMessageReceiver("currentVideoChanged", _callback);
addMessageReceiver("playbackStatusChanged", _callback);
} else {
// HTML player events
addMessageReceiver("currentVideoDataUpdated", _callback);
addMessageReceiver("playbackStatusChanged",
function (event) {
// The MSN "loaded" event fires too early and the video is unplayable at this time
if (event.param.status != "loaded") {
_callback(event);
}
}
);
// Check to see if the video is paused, if it is the video is ready to play
if ($("#" + _outputLocation).find("div.ready").length > 0) {
// When the player is ready, fire the video:loaded event
_context.one(video.enumerations.event.player.loaded, function () {
_callback({ type: "playbackStatusChanged", sourceId: _id, param: { status: "loaded"} });
});
}
// When the players "canplay" event is fired, then raise a loaded event
_player.find("video").bind("canplay", function () {
_callback({ type: "playbackStatusChanged", sourceId: _id, param: { status: "loaded"} });
});
// window.$vxp.vxpGlobal.players[_id]
}
if (_context.config("msn.playerOverrides.DisplayControlBar") == null || !_context.config("msn.playerOverrides.DisplayControlBar")) {
// The MSN player has a hardcoded div appearing below the player which casues a gap to appear, hide the div
$("#" + _outputLocation + " .vxpMultiLiteInfo").hide();
}
// Raise the player:loaded event
_context.trigger(video.enumerations.event.player.loaded, { id: _outputLocation });
_loaded = true; // The player is now loaded and ready to use
// Raise video:loaded event if video not loaded
if (!_videoLoaded && _playerType != video.enumerations.player.type.HTML5) {
if (_context.get("STATUS") != _translations.event.loading && _context.get("META") != null) {
_callback({ type: "playbackStatusChanged", sourceId: _id, param: { status: "loaded"} });
}
}
// Remove the loading class
$("#" + _outputLocation).removeClass("video_player_loading");
if (_context.config("account") == video.enumerations.account.msnNZ) {
$("#" + _outputLocation).removeClass("video_player_loading_nz");
}
} else {
// Raise a player error event
_context.logger.error("The player type is unknown");
_context.trigger("player:error");
}
};
this.send = function (type, value) {
/// <summary>
/// Convert the type and value to a MSN object and sends it to the playeer
/// </summary>
/// <param name="type" type="String">The type of message to send, such as “PLAY”</param>
/// <param name="value" optional="true" type="Object">The value to send with the message</param>
var params = {
SEEK: function (position) {
return {
"position": position
};
},
VOLUME: function (volume) {
return {
"volume": volume
};
},
MUTE: function (mute) {
return {
"mute": mute
};
},
LOAD: function (uuid) {
return {
"uuid": uuid
};
}
};
window.MsnVideo2.sendMessage({
"type": _translations.send[type],
"targetId": _id,
"param": (params.hasOwnProperty(type) ? params[type](value) : value)
});
};
this.get = function (property) {
/// <summary>
/// Converts the property to a MSN object and gets the value of the given property from the player
/// </summary>
/// <param name="property" type="String">The property to return, such as “VOLUME”</param>
var _methods = {
TYPE: function () {
var _player = window.$vxp.vxpGlobal.players[_id];
if (_player != null) {
var type = _player.type;
var playerTypes = video.enumerations.player.type;
if (type == "msn:flash") {
type = playerTypes.Flash;
} else if (type == "msn:silverlight") {
type = playerTypes.Silverlight;
} else if (type == "msn:html5") {
type = playerTypes.HTML5;
} else {
_context.logger.warn("'" + type + "' is an unknown player type.");
type = null;
}
return type;
} else {
_context.logger.warn("Could not find the player on the page. The player type could not be determined.");
return null;
}
},
VOLUME: function () {
return window.MsnVideo2.getProperties({
"type": _translations.get["VOLUME"],
"targetId": _id
})[0].param.volume;
},
MUTED: function () {
return window.MsnVideo2.getProperties({
"type": _translations.get["MUTED"],
"targetId": _id
})[0].param.mute;
},
POSITION: function () {
return window.MsnVideo2.getProperties({
"type": _translations.get["POSITION"],
"targetId": _id
})[0].param.position;
},
DURATION: function () {
return window.MsnVideo2.getProperties({
"type": _translations.get["DURATION"],
"targetId": _id
})[0].param.duration;
},
STATUS: function () {
if (_loaded) {
var status = window.MsnVideo2.getProperties({
"type": _translations.get["STATUS"],
"targetId": _id
})[0].param.status;
// fix Silverlight player has capital play status
if (_context.get("TYPE") == video.enumerations.player.type.Silverlight) {
status = status.substring(0, 1).toLowerCase() + status.substring(1);
}
if (_translations.event[status] != null) {
return _translations.event[status];
} else {
_context.logger.warn("Could not normalise the '" + status + "' status");
return null;
}
}
else {
return "player:loading";
}
},
META: function () {
return createVideoObject(
window.MsnVideo2.getProperties({
"type": _translations.get["META"],
"targetId": _id
})[0].param.video
);
},
FULLSCREEN: function () {
return window.MsnVideo2.getProperties({
"type": _translations.get["FULLSCREEN"],
"targetId": _id
})[0].param.isFullScreen;
}
};
if (_methods.hasOwnProperty(property)) {
return _methods[property]();
} else {
_context.logger.warn(property + " is not a supported property");
return null;
}
};
this.dispose = function () {
/// <summary>
/// Removes the player from the page
/// </summary>
_context.logger.log("Removing a MSN player");
// Remove all event handlers
for (var i = 0; i < _messageReceivers.length; i++) {
window.MsnVideo2.removeMessageReceiver(_messageReceivers[i]);
}
_messageReceivers = []; // Empty the array
// Call the MSN remove method
window.MsnVideoUx.remove(_outputLocation);
};
// Handles the configuration and creation of the MSN player
(function () {
// Raise the loading event
_context.trigger(video.enumerations.event.player.loading);
_outputLocation = _context.config("outputLocation");
// There is a known issue in the MSN HTML5 player when the player is rendered in a location called "videoplayer"
if (_outputLocation.toLowerCase() == "videoplayer") {
_context.logger.warn("Output location cannot be '" + _outputLocation + "'. Please change the name of the output location.");
}
/*
The MSN player has issues resizing. If the output width is different to the network default,
a background is automatically added. This clipping removes the background.
*/
$("#" + _outputLocation).css({
overflow: _config["overflow"],
width: (function () {
return _context.config("width") + "px";
} ()),
height: (function () {
return _context.config("height") + "px";
} ())
});
// Add the loading class
$("#" + _outputLocation).addClass("video_player_loading");
if (_context.config("account") == video.enumerations.account.msnNZ) {
$("#" + _outputLocation).addClass("video_player_loading_nz");
}
// The ID of the player object, a bit hacky but this is the only way to get the ID of the player before it is created
_id = _outputLocation + "_ux1_1_1_1";
// Set market specific config overrides
setMarketOverrides();
// Once the component is loaded; attatch the event handlers
window.$vxp("#" + _outputLocation).bind("playerReady", attachEventHandlers);
// Render the MSN player
_context.logger.log("Rendering a MSN video player");
window.MsnVideoUx.render(
(_context.config("msn") && _context.config("msn")["configName"]) || _config["configName"],
_outputLocation,
getPlayerOverrides(),
(_context.config("msn") && _context.config("msn")["defaultDomain"]) || _config["defaultDomain"]
);
})();
};
_playerAdapters[video.enumerations.player.adapter.Brightcove] = _playerAdapters[video.enumerations.player.adapter.Brightcove] || function (playerContext) {
/// <summary>Creates a new ninemsn.portal.common.video.player.adapters.msn object</summary>
/// <returns type="ninemsn.portal.common.video.player">A Brightcove video player object</returns>
// Get the player's context
var _context = playerContext;
/// The default configuration of the player extended by the supplied settings
var _config = $.extend(
true,
{
bgcolor: "#000000",
isVid: true,
isUI: true,
dynamicStreaming: true,
includeAPI: true,
wmode: "transparent"
},
_context.config("brightcove")); // the configuration of the player
var _outputLocation = _context.config("outputLocation");
var _experienceID = "BC_" + _outputLocation;
var _player; // The player as a brightcove experience
var _modVP; // Video Player Module
var _modExp; // Experience Module
var _modCon; // Content Module
var _modAd; // Advertising Module
var _loaded = false;
var _currentVideo; // Stores the META data for the current video
var _currentPosition = 0; // Stores the current time position
var _currentStatus = video.enumerations.event.player.loading; // Stores the status of the player/video
var _translate = {
Age: { MA: 15, R: 18 },
AudienceInfo: { PG: "Parental guidance recommended", M: "Recommended for mature audiences" }
};
this.send = function (type, value) {
var methods = {
SEEK: function (position) {
_modVP.seek(position);
},
LOAD: function (id) {
id = id.toString();
if (id.indexOf("ref:") != 0) {
_modVP.loadVideoByID(id);
} else {
// remove the "ref:" prefix
id = id.replace("ref:", "");
// load by reference id
_modVP.loadVideoByReferenceID(id);
}
$("#video_player_ageGate").remove();
$("iframe#" + _experienceID).css({ width: _context.config("width") + "px" });
_context.one(video.enumerations.event.video.loaded, attachAgeGate);
$("#video_player_html5_error").remove();
},
PLAY: function () {
_modVP.play();
},
PAUSE: function () {
_modVP.pause();
},
STOP: function () {
_modVP.pause();
_modVP.seek(0);
_context.trigger(video.enumerations.event.video.stopped);
}
};
if (methods.hasOwnProperty(type)) {
methods[type](value);
} else {
_context.logger.warn(type + " is not supported");
}
};
this.get = function (property) {
/// <summary>
/// Converts the property to a MSN object and gets the value of the given property from the player
/// </summary>
/// <param name="property" type="String">The property to return, such as “VOLUME”</param>
var _methods = {
META: function () {
return _currentVideo;
},
TYPE: function () {
if (_modVP.experience != null) {
var type = _modVP.experience.type;
var playerTypes = video.enumerations.player.type;
if (type == "flash") {
type = playerTypes.Flash;
} else if (type == "html") {
type = playerTypes.HTML5;
} else {
_context.logger.warn("'" + type + "' is an unknown player type.");
type = null;
}
return type;
} else {
_context.logger.warn("Could not find the player on the page. The player type could not be determined.");
return null;
}
},
POSITION: function () {
return _currentPosition;
},
DURATION: function () {
if (_currentVideo != null) {
return _currentVideo.duration;
} else {
_context.logger.warn("DURATION is not available yet");
return 0;
}
},
STATUS: function () {
if (_loaded) {
return _currentStatus;
}
else {
return video.enumerations.event.player.loading;
}
}
};
if (_methods.hasOwnProperty(property)) {
return _methods[property]();
} else {
_context.logger.warn(property + " is not a supported property");
return null;
}
};
var createVideoObject = function (data) {
/// <summary>Converts the Brightcove video object to a ninemsn video object</summary>
/// <returns type="Object" />
/// <private />
var videoObject = null;
if (data != null && data != "undefined") {
videoObject = {
id: data.id,
title: data.displayName,
description: data.shortDescription,
duration: data.length / 1000, // convert the duration to seconds
publishDate: video.utils.createUtcDateFromString(data.startDate),
source: data && data.customFields && data.customFields.series,
account: _context.config("account"),
reporting: {}, // The Brightcove player does not return usage data
rawObject: data
};
videoObject.image = function (width, height) {
return "http://images.ninemsn.com.au/resizer.aspx?width=" + width + "&height=" + height + "&url=" + data.videoStillURL;
};
} else {
_context.logger.warn("Cannot normalise, supplied data was invalid", data);
}
return videoObject;
};
var eventFired = function () {
/// <summary>Handles Brightcove player events and raises them as ninemsn video events</summary>
/// <returns type="Object" />
/// <private />
var _playerEvents = {
mediaPlay: function (event) {
if (event.position == 0) {
_currentVideo = createVideoObject(event.media);
_currentStatus = video.enumerations.event.video.opening;
if (_currentVideo != null) {
_context.trigger(video.enumerations.event.video.opening, _currentVideo);
} else {
_context.logger.warn("Could not raise video:opening with META data as it was null");
_context.trigger(video.enumerations.event.video.opening);
}
}
_currentStatus = video.enumerations.event.video.playing;
_context.trigger(video.enumerations.event.video.playing);
},
mediaStop: function () {
_currentStatus = video.enumerations.event.video.paused;
_context.trigger(video.enumerations.event.video.paused);
},
mediaComplete: function () {
_currentStatus = video.enumerations.event.video.playCompleted;
_context.trigger(video.enumerations.event.video.playCompleted);
},
mediaChange: function (event) {
_currentVideo = createVideoObject(event.media);
_currentStatus = video.enumerations.event.video.changed;
if (_currentVideo != null) {
_context.trigger(video.enumerations.event.video.changed, _currentVideo);
_context.trigger(video.enumerations.event.video.loaded, _currentVideo);
} else {
// Get the current video
_modVP.getCurrentVideo(function (result) {
_currentVideo = createVideoObject(result);
_context.trigger(video.enumerations.event.video.changed, _currentVideo);
_context.trigger(video.enumerations.event.video.loaded, _currentVideo);
});
}
},
mediaProgress: function (event) {
// store the current position
_currentPosition = event.position;
},
mediaError: function () {
_currentStatus = video.enumerations.event.video.error;
_context.trigger(video.enumerations.event.video.error);
},
adStart: function (event) {
if (event.position == 0) {
_currentStatus = video.enumerations.event.ad.opening;
_context.trigger(video.enumerations.event.ad.opening);
}
_currentStatus = video.enumerations.event.ad.playing;
_context.trigger(video.enumerations.event.ad.playing);
},
adComplete: function () {
_currentStatus = video.enumerations.event.ad.playCompleted;
_context.trigger(video.enumerations.event.ad.playCompleted);
}
};
return function (event) {
if (_playerEvents.hasOwnProperty(event.type)) {
_playerEvents[event.type](event);
} else {
_context.logger.warn(event.type + " is an unhandled event type");
}
};
};
var attachEventHandlers = function () {
_player = window.brightcove.api.getExperience(_experienceID);
_currentStatus = video.enumerations.event.player.loaded;
// Create the callback handler
var _callback = new eventFired();
_modVP = _player.getModule(window.brightcove.api.modules.APIModules.VIDEO_PLAYER);
_modExp = _player.getModule(window.brightcove.api.modules.APIModules.EXPERIENCE);
_modCon = _player.getModule(window.brightcove.api.modules.APIModules.CONTENT);
_modAd = _player.getModule(window.brightcove.api.modules.APIModules.ADVERTISING);
_context.trigger(video.enumerations.event.video.loading);
_currentStatus = video.enumerations.event.video.loading;
_modExp.addEventListener(window.brightcove.api.events.ExperienceEvent.TEMPLATE_READY, function () {
_loaded = true;
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.BEGIN, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.CHANGE, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.COMPLETE, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.ERROR, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.PLAY, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.PROGRESS, _callback);
_modVP.addEventListener(window.brightcove.api.events.MediaEvent.STOP, _callback);
_modAd.addEventListener(window.brightcove.api.events.AdEvent.START, _callback);
_modAd.addEventListener(window.brightcove.api.events.AdEvent.COMPLETE, _callback);
});
};
var setAccountOverrides = function () {
/// <summary>Updates the config object to include account specific overrides</summary>
if (_context.config("account") != null) {
var _accountOverrides = {};
// ninemsn catchup
_accountOverrides[video.enumerations.account.ninemsnCatchup] = function () {
_config["playerID"] = "2193241313001";
_config["playerKey"] = "AQ~~,AAABecFwRRk~,e1HkYhZIbpgkrcvm9Xo3tHIAN8ttykr_";
// Dev
//_config["playerID"] = "929577932001";
//_config["playerKey"] = "AQ~~,AAAA2EMGPBE~,w0dWIowaawiPXdUORDVzo9p-LKLkiBxg";
};
// ninemsn
_accountOverrides[video.enumerations.account.ninemsn] = function () {
_config["playerID"] = "952317942001";
_config["playerKey"] = "AQ~~,AAAAmtNDn-E~,a88FbwlXndisf2n9Aq-Kj8HVijl5N4vU";
};
if (_accountOverrides.hasOwnProperty(_context.config("account"))) {
_accountOverrides[_context.config("account")]();
} else {
_context.logger.error("The supplied account is not supported on this adapter", _context.config("account"));
}
} else {
_context.logger.error("Account has not been set on the adapter");
}
};
var preloadClassificationImg = function () {
function preload(arrayOfImages) {
$(arrayOfImages).each(function () {
$('<img/>')[0].src = this;
});
}
// Preload classification imgs:
preload([
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/M.png',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/MA.png',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/PG.png',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/R.png',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/black_bg.gif',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/dialog_bg.png',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/M_bg.jpg',
'http://shared.9msn.com.au/share/long_cache/img/video/age_gate/PG_bg.jpg'
]);
};
var attachAgeGate = function () {
var ageGateHTML = "";
var classification = _currentVideo.rawObject.customFields.classification;
var autoPlay = _context.config("autoPlay");
function calaulateAge() {
if (classification == "MA" || classification == "R") {
if (video.utils.isDate($("#video_player_ageGate input#day").val() + "/" + $("#video_player_ageGate input#month").val() + "/" + $("#video_player_ageGate input#year").val())) {
var birthDate = new Date(parseInt($("#video_player_ageGate input#year").val()), parseInt($("#video_player_ageGate input#month").val()) - 1, parseInt($("#video_player_ageGate input#day").val()));
var today = new Date();
var restrictYear = _translate.Age.hasOwnProperty(classification) ?
_translate.Age[classification] : 0;
if (today >= new Date(birthDate.getFullYear() + restrictYear, birthDate.getMonth(), birthDate.getDate())) {
$("#video_player_ageGate").remove();
$("iframe#" + _experienceID).css({ width: _context.config("width") + "px" });
_modVP.play();
} else {
$("#video_player_ageGate span.warning").text("We're sorry, this video is restricted based on the date of birth you entered.");
setTimeout(function () {
for (var vid in video.objects) {
if (video.objects[vid].config().outputLocation == _outputLocation) {
video.objects[vid].trigger(video.enumerations.event.video.playCompleted);
}
}
}, 5000);
}
} else {
$("#video_player_ageGate span.warning").text("Invalid date input.");
}
} else {
$("#video_player_ageGate").remove();
$("iframe#" + _experienceID).css({ width: _context.config("width") + "px" });
_modVP.pause(false);
}
}
if (classification &&
(classification == "M" || classification == "MA" || classification == "PG" || classification == "R")
) {
ageGateHTML = "<div id='video_player_ageGate' class='rate_" + classification.toLowerCase() + "' style='display:none;'>";
ageGateHTML += "<span class='rateinfo'><img src='http://shared.9msn.com.au/share/long_cache/img/video/age_gate/" + classification + ".png'>";
ageGateHTML += "</span>";
if (classification == "MA" || classification == "R") {
ageGateHTML += "<div class='agedialog'>";
ageGateHTML += "<span class='ageinfo'>Please verify your date of birth to view this video</span>";
ageGateHTML += "<span class='dobinput'><span class='dayinput'><input id='day' type='text' maxlength='2' value='DD'/></span>";
ageGateHTML += "<input id='month' type='text' maxlength='2' value='MM'/>";
ageGateHTML += "<input id='year' type='text' maxlength='4' value='YYYY'/></span>";
ageGateHTML += "</div>";
ageGateHTML += "<input id='submit' type='button' value=''></input>";
}
else {
ageGateHTML += "<span class='audienceinfo'>" + _translate.AudienceInfo[classification].toString() + "</span>";
}
ageGateHTML += "<span class='warning'></span>";
ageGateHTML += "</div>";
if ($("#" + _outputLocation + " #video_player_ageGate").length == 0) {
$("#" + _outputLocation).append(ageGateHTML);
$("#video_player_ageGate input[type=text]").click(function (event) { $(this).val(""); });
$("#video_player_ageGate input[type=text]#day").blur(function (e) { if ($(this).val() == "") $(this).val("DD"); });
$("#video_player_ageGate input[type=text]#month").blur(function (e) { if ($(this).val() == "") $(this).val("MM"); });
$("#video_player_ageGate input[type=text]#year").blur(function (e) { if ($(this).val() == "") $(this).val("YYYY"); });
$("#video_player_ageGate input[type=text]#day").keyup(function (e) { if ($(this).val().length == 2) $("#video_player_ageGate input[type=text]#month").click().focus(); });
$("#video_player_ageGate input[type=text]#month").keyup(function (e) { if ($(this).val().length == 2) $("#video_player_ageGate input[type=text]#year").click().focus(); });
$("#video_player_ageGate #submit").click(calaulateAge);
$("#video_player_ageGate input[type=text]").keypress(function (event) {
if (event.keyCode == 13) {
calaulateAge(); return false;
}
});
$("#video_player_ageGate").css({ width: _context.config("width") + "px", height: _context.config("height") + "px" });
}
// Attach video:playing to show classification, only to flash player
if ((classification == "M" || classification == "PG") && _context.get("TYPE") == video.enumerations.player.type.Flash) {
_context.one('video:playing', function () {
$("#video_player_ageGate").show();
if ($("#video_player_ageGate").length > 0) {
setTimeout(function () {
_modVP.pause();
}, 500);
setTimeout(function () { calaulateAge(); }, 2500);
$("iframe#" + _experienceID).css({ width: "0px" });
}
});
if (autoPlay) {
_modVP.play();
}
}
else if (classification == "MA" || classification == "R") // for MA or R, show age gate directly for both flash and HTML5
{
$("#video_player_ageGate").show();
if ($("#video_player_ageGate").length > 0) {
setTimeout(function () {
_modVP.pause();
}, 500);
$("iframe#" + _experienceID).css({ width: "0px" });
}
}
}
else { // No Classification
if (autoPlay) {
_modVP.play();
}
}
};
var attachLoadImg = function () {
if (_context.get("TYPE") == video.enumerations.player.type.Flash) {
if ($("#" + _outputLocation + " #video_player_brightcove_loading_img").length == 0) {
$("#" + _outputLocation).append("<img src='http://catchup.ninemsn.com.au/img/loading.gif' id='video_player_brightcove_loading_img'/>");
} else {
$("#video_player_brightcove_loading_img").show();
}
_context.one("ad:playing video:playing player:error", function () {
$("#video_player_brightcove_loading_img").hide();
});
}
};
var attachHTML5Error = function () {
if (_context.get("TYPE") == video.enumerations.player.type.HTML5) {
var defaultErrorHTML = "";
defaultErrorHTML = "<div id='video_player_html5_error'>";
defaultErrorHTML += "<span>We’re sorry, the video you are looking for cannot be viewed on this device.</span>";
defaultErrorHTML += "</div>";
if ($("#" + _outputLocation + " #video_player_html5_error").length == 0) {
$("#" + _outputLocation).append(defaultErrorHTML);
$("#video_player_html5_error").css({ width: _context.config("width") + "px", height: _context.config("height") + "px" });
} else {
$("#video_player_html5_error").show();
}
}
};
var setupAds = function () {
// Configure the advertising
var adsConfig = _context.config("ads") || {};
// Are ads enabled?
if (adsConfig.enabled === false) {
return;
}
var userInput = adsConfig.freewheel || {};
var freewheelConfig = _playerAdapters[video.enumerations.player.adapter.ads.freewheel];
var siteConfig = $.extend({}, _context.config("tracking"), _context.config("networkLocation"));
//settings for flash player
var defaults = {
fw_server: userInput.serverUrl || freewheelConfig.getServerUrl(),
amLocation: userInput.adManagerUrl || freewheelConfig.getAdManagerUrl('flash'), //fixed
networkId: userInput.networkId || freewheelConfig.getNetworkId(), //account
siteSection: userInput.siteSection || freewheelConfig.getSiteSection(siteConfig.site, siteConfig.section), //site info
cb_profile: userInput.playerProfile || freewheelConfig.getPlayerProfile('flash', 'brightcove'), //fixed (different for html5)
assetIdField: userInput.assetIdField || 'standardBC_id', //fixed
fw_keyvalues: userInput.keyValues,
sponsorMsg: true
};
userInput = $.extend(true, userInput, adsConfig.html5 && adsConfig.html5.freewheel);
//settings for html player
var htmlSettings = userInput.html || { };
defaults = $.extend(defaults, {
serverUrl: defaults.serverUrl,
amLocation_js: htmlSettings.adManagerUrl || freewheelConfig.getAdManagerUrl('html'),
siteSectionId: defaults.siteSection,
cb_profile_js: htmlSettings.playerProfile || freewheelConfig.getPlayerProfile('html', 'brightcove'),
videoAssetCustomId: _config["@videoPlayer"],
keyvalues: userInput.keyValues
});
var config = $.extend(true, defaults, adsConfig && adsConfig.freewheel);
window.fw_config = function () {
return config;
};
};
var setPlayerOverrides = function () {
var _playerOverrides = {};
if (_context.config("data") != null) {
var _videoFilter = {};
_videoFilter[video.enumerations.data.method.ID] = function () {
return _context.config("data.filter.id");
};
_videoFilter[video.enumerations.data.method.Tags] = function () {
_context.one(video.enumerations.event.player.loaded,
function () {
var dt = new video.Data(
video.$.extend(true, {
success: function (data) {
_modVP.cueVideoByID(data.videos[0].id);
}
}, _context.config("data"))
);
});
return "";
};
// Set the data source
if (_videoFilter.hasOwnProperty(_context.config("data.method"))) {
_playerOverrides["@videoPlayer"] = _videoFilter[_context.config("data.method")]();
videoId = _playerOverrides["@videoPlayer"];
// Attach Age Gate for video.Playing
_context.one(video.enumerations.event.video.loaded, attachAgeGate);
// Attach Loading Img
//if (_context.config("account") === video.enumerations.account.ninemsnCatchup) {
// _context.on(video.enumerations.event.video.loaded, attachLoadImg);
//}
// Attach HTML5 player error message
_context.on(video.enumerations.event.video.error, attachHTML5Error);
} else {
_context.logger.error("Data method not implemented", _context.config("data"));
}
} else {
_context.logger.warn("An empty data object was supplied to the player.");
}
// Set the player width/height
_playerOverrides["width"] = _context.config("width");
_playerOverrides["height"] = _context.config("height");
// Autoplay the video? - moved to age gate logic
//var _autoPlay = _context.config("autoPlay");
//if (_autoPlay != null) {
// _playerOverrides["autoStart"] = _autoPlay;
//}
// Apply the supplied player overrides
_config = $.extend(true, _config, _playerOverrides);
_context.logger.debug("Player Configuration", _config);
};
function createParam(name, value) {
return "<param name=\"" + name + "\" value=\"" + value + "\" />";
};
function attachTemplateHandlers() {
var _markup = "";
// Set the callback for when the player is loaded
// we need to create a new function and attach it to the window to support the HTML5 player
window[_experienceID + "_loadCallback"] = (function () {
// raise the player:loaded event
_context.trigger(video.enumerations.event.player.loaded);
// Remove this function from the DOM
delete window[_experienceID + "_loadCallback"];
});
_markup += createParam("templateLoadHandler", (_experienceID + "_loadCallback"));
window[_experienceID + "_readyCallback"] = (function () {
// Get the current video
_modVP.getCurrentVideo(function (result) {
_currentVideo = createVideoObject(result);
_context.trigger(video.enumerations.event.video.loaded, _currentVideo);
});
// Remove this function from the DOM
delete window[_experienceID + "_readyCallback"];
});
_markup += createParam("templateReadyHandler", (_experienceID + "_readyCallback"));
window[_experienceID + "_errorCallback"] = (function (event) {
_currentStatus = video.enumerations.event.player.error;
var _errors = {
unknown: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | There was an unidentifiable issue that prevents load or playback", event);
},
domainRestricted: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | The player is not allowed to be viewed on the requesting domain", event);
},
geoRestricted: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | The player may not be viewed in the current geography", event);
},
invalidID: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | The ID provided for the player is not for a currently active player", event);
},
noContent: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | There was no programmed content in the player", event);
},
unavailableContent: function () {
_currentStatus = video.enumerations.event.video.error;
_context.trigger(video.enumerations.event.video.error);
_context.logger.error(_currentStatus + " | There was an error loading the video content", event);
},
upgradeRequiredForVideo: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | An upgrade to the Flash Player is required to view the content", event);
},
upgradeRequiredForPlayer: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | An upgrade to the Flash Player is required to load the player", event);
},
serviceUnavailable: function () {
_context.trigger(video.enumerations.event.player.error);
_context.logger.error(_currentStatus + " | There was an error connecting to the backend on initial load", event);
}
};
if (_errors.hasOwnProperty(event.errorType)) {
_errors[event.errorType]();
} else {
// Raise an "unknown" error event
_errors["unknown"]();
}
});
_markup += createParam("templateErrorHandler", (_experienceID + "_errorCallback"));
return _markup;
}
var videoId;
// Handles the configuration and creation of the Brightcove player
(function () {
// Raise the loading event
_context.trigger(video.enumerations.event.player.loading);
// Preload Classification Images
preloadClassificationImg();
// Once the player is loaded, attach the event handlers
_context.on(video.enumerations.event.player.loaded, function () {
attachEventHandlers();
});
// Set the account overrides
setAccountOverrides();
// Set the player overrides
setPlayerOverrides();
setupAds();
_config = $.extend(true, _config, _context.config("brightcove"));
// Render the player
var _markup = "<object id=\"" + _experienceID + "\" class=\"BrightcoveExperience\">";
for (var i in _config) {
_markup += createParam(i, _config[i]);
}
// Attach event handlers to the template
_markup += attachTemplateHandlers();
_markup += "</object>";
$("#" + _outputLocation).html(_markup);
var head = document.getElementById(_outputLocation);
var scr = document.createElement('script');
scr.setAttribute('src', 'http://adm.fwmrm.net/p/mi9_test/BrightcovePlugin.js');
var freewheelPluginLoaded = false;
scr.onload = scr.onreadystatechange = function () {
if (!freewheelPluginLoaded && (!this.readyState || this.readyState == 'complete')) {
freewheelPluginLoaded = true;
window.brightcove.createExperiences();
scr.onload = null;
}
};
head.appendChild(scr);
})();
};
_playerAdapters[video.enumerations.player.adapter.ads.freewheel] =
_playerAdapters[video.enumerations.player.adapter.ads.freewheel] || (function () {
var siteSectionMappings = {
'channelnine': {
'sections': {
'showthefarmerwantsawife': {}
}
},
'homes': {
'sections': {
'houseandgarden': { },
'realliving': { },
'theblock2012': { }
}
}
};
var methods = {};
methods.getSiteSection = function (site, section) {
var selectedSiteSectionName = site + '_general';
var siteMap = siteSectionMappings[site];
if (siteMap) {
if (siteMap.sections && siteMap.sections[section]) {
selectedSiteSectionName = siteMap.sections[section].name ||
site + '_' + section + '_general';
}
if (siteMap.name)
selectedSiteSectionName = siteMap.name;
}
return selectedSiteSectionName;
};
methods.getNetworkId = function () {
return 375613;
};
methods.getPlayerProfile = function (playerType, playerVendor) {
if (playerType === 'flash')
return playerVendor === 'msn' ? 'MSN_AU_as3_Live' : 'MSN_AU_BC_Live';
else
return playerVendor === 'msn' ? 'MSN_AU_HTML5_SmartXML_Live' : 'MSN_AU_BC_HTML5_Live';
};
methods.getAdManagerUrl = function (playerType) {
return playerType === 'html' ? 'http://adm.fwmrm.net/p/msn_au_live/AdManager.js' :
'http://adm.fwmrm.net/p/msn_au_live/AdManager.swf?logLevel=QUIET&cb=1';
};
methods.getServerUrl = function () {
return 'http://5bb3d.v.fwmrm.net';
};
return methods;
} ());
video.utils = video.utils || {
createDataFilterFromQuery: function (query) {
/// <summary>Translates a MSN video query to data objects</summary>
query = query.indexOf("/") == 0 ? query.substring(1) : query;
query = decodeURIComponent(query);
var _translations = {
sort_by: {
ActiveStartDate: "START_DATE"
},
market: {
"en-au": video.enumerations.account.ninemsn,
"en-nz": video.enumerations.account.msnNZ,
"alt2-en-au": video.enumerations.account.ninemsnCatchup,
"alt-en-au": video.enumerations.account.thirdParty
}
};
var paramsAsObject = function (q) {
/// <summary>Converts the params of a URL into an object</summary>
// Remove everything before the ?
q = q.substr(q.indexOf('?') + 1);
// Split everything on &
q = q.split('&');
// Split all items on =
var params = {};
for (i = 0; i < q.length; i++) {
var param = q[i].split('=');
params[param[0]] = param[1];
}
return params;
};
var data = {};
var queryParams = paramsAsObject(query);
var i;
// From video by tags query
if (query.toLowerCase().indexOf("videobytag.aspx") > -1) {
data["method"] = video.enumerations.data.method.Tags;
data["filter"] = { tags: [] };
//ns=MSNVideo_Cat&tag=AUnationalninenews
// [ { $namespace: "", $: "" }, ... ]
var ns = queryParams["ns"].split(',');
var tags = queryParams["tag"].split(',');
for (i = 0; i < ns.length; i++) {
data["filter"]["tags"].push({ name: ns[i], value: tags[i] });
}
}
// From related video query
if (query.toLowerCase().indexOf("relatedvideos.aspx") > -1) {
data["method"] = video.enumerations.data.method.Related;
data["filter"] = { id: queryParams["uuids"] };
}
// From search query
if (query.toLowerCase().indexOf("search.aspx") > -1) {
data["method"] = video.enumerations.data.method.Search;
data["filter"] = { term: [] };
var terms = queryParams["q"].split(' ');
for (i = 0; i < terms.length; i++) {
data["filter"]["term"].push(terms[i]);
}
}
// Paging
if (queryParams.hasOwnProperty("ps")) {
data["paging"] = {};
data["paging"]["size"] = queryParams["ps"];
var pageSize = parseInt(data["paging"]["size"]);
if (queryParams.hasOwnProperty("ind")) {
data["paging"] = (typeof (data["paging"]) == "undefined") ? {} : data["paging"];
var pageNumber = parseInt(queryParams["ind"]) - 1;
pageNumber = pageNumber + pageSize;
pageNumber = pageNumber / pageSize;
data["paging"]["page"] = pageNumber;
}
}
// Market
if (queryParams.hasOwnProperty("mk")) {
var mk = queryParams["mk"];
data["account"] = _translations.market.hasOwnProperty(mk) ? _translations.market[mk] : mk;
}
// File Filter
if (queryParams.hasOwnProperty("ff")) {
data["msn"] = {};
data["msn"]["fileFilter"] = queryParams["ff"];
}
// Sorting
if (queryParams.hasOwnProperty("sf")) {
var sf = queryParams["sf"].split(',');
var sd = (queryParams.hasOwnProperty("sd")) ? queryParams["sd"].split(',') : [];
var sort = [];
for (i = 0; i < sf.length; i++) {
var by = (_translations.sort_by.hasOwnProperty(sf[i]) ? _translations.sort_by[sf[i]] : sf[i]);
var order = ((sd[i] < sd.length) ? sd[i] : 1);
order = ((order == -1) ? "DESC" : "ASC");
sort.push({
"by": by,
"order": order
});
}
data["sort"] = sort;
}
return data;
},
createUtcDateFromString: function (fullUtcDate) {
if (typeof fullUtcDate == "string") {
var dateToReturn;
if (fullUtcDate.indexOf('T') > -1) {
if (fullUtcDate.indexOf('Z') > -1) {
fullUtcDate = fullUtcDate.substr(0, fullUtcDate.length - 1); // remove the Z
}
var utcDate = fullUtcDate.split('T')[0].split('-');
var utcTime = fullUtcDate.split('T')[1].split(':');
dateToReturn = new Date(Date.UTC(utcDate[0], (parseInt(utcDate[1], 10) - 1), utcDate[2], utcTime[0], utcTime[1], utcTime[2]));
} else {
dateToReturn = new Date(fullUtcDate);
}
return dateToReturn;
} else {
return fullUtcDate;
}
},
isDate: function (value) {
try {
//Change the below values to determine which format of date you wish to check. It is set to dd/mm/yyyy by default.
var DayIndex = 0;
var MonthIndex = 1;
var YearIndex = 2;
value = value.replace(/-/g, "/").replace(/\./g, "/");
var SplitValue = value.split("/");
var OK = true;
if (!(SplitValue[DayIndex].length == 1 || SplitValue[DayIndex].length == 2)) {
OK = false;
}
if (OK && !(SplitValue[MonthIndex].length == 1 || SplitValue[MonthIndex].length == 2)) {
OK = false;
}
if (OK && SplitValue[YearIndex].length != 4) {
OK = false;
}
if (OK) {
var Day = parseInt(SplitValue[DayIndex], 10);
var Month = parseInt(SplitValue[MonthIndex], 10);
var Year = parseInt(SplitValue[YearIndex], 10);
if (OK = ((Year > 1900) && (Year < new Date().getFullYear()))) {
if (OK = (Month <= 12 && Month > 0)) {
var LeapYear = (((Year % 4) == 0) && ((Year % 100) != 0) || ((Year % 400) == 0));
if (Month == 2) {
OK = LeapYear ? Day <= 29 : Day <= 28;
}
else {
if ((Month == 4) || (Month == 6) || (Month == 9) || (Month == 11)) {
OK = (Day > 0 && Day <= 30);
}
else {
OK = (Day > 0 && Day <= 31);
}
}
}
}
}
return OK;
}
catch (e) {
return false;
}
}
};
video.utils.Config = video.utils.Config || function (context, config) {
var _context = context;
var _config = config;
return function (property) {
/// <summary>
/// 1: config() - Gets the entire configuration object.
/// 2: config(property) - Gets the value of the given configuration property.
/// </summary>
/// <param name="property" optional="true" type="String">The property to get the configuration value of such as “outputLocation” or “video.filter.id” to traverse through multiple levels</param>
/// <returns type="Object">Configuration value is returned if property param is not null otherwise the entire configuration object is returned</returns>
if (typeof (property) != "undefined") {
var prop = null;
if (_config.hasOwnProperty(property)) {
prop = _config[property];
}
else if (property.split('.').length > 1) {
var p = property.split('.');
if (_config.hasOwnProperty(p[0])) {
prop = _config[p[0]];
for (var i = 1; i < p.length && prop != null; i++) {
prop = prop.hasOwnProperty(p[i]) ? prop[p[i]] : null;
}
}
}
// The property was not found in the configuration, log a warning
if (prop == null && _context.logger != null) {
_context.logger.debug("'" + property + "' is null or was not found in the configuration object");
}
return prop;
} else {
// Return the entire configration object
return _config;
}
};
};
video.utils.Logger = video.utils.Logger || function (config) {
var _config, _name, _enabled;
var getDate = function () {
var currentDate = new Date();
return currentDate.getHours() + ":" + currentDate.getMinutes() + ":" + currentDate.getSeconds() + "." + currentDate.getMilliseconds();
};
this.log = function (msg, obj) {
if (_enabled) {
if (typeof (obj) != "undefined") {
console.log(getDate() + " |", _name, msg + " |", obj);
} else {
console.log(getDate() + " |", _name, msg);
}
}
};
this.debug = function (msg, obj) {
if (_enabled) {
if (console.debug != null) {
if (typeof (obj) != "undefined") {
console.debug(getDate() + " |", _name, msg + " |", obj);
} else {
console.debug(getDate() + " |", _name, msg);
}
} else {
// The browser (IE) does not support debug, log it instead
this.log(msg, obj);
}
}
};
this.info = function (msg, obj) {
if (_enabled) {
if (typeof (obj) != "undefined") {
console.info(getDate() + " |", _name, msg + " |", obj);
} else {
console.info(getDate() + " |", _name, msg);
}
}
};
this.warn = function (msg, obj) {
if (_enabled) {
if (typeof (obj) != "undefined") {
console.warn(getDate() + " |", _name, msg + " |", obj);
} else {
console.warn(getDate() + " |", _name, msg);
}
}
};
this.error = function (msg, obj) {
if (_enabled) {
if (typeof (obj) != "undefined") {
console.error(getDate() + " |", _name, msg + " |", obj);
} else {
console.error(getDate() + " |", _name, msg);
}
}
};
(function () {
_config = $.extend(
true,
{
// default settings
enabled: false,
name: ""
},
config); // the configuration of the logger
// does console exist? if it doesn't, turn logging off
if (typeof (console) == "undefined") {
_config["enabled"] = false;
} else if (!_config["enabled"]) {
// Has a query string param override been provided? (debugvideo = true)
var queryString = location.href;
queryString = queryString.substr(queryString.indexOf('?') + 1); // remove everything before the ?
queryString = queryString.split('&');
for (var i = 0; i < queryString.length; i++) {
var param = queryString[i].split('=');
if (param[0].toLowerCase() == "debugvideo") {
if (param[1].toLowerCase() == "true") {
_config["enabled"] = true;
}
}
}
}
_enabled = _config["enabled"];
_name = ((_config["name"] != "") ? _config["name"] + " |" : "");
})();
};
video.utils.sbk = video.utils.sbk = {
/// <summary>Tools used by SBK sites to help make the transition to the new framework easier</summary>
createTrackingObject: function () {
/// <summary>Creates a new ninemsn.portal.common.video.player.tracking object useing the settings supplied on the SBK site</summary>
var _category = "unknown";
var _site = "unknown";
var _section = "unknown";
if (typeof (window.ninemsn.thirdParty) != "undefined") {
// Get the values from the new 3rd party header kit
_category = window.ninemsn.thirdParty.ThirdPartyModule.getOmnitureCategory();
_site = window.ninemsn.thirdParty.ThirdPartyModuleConfig.getSiteName();
_section = window.ninemsn.thirdParty.ThirdPartyModuleConfig.getSectionName();
}
else {
// Get the values from the site settings
if (typeof (window._nmsnOCategory) != "undefined" && window._nmsnOCategory.search("msnportalaucat") == 0) {
window.JS_OMNTR_CATEGORY = window._nmsnOCategory.split(',')[0].substr(14);
}
if (typeof (window.JS_OMNTR_CATEGORY) != 'undefined' && window.JS_OMNTR_CATEGORY != '') {
_category = JS_OMNTR_CATEGORY;
}
if (typeof (window.JS_OMNTR_SITE) != "undefined" && window.JS_OMNTR_SITE != "") {
_site = window.JS_OMNTR_SITE;
}
else if (typeof (window.JS_SITE) != "undefined" && window.JS_SITE != "") {
_site = window.JS_SITE;
}
else if (typeof (window._nmsnSite) != "undefined" && window._nmsnSite != "") {
_site = window._nmsnSite;
}
if (typeof (window.JS_OMNTR_VIDEO_SECTION) != "undefined" && window.JS_OMNTR_VIDEO_SECTION != "") {
_section = window.JS_OMNTR_VIDEO_SECTION;
}
else if (typeof (window.JS_OMNTR_SECTION) != "undefined" && window.JS_OMNTR_SECTION != "") {
_section = window.JS_OMNTR_SECTION;
}
else if (typeof (window.JS_SECTION) != "undefined" && window.JS_SECTION != "") {
_section = window.JS_SECTION;
}
else if (typeof (window._nmsnSection) != "undefined" && window._nmsnSection != "") {
_section = window._nmsnSection;
}
}
return {
category: _category,
site: _site,
section: _section,
//subSection: "",
hierarchy: [_category, _site, _section]
};
}
};
video.utils.msn = video.utils.msn || {
getAccountFromMarket: function (mkt) {
var _translations = {
market: {
"en-au": video.enumerations.account.ninemsn,
"en-nz": video.enumerations.account.msnNZ,
"alt2-en-au": video.enumerations.account.ninemsnCatchup,
"alt-en-au": video.enumerations.account.thirdParty
}
};
return _translations.market.hasOwnProperty(mkt) ? _translations.market[mkt] : null;
},
getMarketFromAccount: function (acc) {
var _translations = {
account: {
ninemsn: "en-au",
msnNZ: "en-nz",
ninemsnCatchup: "alt2-en-au",
thirdParty: "alt-en-au"
}
};
return _translations.account.hasOwnProperty(acc) ? _translations.account[acc] : null;
}
};
video.utils.GetTargetString = video.utils.GetTargetString || function () {
var radCallUrl = 'http://rad.msn.com/ADSAdClient31.dll?GetAd=&PG=MSVFOO';
var result = { ads: { freewheel: { keyValues: ''}} };
var dfd = $.Deferred();
var parseString = function(inputString, keyToFind, separator) {
if (inputString != null) {
var c = inputString.toLowerCase().indexOf(keyToFind.toLowerCase() + "=");
if (c != -1) {
c += keyToFind.length + 1;
var b = inputString.indexOf(separator, c);
b = b == -1 ? inputString.length : b;
return inputString.substring(c, b);
}
}
return "";
},
getParameterString = function() {
var cookie = document.cookie,
mhValue = escape(parseString(cookie, "mh", ";")),
parameterString = mhValue != "" ? "&PN=" + mhValue : "",
anonValue = escape(parseString(parseString(cookie, "ANON", ";"), "A", "&")),
muidValue = escape(parseString(cookie, "MUID", ";"));
if (anonValue == "") anonValue = muidValue;
parameterString += anonValue != "" ? "&ID=" + anonValue : "";
parameterString += muidValue != "" ? "&MUID=" + muidValue : "";
return parameterString;
};
// Reject after 4 seconds, and return empty obj
setTimeout(function () { dfd.reject({}); }, 4000);
// Resolve ajax get rad call content
$.get(radCallUrl + getParameterString(), function (data) {
result.ads.freewheel.keyValues = '_fw_ekv=' + '1:' + data.substring(4);
dfd.resolve(result);
});
return dfd.promise();
};
video.Widget = video.Widget || function (widgetConfig) {
/// <summary>Creates a new ninemsn.portal.common.video.widget object</summary>
/// <param name="config" optional="true" type="Object"></param>
/// <returns type="ninemsn.portal.common.video.widget" />
// Ensure we are working with an instance of the object
var _context = (this instanceof video.Widget) ? this : new video.Widget(widgetConfig);
// the widget as a jQuery object, all events are attached to this
var _widget;
// stores the widget adapter object
var _adapter;
// stores the config object
var _config;
_context.on = function (event, handler) {
/// <summary>
/// Attach an event handler function for one or more events to the selected elements.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false.</param>
_context.logger.debug("on", { event: event, handler: handler });
// As of jQuery 1.7, the .on() method is the preferred method for attaching event handlers to a document
// If .on() is support use it, otherwise use the old .bind() method
if (typeof (_widget.on) != "undefined") {
_widget.on(event, handler);
} else {
_widget.bind(event, handler);
}
};
_context.one = function (event, handler) {
/// <summary>
/// Attach a handler to an event for the elements. The handler is executed at most once per element.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A function to execute when the event is triggered. The value false is also allowed as a shorthand for a function that simply does return false.</param>
_context.logger.debug("one", { event: event, handler: handler });
// Executes once and then removes itself
_widget.one(event, handler);
};
_context.off = function (event, handler) {
/// <summary>
/// Remove an event handler.
/// </summary>
/// <param name="event" type="String">One or more space-separated event types, such as "video:loaded" or "ad:paused".</param>
/// <param name="handler" type="Function">A handler function previously attached for the event(s), or the special value false.</param>
_context.logger.debug("off", { event: event, handler: handler });
// As of jQuery 1.7, the .off() method is the preferred method for removing event handlers
// If .off() is support use it, otherwise use the old .unbind() method
if (typeof (_widget.off) != "undefined") {
_widget.off(event, handler);
} else {
_widget.unbind(event, handler);
}
};
_context.trigger = function (event, data) {
/// <summary>
/// Execute all handlers and behaviours attached to the matched elements for the given event object.
/// </summary>
/// <param name="event" type="String">The event type, such as "video:loaded" or "ad:paused".</param>
/// <param name="data" optional="true" type="Object">Additional data passed to the event handler as additional arguments</param>
_context.logger.log(event, data);
_widget.trigger(event, data);
};
_context.send = function (type, value) {
/// <summary>
/// Sends a message to the inner object.
/// </summary>
/// <param name="type" type="String">The type of message to send, such as “PLAY”</param>
/// <param name="value" optional="true" type="Object">The value to send with the message</param>
_context.logger.log("send", { type: type, value: value });
if (_adapter.send != null) {
_adapter.send(type, value);
} else {
_context.logger.warn(_context.config("type") + " does not implement 'send'");
}
};
_context.get = function (property) {
/// <summary>
/// Get the value of the given property.
/// </summary>
/// <param name="property" type="String">The property to return, such as “VOLUME”</param>
_context.logger.log("get", property);
if (_adapter.get != null) {
return _adapter.get(property);
} else {
_context.logger.warn(_context.config("type") + " does not implement 'get'");
return null;
}
};
_context.dispose = function () {
/// <summary>
/// In addition to the element itself, all bound events and data associated with the element is removed.
/// </summary>
_context.logger.debug("is being disposed of");
if (_adapter.dispose != null) {
_adapter.dispose();
}
_widget.empty();
// Remove from the list of object
delete video.objects[_config["outputLocation"]];
_widget = null;
_adapter = null;
_config = null;
_context = null;
};
(function () {
// Merge the default settings with the supplied configuration
_config = $.extend(true, _config, widgetConfig);
// Create a new config getter
_context.config = new video.utils.Config(_context, _config);
// Attach the logger object
_context.logger = new video.utils.Logger(
$.extend(
true,
{
name: (function () {
return "ninemsn.portal.common.video.Widget | " + _context.config("outputLocation");
})()
},
_context.config("logger")
)
);
// Get the player as a jQuery object
_widget = $("#" + _context.config("outputLocation"));
// init the widget
if (_widgets.hasOwnProperty(_config["type"])) {
_adapter = new _widgets[_config["type"]](_context);
} else {
_context.logger.error("'" + _config["type"] + "' is an unknown Widget type");
}
// add it to the list of video objects on the page
video.objects[_config["outputLocation"]] = _context;
})();
};
var _widgets = _widgets || {
/// <summary>Namespace for nineemsn video widdgets</summary>
};
_widgets[video.enumerations.widget.type.list] = _widgets[video.enumerations.widget.type.list] || function (widgetContext) {
var _context = widgetContext;
var _config = $.extend(
true,
{
// default settings
baseURL: "/videos/?videoid=",
target: "_self",
descriptionLength: 35,
image: { width: 128, height: 72, defaultSrc: "http://shared.9msn.com.au/share/img/videoindex/thumb_default_AU.jpg" }
},
_context.config("list")); // the configuration of the widget
var _data, _dataAdapter;
var render = function () {
var output = "<ul class=\"videoList\">\n";
for (var i = 0; i < _data.videos.length; i++) {
var videoItem = _data.videos[i];
if (videoItem.hasOwnProperty("image")) {
videoItem.image = videoItem.image(_config["image"].width, _config["image"].height);
} else {
videoItem.image = _config["image"].defaultSrc;
}
// Build the video link
var videoLink = _config["baseURL"] + videoItem.id;
// Append the src param to the video link
videoLink += (videoLink.indexOf('?') == -1) ? '?' : '&';
videoLink += "src=widget:list";
output += "<li id=\"" + _context.config("outputLocation") + "_" + videoItem.id + "\">" +
"<a href=\"" + videoLink + "\" title='" + videoItem.title + "' target='" + _config["target"] + "'>" +
"<img src=\"" + videoItem.image + "\" style=\"width: " + _config["image"].width + "px; height: " + _config["image"].height + "px\" />" +
"<p>" +
((videoItem.title.length > _config["descriptionLength"]) ? videoItem.title.substr(0, _config["descriptionLength"] - 3) + "..." : videoItem.title.substr(0, _config["descriptionLength"])) +
"</p>" +
"</a>" +
"</li>\n";
}
output += "</ul>\n";
$("#" + _context.config("outputLocation")).html(output);
// Raise the loaded event
_context.trigger("widget:loaded");
};
(function () {
// Raise the loading event
_context.trigger("widget:loading");
// Get the data and display the list
if (_context.config("data") instanceof Array) {
// The data has been supplied, render the list using this information
_data = _context.config("data");
render();
} else {
// Get the data using the supplied settings
_dataAdapter = new video.Data(
$.extend(
true,
{
success: function (data) {
_data = data;
render();
}
},
_context.config("data")
)
);
}
})();
};
_widgets[video.enumerations.widget.type.leadWithImage] = _widgets[video.enumerations.widget.type.leadWithImage] || function (widgetContext) {
var _context = widgetContext;
var _config = $.extend(
true,
{
// default settings
descriptionLength: 220,
displayMetaData: true,
displayPlayButton: true,
createPlayerOnLoad: true,
width: 640,
height: 360,
strings: {
clickToPlay: "Click to Play Video"
}
},
_context.config("leadWithImage")); // the configuration of the widget
var _data, _dataAdapter, _videoPlayer;
// Render the widget
var render = function () {
// Get the first item only (incase multiple were returned)
if (_data.videos instanceof Array) {
_data = _data.videos[0];
}
// Inherit the width/height
_config["image"] = _config["image"] || {};
_config.image["width"] = _config.image["width"] || _config["width"];
_config.image["height"] = _config.image["height"] || _config["width"];
// / Inherit the width/height
// Set the image width/height
var image = _data.image(_config["image"].width, _config["image"].height);
var output = "<div class=\"video_widget_leadWithImage\" style=\"background-image: url('" + image + "'); width: " + _config["width"] + "px; height: " + _config["height"] + "px;\" title=\"" + _config.strings["clickToPlay"] + "\">\n";
if (_config["displayPlayButton"]) {
output += "<div class=\"play\"></div>\n";
}
if (_config["displayMetaData"]) {
output += "<div class=\"metaBackground\"></div>\n" +
"<div class=\"meta\">\n" +
"<h2>" + _data.title + "</h2>\n" +
(_config["descriptionLength"] > 0 ?
("<p>" + ((_data.description.length > _config["descriptionLength"]) ? _data.description.substr(0, _config["descriptionLength"] - 3) + "..." : _data.description.substr(0, _config["descriptionLength"])) + "</p>\n")
: "") +
"</div>\n";
}
output += "</div>\n";
// Attach the click event
$("#" + _context.config("outputLocation")).html(output).find("div.video_widget_leadWithImage").click(function () { video.objects[_context.config("outputLocation")].send('PLAY'); });
// Create the player
_videoPlayer = _context.config("player");
if (_config["createPlayerOnLoad"]) {
createPlayer();
}
// Ensure the widget is visible
$("#" + _context.config("outputLocation")).show();
// Raise the loaded event
_context.trigger("widget:loaded");
};
var createPlayer = function () {
if ((_videoPlayer == null) || !(_videoPlayer instanceof video.Player)) {
// Render the player output location
var playerOutputLocation = _context.config("outputLocation") + "_player";
if ($("#" + playerOutputLocation).length == 0) {
var output = "<div id=\"" + playerOutputLocation + "\"></div>";
$(output).insertAfter("#" + _context.config("outputLocation"));
}
if (_videoPlayer == null) {
// Use the widget's data object
_videoPlayer = {
width: _config["width"],
height: _config["height"],
data: _context.config("data")
};
}
// Create a new player
// set the output location to the widgets output location (with a _player suffix)
_videoPlayer.outputLocation = _context.config("outputLocation") + "_player";
// Render the player
_videoPlayer.autoPlay = false; // ensure the video does not start playing in the background
_videoPlayer = new video.Player(_videoPlayer);
$("#" + _context.config("outputLocation") + "_player").width(0).height(0);
// Raise a player:created event, allowing other the events to be bound
_context.trigger("player:created", _videoPlayer);
}
};
var showPlayer = function () {
$("#" + _context.config("outputLocation")).hide(); // Hide the lead with image widget
// Show the player
$("#" + _videoPlayer.config("outputLocation")).width(_videoPlayer.config("width")).height(_videoPlayer.config("height"));
// Play the video
if (_videoPlayer.get("STATUS") == "video:loaded") {
// The video is ready, play the video
_videoPlayer.send("PLAY");
} else {
// the video isn't ready yet, when is it ready play the video
_videoPlayer.one("video:loaded", function () {
_videoPlayer.send("PLAY");
});
}
};
this.send = function (type, param) {
var types = {
PLAY: function () {
if (_videoPlayer instanceof video.Player) {
// Show the player
showPlayer();
} else {
// Attach an event tp show the player (once it has been created)
_context.on("player:created", showPlayer);
// Create the player
createPlayer();
}
}
};
if (types.hasOwnProperty(type)) {
types[type](param);
}
};
this.dispose = function () {
if (_videoPlayer != null) {
_videoPlayer.dispose();
}
if (_dataAdapter != null) {
_dataAdapter.dispose();
}
};
(function () {
// Raise the loading event
_context.trigger("widget:loading");
// Get the data and display the list
if (_context.config("data.videos") != null && _context.config("data.videos") instanceof Array) {
// The data has been supplied, render the list using this information
_data = _context.config("data");
render();
} else {
// Get the data using the supplied settings
_dataAdapter = new video.Data(
$.extend(
true,
{
success: function (data) {
_data = data;
render();
}
},
_context.config("data")
)
);
}
})();
};
_widgets[video.enumerations.widget.type.playlist] = _widgets[video.enumerations.widget.type.playlist] || function (widgetContext) {
var _context = widgetContext;
var _config = $.extend(
true,
{
// default settings
addDefaultVideo: true,
removeDuplicatedVideos: true,
titleLength: 35,
scrollSpeed: 200,
animate: { enabled: true, properties: { opacity: "show" }, duration: "slow" },
iScroll: {
enabled: (navigator.userAgent.toLowerCase().match(/(iphone|ipod|ipad|android)/) != null),
config: {
hScrollbar: false, vScrollbar: false, vScroll: false, momentum: false
}
},
image: { width: 128, height: 72, defaultSrc: "http://shared.9msn.com.au/share/img/videoindex/thumb_default_AU.jpg" },
moreVideos: { enabled: true, link: "/video", target: "_self" },
strings: {
playing: "Currently Viewing",
next: "Up Next",
moreVideos: "Continue viewing other video clips from this site",
arrowLeft: "Scroll Left",
arrowRight: "Scroll Right"
}
},
_context.config("playlist")); // the configuration of the widget
var _data, _dataAdapter, _scroller, _playlistWidth, _itemWidth, _viewableItems;
var _outputLocation = _context.config("outputLocation");
var highlight = function (id) {
// Remove the selected class from all related videos
$("#" + _outputLocation + "_playlist li").removeClass("selected");
// Hide the playing/up next messages
$("#" + _outputLocation + "_playlist li span").text("").hide();
// Highlight the video
$("#" + _outputLocation + "_playlist_" + id).addClass("selected");
$("#" + _outputLocation + "_playlist_" + id + " span").text(_config["strings"].playing).css("display", "block");
// Add the "up next" message to the next item
var nextVideo = $("#" + _outputLocation + "_playlist_" + id).next();
nextVideo = (nextVideo.length > 0) ? nextVideo : $("#" + _outputLocation + "_playlist li:first");
nextVideo = nextVideo.find("span");
nextVideo.text(_config["strings"].next).css("display", "block");
if (_scroller != null) {
_scroller.scrollToElement("#" + _outputLocation + "_playlist_" + id, _config["scrollSpeed"]);
} else {
var videoOffsetLeft = ($("#" + _outputLocation + "_playlist_" + id).length == 1 ? $("#" + _outputLocation + "_playlist_" + id).offset().left : 0);
$("#" + _outputLocation + "_playlist").animate({
scrollLeft: (videoOffsetLeft - $("#" + _outputLocation + "_playlist ul").offset().left)
}, _config["scrollSpeed"]);
}
};
var loadVideo = function (id) {
// Loads a video into the player
var player = _context.config("player");
// Stop the current video
player.send("STOP");
// Load the next video
player.send("LOAD", id);
// Highlight the next video
highlight(id);
// The video won't start playing on it's own, start playing it
player.one("video:loaded", function () {
player.send("PLAY");
});
};
var loadNext = function () {
// Get the id of the current video
var currentVideo = _context.config("player").get("META");
// Get the id of the next video
var nextVideo;
for (var i = 0; i < _data.videos.length && nextVideo == null; i++) {
if (_data.videos[i].id == currentVideo.id) {
var nextVideoIndex = i + 1;
if (nextVideoIndex < _data.videos.length) {
nextVideo = _data.videos[nextVideoIndex];
}
}
}
if (nextVideo == null) {
// Cannot find the next video, play the first video in the list
nextVideo = _data.videos[0];
}
loadVideo(nextVideo.id);
};
// Remove Duplicate videos
var removeDuplicates = function (videos) {
var output = [];
var duplicateFound;
for (var i = 0; i < videos.length; i++) {
duplicateFound = false;
for (var j = 0; j < output.length && !duplicateFound; j++) {
duplicateFound = (videos[i].id == output[j].id);
}
if (!duplicateFound) {
output.push(videos[i]);
}
}
return output;
};
var render = function () {
// remove duplicated videos
if (_config["removeDuplicatedVideos"]) {
_data.videos = removeDuplicates(_data.videos);
}
var output = "<div class=\"video_widget_playlist\">\n" +
"<div id=\"leftArrow\" class=\"arrow\"></div>\n" +
"<div id=\"" + _outputLocation + "_playlist\" class=\"playlist\">\n" +
"<ul>\n";
for (var i = 0; i < _data.videos.length; i++) {
var videoItem = _data.videos[i];
if (videoItem.hasOwnProperty("image")) {
videoItem.image = videoItem.image(_config["image"].width, _config["image"].height);
} else {
videoItem.image = _config["image"].defaultSrc;
}
output +=
"<li id=\"" + _outputLocation + "_playlist_" + videoItem.id + "\" class=\"videoListItem\">\n" +
"<div class=\"outer\">\n" +
"<div class=\"imgWrapper\">\n" +
"<img src=\"" + videoItem.image + "\" width=\"" + _config["image"].width + "\" height=\"" + _config["image"].height + "\" />\n" +
"<span></span>\n" +
"</div>\n" +
"<h3>" + videoItem.title + "</h3>\n" +
/*"<div class=\"description\">\n" +
"<p>" +
((video.title.length > _config["titleLength"]) ? video.title.substr(0, _config["titleLength"] - 3) + "..." : video.title.substr(0, _config["titleLength"])) +
"</p>\n" +
"<span class=\"videoDate\">" + video.date + "</span>\n" +
"<span class=\"videoSource\">News</span>\n" +
"</div>\n" +*/
"</div>\n" +
"</li>\n";
}
if (_config["moreVideos"].enabled) {
// Append the src param
_config["moreVideos"].link += (_config["moreVideos"].link.indexOf('?') == -1) ? '?' : '&';
_config["moreVideos"].link += "src=widget:playlist";
output +=
"<li class=\"moreVideosListItem\">\n" +
"<div class=\"outer moreVideos\">\n" +
"<a href=\"" + _config["moreVideos"].link + "\" target=\"" + _config["moreVideos"].target + "\">" +
"<h3>" + _config["strings"].moreVideos + "</h3>\n" +
"</a\n" +
"</div>\n" +
"</li>\n";
}
output += "</ul>\n" +
"</div>\n" +
"<div id=\"rightArrow\" class=\"arrow\"></div>\n" +
"</div>\n";
// Render the list (animate if the browser is not IE or it is and is >= IE9)
if (_config["animate"] != null && _config["animate"].enabled && !($.browser.msie && $.browser.version < 9)) {
$("#" + _outputLocation).html(output).hide().animate(_config["animate"].properties, _config["animate"].duration);
} else {
$("#" + _outputLocation).html(output);
}
// Attach the click event to the right arrow
$("#" + _outputLocation).find("div#rightArrow").click(function () {
video.objects[_outputLocation].send('SCROLL', 'right');
});
// Attach the click event to the left arrow
$("#" + _outputLocation).find("div#leftArrow").click(function () {
video.objects[_outputLocation].send('SCROLL', 'left');
});
// Attach click events to all videos in the list
$("#" + _outputLocation).find("#" + _outputLocation + "_playlist li.videoListItem").each(function (index, element) {
var elementId = $(element).attr("id");
if (elementId) {
var videoId = elementId.split("_").pop();
$(element).click(function () {
video.objects[_outputLocation].send('PLAY', videoId);
});
}
});
// Set the width of the playlist
var arrowWidth = $("#" + _outputLocation + " .arrow").width();
var wrapperWidth = $("#" + _outputLocation + "").width();
_playlistWidth = ((wrapperWidth - (arrowWidth * 2)) - 20);
$("#" + _outputLocation + "_playlist").width(_playlistWidth);
_itemWidth = $("#" + _outputLocation + "_playlist ul:first li:first").outerWidth() + 2;
_viewableItems = parseInt(_playlistWidth / _itemWidth);
// Highlight the current video
highlight(_context.config("player").get("META").id);
// Set the width of the inside scroll
$("#" + _outputLocation + "_playlist ul:first").width(
($("#" + _outputLocation + "_playlist ul:first li:first").outerWidth() + 2) * $("#" + _outputLocation + "_playlist ul:first li").length
);
// Ensure iScroll is disabled in IE
if ($.browser.msie) {
_config["iScroll"].enabled = false;
_context.logger.warn("iScroll disabled. iScroll is not supported in IE");
} else if (_config["iScroll"].enabled && typeof (iScroll) != "undefined") {
// ReSharper disable InconsistentNaming
// Name cannot be changes as it's a public library
_scroller = new window.iScroll(_outputLocation + "_playlist", _config["iScroll"].config); // attach the scroll handler
// ReSharper restore InconsistentNaming
_scroller.refresh();
}
// Raise the loaded event
_context.trigger("widget:loaded");
};
this.send = function (type, param) {
var types = {
PLAY: function (id) {
loadVideo(id);
},
SCROLL: function (direction) {
if (_scroller != null) {
if (direction.toLowerCase() == "left") {
_scroller.scrollTo(0 - (_viewableItems * _itemWidth), 0, _config["scrollSpeed"], true);
} else {
_scroller.scrollTo((_viewableItems * _itemWidth), 0, _config["scrollSpeed"], true);
}
_scroller.refresh();
} else {
if (direction.toLowerCase() == "left") {
$("#" + _outputLocation + "_playlist").animate({ scrollLeft: (function () { return "-=" + (_viewableItems * _itemWidth); } ()) }, _config["scrollSpeed"]);
} else {
$("#" + _outputLocation + "_playlist").animate({ scrollLeft: (function () { return "+=" + (_viewableItems * _itemWidth); } ()) }, _config["scrollSpeed"]);
}
}
}
};
if (types.hasOwnProperty(type)) {
types[type](param);
}
};
this.dispose = function () {
if (_scroller != null) {
_scroller.destroy();
_scroller = null;
}
};
(function () {
// Raise the loading event
_context.trigger("widget:loading");
// Attach to the player events
_context.config("player").on("video:playCompleted", loadNext);
// Get the data and display the list
if (_context.config("data") instanceof Array) {
// The data has been supplied, render the playlist
_data = _context.config("data");
if (_config.addDefaultVideo) {
_data.unshift(_context.config("player").get("META"));
}
render();
} else {
// Get the data using the supplied config
_dataAdapter = new video.Data(
$.extend(
true,
{
success: function (data) {
if (_config.addDefaultVideo) {
data.videos.unshift(_context.config("player").get("META"));
}
_data = data;
render();
},
paging: { size: 20 },
msn: {
fileFilter: (function () {
// if the player is in HTML mode only return videos that can be played in that format
return (_context.config("player").get("TYPE") != video.enumerations.player.type.HTML5) ? 80 : 800;
})()
}
},
_context.config("data")
)
);
}
})();
};
_widgets[video.enumerations.widget.type.suggestedVideos] = _widgets[video.enumerations.widget.type.suggestedVideos] ||
function (widgetContext) {
var _context = widgetContext;
var _config = $.extend(
true,
{
// default settings
playVideo: { baseUrl: "/video/?videoid=", target: "_self" },
moreVideos: { enabled: true, link: "/video/", target: "_self" },
strings: { widgetTitle: "Videos You May Like", moreVideos: "+ More Video", playVideo: "Play Video" },
commonWordFilter: [
"the", "be", "to", "of", "and", "a", "in", "that", "have", "i", "it", "for", "not", "on", "with", "he", "as", "you", "do", "at",
"this", "but", "his", "by", "from", "they", "we", "say", "her", "she", "or", "an", "will", "my", "one", "all", "would", "there",
"their", "what", "so", "up", "out", "if", "about", "who", "get", "which", "go", "me", "when", "make", "can", "like", "time", "no",
"just", "him", "know", "take", "person", "into", "year", "your", "good", "some", "could", "them", "see", "other", "than", "then",
"now", "look", "only", "come", "its", "over", "think", "also", "back", "after", "use", "two", "how", "our", "work", "first", "well",
"way", "even", "new", "want", "because", "any", "these", "give", "day", "most", "us", "is", "didnt", "dont", "off", "where", "not",
"was", "ninemsn"
],
descriptionLength: 50,
image: {
width: 128,
height: 72,
defaultSrc: "http://shared.9msn.com.au/share/img/videoindex/thumb_default_AU.jpg"
}
},
_context.config("suggestedVideos")
); // the configuration of the widget
// determine suggested videos
var filterArray = _config.commonWordFilter;
var _data, _dataAdapter;
// render the videos
var render = function () {
var output = "<div class=\"video_widget_suggestedVideos\">";
output += "<hr />";
output += "<h2>" + _config.strings.widgetTitle + "</h2>";
if (_config.moreVideos.enabled) {
// Append the src param
_config.moreVideos.link += (_config.moreVideos.link.indexOf('?') === -1) ? '?' : '&';
_config.moreVideos.link += "src=widget:suggestedVideos";
output += "<span id=\"moreVideos\"><a class=\"more_link\" href=\"" + _config.moreVideos.link
+ "\" target=\"" + _config.moreVideos.target + "\">" + _config.strings.moreVideos + "</a></span>";
}
output += "<ul>\n";
var i;
for (i = 0; i < _data.videos.length; i += 1) {
var videoItem = _data.videos[i];
if (videoItem.hasOwnProperty("image")) {
videoItem.image = videoItem.image(_config.image.width, _config.image.height);
} else {
videoItem.image = _config.image.defaultSrc;
}
// Build the video link
var videoLink = _config.playVideo.baseUrl + videoItem.id;
// Append the src param to the video link
videoLink += (videoLink.indexOf('?') === -1) ? '?' : '&';
videoLink += "src=widget:suggestedVideos";
output += "<li id=\"" + _context.config("outputLocation") + "_" + videoItem.id + "\">" +
"<div class=\"imageItem\">" +
"<a href=\"" + videoLink + "\" title=\"" + videoItem.title + "\" target='" + _config.playVideo.target
+ "'>" +
"<img src=\"" + videoItem.image + "\" />" +
"</a>" +
"<div class=\"overlay\"><a href=\"" + videoLink + "\" target='" + _config.playVideo.target + "'>"
+ _config.strings.playVideo + "</a></div>" +
"</div>" +
"<a href=\"" + videoLink + "\" class=\"videoText\" target='" + _config.playVideo.target + "'>" +
((videoItem.title.length > _config.descriptionLength)
? videoItem.title.substr(0, _config.descriptionLength - 3) + "..."
: videoItem.title.substr(0, _config.descriptionLength)) +
"</a>" +
"</li>\n";
}
output += "</ul>\n";
output += "<hr /></div>";
$("#" + _context.config("outputLocation")).html(output);
// Raise the loaded event
_context.trigger("widget:loaded");
};
// determin if array has a particular value
var arrHasValue = function (arrayToFind, valueToCompare) {
var result = false;
var i;
for (i = 0; i < arrayToFind.length; i += 1) {
if (arrayToFind[i] === valueToCompare) {
result = true;
}
}
return result;
};
// return unique element array from joining two arrays
var returnUnionFromArrs = function (arr1, arr2) {
var arr = [];
var x, i;
for (x = 0; x < arr2.length; x += 1) {
arr.push(arr2[x]);
}
for (i = 0; i < arr1.length; i += 1) {
if (!arrHasValue(arr, arr1[i])) {
arr.push(arr1[i]);
}
}
return arr;
};
// return common element array from two arrays
var returnCommonFromArrs = function (arr1, arr2, union) {
union = (typeof union === "undefined") ? true : union;
var arr = [];
var i;
for (i = 0; i < arr1.length; i += 1) {
if (arrHasValue(arr2, arr1[i])) {
arr.push(arr1[i]);
}
}
if (arr.length < 2 && union) {
arr = returnUnionFromArrs(arr1, arr2);
}
return arr;
};
// build array from string, filtered by word filter
var buildArrByString = function (arr, fullString) {
fullString = fullString.replace(/[,|.|;|!|:|'|-|\$]/g, ' ');
var tempTags = fullString.split(' ');
var k;
for (k = 0; k < tempTags.length; k += 1) {
if (tempTags[k].length > 0) {
if (!arrHasValue(arr, tempTags[k]) && tempTags[k].length > 1) {
arr.push(tempTags[k].toLowerCase());
}
}
}
if (arr.length > 0) {
removeItems(arr, filterArray);
}
return arr;
};
// get the keyword
var getPageKeyword = function () {
var tagArray = [],
titleArray = [],
keywordArray = [],
descriptionArray = [],
commonArray1,
commonArray2,
commonArray3,
unionArray;
var tagVar = "", tagArrVar, match, metadata, result = "";
// Get ninemsn sbk Tags
var j, y;
for (j = 1; j <= 10; j += 1) {
if (typeof (window['JS_TAGGING_TAGS_' + j]) !== "undefined") {
tagArrVar = window['JS_TAGGING_TAGS_' + j].split("~");
for (y = 0; y < tagArrVar.length; y += 1) {
match = tagArrVar[y].split("|");
if (typeof match[1] !== "undefined") {
tagVar += match[1] + " ";
}
}
}
}
tagArray = buildArrByString(tagArray, tagVar);
// Get Title Array
titleArray = buildArrByString(titleArray, $("title").html());
// Get Keywords/discription array
metadata = document.getElementsByTagName("meta");
var i;
for (i = 0; i < metadata.length; i += 1) {
switch (metadata[i].name) {
case 'keywords':
keywordArray = buildArrByString(keywordArray, metadata[i].content);
break;
case 'description':
descriptionArray = buildArrByString(descriptionArray, metadata[i].content);
break;
}
}
commonArray1 = returnCommonFromArrs(titleArray, keywordArray, (tagArray.length === 0));
commonArray2 = returnCommonFromArrs(titleArray, descriptionArray, false);
commonArray3 = returnCommonFromArrs(keywordArray, descriptionArray, false);
unionArray = returnUnionFromArrs(
returnUnionFromArrs(
returnUnionFromArrs(commonArray1, commonArray2),
returnUnionFromArrs(commonArray1, commonArray3)
),
tagArray
);
// Clear up union array to take down words less than 3 chars if total keywords larger than 2
for (i = unionArray.length - 1; i >= 0; i--) {
var item = unionArray[i];
if (unionArray.length > 2 && item.length < 3) {
removeItems(unionArray, item);
}
}
var r;
for (r = 0; r < unionArray.length; r += 1) {
result += (result === "") ? unionArray[r] : " " + unionArray[r];
}
// Limit query to be less than 100 chars
if (result.length > 100) {
result = result.substring(0, result.substring(0, 100 - 1).lastIndexOf(" "));
}
return result;
};
var removeItems = function (originalArray, itemsToRemove) {
if (!/Array/.test(itemsToRemove.constructor)) {
itemsToRemove = [itemsToRemove];
}
var j, i;
for (i = 0; i < itemsToRemove.length; i += 1) {
j = 0;
while (j < originalArray.length) {
if (originalArray[j] === itemsToRemove[i]) {
originalArray.splice(j, 1);
} else {
j += 1;
}
}
}
};
(function () {
// Raise the loading event
_context.trigger("widget:loading");
// determine the suggested videos
_dataAdapter = new video.Data(
$.extend(
true,
{
success: function (data) {
_data = data;
render();
},
method: video.enumerations.data.method.Search,
filter: {
term: getPageKeyword(),
operator: video.enumerations.data.searchOperator.Any
}
},
_context.config("data")
)
);
} ());
};
/*!
* iScroll v4.1.9 ~ Copyright (c) 2011 Matteo Spinelli, http://cubiq.org
* Released under MIT license, http://cubiq.org/license
*/
(function(){
var m = Math,
mround = function (r) { return r >> 0; },
vendor = (/webkit/i).test(navigator.appVersion) ? 'webkit' :
(/firefox/i).test(navigator.userAgent) ? 'Moz' :
'opera' in window ? 'O' : '',
// Browser capabilities
isAndroid = (/android/gi).test(navigator.appVersion),
isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
isPlaybook = (/playbook/gi).test(navigator.appVersion),
isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
has3d = 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix(),
hasTouch = 'ontouchstart' in window && !isTouchPad,
hasTransform = vendor + 'Transform' in document.documentElement.style,
hasTransitionEnd = isIDevice || isPlaybook,
nextFrame = (function() {
return window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { return setTimeout(callback, 1); }
})(),
cancelFrame = (function () {
return window.cancelRequestAnimationFrame
|| window.webkitCancelRequestAnimationFrame
|| window.mozCancelRequestAnimationFrame
|| window.oCancelRequestAnimationFrame
|| window.msCancelRequestAnimationFrame
|| clearTimeout
})(),
// Events
RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
START_EV = hasTouch ? 'touchstart' : 'mousedown',
MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
END_EV = hasTouch ? 'touchend' : 'mouseup',
CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
WHEEL_EV = vendor == 'Moz' ? 'DOMMouseScroll' : 'mousewheel',
// Helpers
trnOpen = 'translate' + (has3d ? '3d(' : '('),
trnClose = has3d ? ',0)' : ')',
// Constructor
iScroll = function (el, options) {
var that = this,
doc = document,
i;
that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
that.wrapper.style.overflow = 'hidden';
that.scroller = that.wrapper.children[0];
// Default options
that.options = {
hScroll: true,
vScroll: true,
x: 0,
y: 0,
bounce: true,
bounceLock: false,
momentum: true,
lockDirection: true,
useTransform: true,
useTransition: false,
topOffset: 0,
checkDOMChanges: false, // Experimental
// Scrollbar
hScrollbar: true,
vScrollbar: true,
fixedScrollbar: isAndroid,
hideScrollbar: isIDevice,
fadeScrollbar: isIDevice && has3d,
scrollbarClass: '',
// Zoom
zoom: false,
zoomMin: 1,
zoomMax: 4,
doubleTapZoom: 2,
wheelAction: 'scroll',
// Snap
snap: false,
snapThreshold: 1,
// Events
onRefresh: null,
onBeforeScrollStart: function (e) { e.preventDefault(); },
onScrollStart: null,
onBeforeScrollMove: null,
onScrollMove: null,
onBeforeScrollEnd: null,
onScrollEnd: null,
onTouchEnd: null,
onDestroy: null,
onZoomStart: null,
onZoom: null,
onZoomEnd: null
};
// Helpers FIX ANDROID BUG!
// translate3d and scale doesn't work together!
// Ignoring 3d ONLY WHEN YOU SET that.zoom
if ( that.zoom && isAndroid ){
trnOpen = 'translate(';
trnClose = ')';
}
// User defined options
for (i in options) that.options[i] = options[i];
// Set starting position
that.x = that.options.x;
that.y = that.options.y;
// Normalize options
that.options.useTransform = hasTransform ? that.options.useTransform : false;
that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
that.options.zoom = that.options.useTransform && that.options.zoom;
that.options.useTransition = hasTransitionEnd && that.options.useTransition;
// Set some default styles
that.scroller.style[vendor + 'TransitionProperty'] = that.options.useTransform ? '-' + vendor.toLowerCase() + '-transform' : 'top left';
that.scroller.style[vendor + 'TransitionDuration'] = '0';
that.scroller.style[vendor + 'TransformOrigin'] = '0 0';
if (that.options.useTransition) that.scroller.style[vendor + 'TransitionTimingFunction'] = 'cubic-bezier(0.33,0.66,0.66,1)';
if (that.options.useTransform) that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose;
else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
if (that.options.useTransition) that.options.fixedScrollbar = true;
that.refresh();
that._bind(RESIZE_EV, window);
that._bind(START_EV);
if (!hasTouch) {
that._bind('mouseout', that.wrapper);
if (that.options.wheelAction != 'none')
that._bind(WHEEL_EV);
}
if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
that._checkDOMChanges();
}, 500);
};
// Prototype
iScroll.prototype = {
enabled: true,
x: 0,
y: 0,
steps: [],
scale: 1,
currPageX: 0, currPageY: 0,
pagesX: [], pagesY: [],
aniTime: null,
wheelZoomCount: 0,
handleEvent: function (e) {
var that = this;
switch(e.type) {
case START_EV:
if (!hasTouch && e.button !== 0) return;
that._start(e);
break;
case MOVE_EV: that._move(e); break;
case END_EV:
case CANCEL_EV: that._end(e); break;
case RESIZE_EV: that._resize(); break;
case WHEEL_EV: that._wheel(e); break;
case 'mouseout': that._mouseout(e); break;
case 'webkitTransitionEnd': that._transitionEnd(e); break;
}
},
_checkDOMChanges: function () {
if (this.moved || this.zoomed || this.animating ||
(this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
this.refresh();
},
_scrollbar: function (dir) {
var that = this,
doc = document,
bar;
if (!that[dir + 'Scrollbar']) {
if (that[dir + 'ScrollbarWrapper']) {
if (hasTransform) that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = '';
that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
that[dir + 'ScrollbarWrapper'] = null;
that[dir + 'ScrollbarIndicator'] = null;
}
return;
}
if (!that[dir + 'ScrollbarWrapper']) {
// Create the scrollbar wrapper
bar = doc.createElement('div');
if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px');
bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:opacity;-' + vendor + '-transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1');
that.wrapper.appendChild(bar);
that[dir + 'ScrollbarWrapper'] = bar;
// Create the scrollbar indicator
bar = doc.createElement('div');
if (!that.options.scrollbarClass) {
bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);-' + vendor + '-background-clip:padding-box;-' + vendor + '-box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';-' + vendor + '-border-radius:3px;border-radius:3px';
}
bar.style.cssText += ';pointer-events:none;-' + vendor + '-transition-property:-' + vendor + '-transform;-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);-' + vendor + '-transition-duration:0;-' + vendor + '-transform:' + trnOpen + '0,0' + trnClose;
if (that.options.useTransition) bar.style.cssText += ';-' + vendor + '-transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
that[dir + 'ScrollbarWrapper'].appendChild(bar);
that[dir + 'ScrollbarIndicator'] = bar;
}
if (dir == 'h') {
that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
that.hScrollbarIndicatorSize = m.max(mround(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
} else {
that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
that.vScrollbarIndicatorSize = m.max(mround(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
}
// Reset position
that._scrollbarPos(dir, true);
},
_resize: function () {
var that = this;
setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
},
_pos: function (x, y) {
x = this.hScroll ? x : 0;
y = this.vScroll ? y : 0;
if (this.options.useTransform) {
this.scroller.style[vendor + 'Transform'] = trnOpen + x + 'px,' + y + 'px' + trnClose + ' scale(' + this.scale + ')';
} else {
x = mround(x);
y = mround(y);
this.scroller.style.left = x + 'px';
this.scroller.style.top = y + 'px';
}
this.x = x;
this.y = y;
this._scrollbarPos('h');
this._scrollbarPos('v');
},
_scrollbarPos: function (dir, hidden) {
var that = this,
pos = dir == 'h' ? that.x : that.y,
size;
if (!that[dir + 'Scrollbar']) return;
pos = that[dir + 'ScrollbarProp'] * pos;
if (pos < 0) {
if (!that.options.fixedScrollbar) {
size = that[dir + 'ScrollbarIndicatorSize'] + mround(pos * 3);
if (size < 8) size = 8;
that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
}
pos = 0;
} else if (pos > that[dir + 'ScrollbarMaxScroll']) {
if (!that.options.fixedScrollbar) {
size = that[dir + 'ScrollbarIndicatorSize'] - mround((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
if (size < 8) size = 8;
that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
} else {
pos = that[dir + 'ScrollbarMaxScroll'];
}
}
that[dir + 'ScrollbarWrapper'].style[vendor + 'TransitionDelay'] = '0';
that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
that[dir + 'ScrollbarIndicator'].style[vendor + 'Transform'] = trnOpen + (dir == 'h' ? pos + 'px,0' : '0,' + pos + 'px') + trnClose;
},
_start: function (e) {
var that = this,
point = hasTouch ? e.touches[0] : e,
matrix, x, y,
c1, c2;
if (!that.enabled) return;
if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
that.moved = false;
that.animating = false;
that.zoomed = false;
that.distX = 0;
that.distY = 0;
that.absDistX = 0;
that.absDistY = 0;
that.dirX = 0;
that.dirY = 0;
// Gesture start
if (that.options.zoom && hasTouch && e.touches.length > 1) {
c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x;
that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y;
if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
}
if (that.options.momentum) {
if (that.options.useTransform) {
// Very lame general purpose alternative to CSSMatrix
matrix = getComputedStyle(that.scroller, null)[vendor + 'Transform'].replace(/[^0-9-.,]/g, '').split(',');
x = matrix[4] * 1;
y = matrix[5] * 1;
} else {
x = getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '') * 1;
y = getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '') * 1;
}
if (x != that.x || y != that.y) {
if (that.options.useTransition) that._unbind('webkitTransitionEnd');
else cancelFrame(that.aniTime);
that.steps = [];
that._pos(x, y);
}
}
that.absStartX = that.x; // Needed by snap threshold
that.absStartY = that.y;
that.startX = that.x;
that.startY = that.y;
that.pointX = point.pageX;
that.pointY = point.pageY;
that.startTime = e.timeStamp || Date.now();
if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
that._bind(MOVE_EV);
that._bind(END_EV);
that._bind(CANCEL_EV);
},
_move: function (e) {
var that = this,
point = hasTouch ? e.touches[0] : e,
deltaX = point.pageX - that.pointX,
deltaY = point.pageY - that.pointY,
newX = that.x + deltaX,
newY = that.y + deltaY,
c1, c2, scale,
timestamp = e.timeStamp || Date.now();
if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
// Zoom
if (that.options.zoom && hasTouch && e.touches.length > 1) {
c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
that.touchesDist = m.sqrt(c1*c1+c2*c2);
that.zoomed = true;
scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
that.lastScale = scale / this.scale;
newX = this.originX - this.originX * that.lastScale + this.x,
newY = this.originY - this.originY * that.lastScale + this.y;
this.scroller.style[vendor + 'Transform'] = trnOpen + newX + 'px,' + newY + 'px' + trnClose + ' scale(' + scale + ')';
if (that.options.onZoom) that.options.onZoom.call(that, e);
return;
}
that.pointX = point.pageX;
that.pointY = point.pageY;
// Slow down if outside of the boundaries
if (newX > 0 || newX < that.maxScrollX) {
newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
}
if (newY > that.minScrollY || newY < that.maxScrollY) {
newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
}
if (that.absDistX < 6 && that.absDistY < 6) {
that.distX += deltaX;
that.distY += deltaY;
that.absDistX = m.abs(that.distX);
that.absDistY = m.abs(that.distY);
return;
}
// Lock direction
if (that.options.lockDirection) {
if (that.absDistX > that.absDistY + 5) {
newY = that.y;
deltaY = 0;
} else if (that.absDistY > that.absDistX + 5) {
newX = that.x;
deltaX = 0;
}
}
that.moved = true;
that._pos(newX, newY);
that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
if (timestamp - that.startTime > 300) {
that.startTime = timestamp;
that.startX = that.x;
that.startY = that.y;
}
if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
},
_end: function (e) {
if (hasTouch && e.touches.length != 0) return;
var that = this,
point = hasTouch ? e.changedTouches[0] : e,
target, ev,
momentumX = { dist:0, time:0 },
momentumY = { dist:0, time:0 },
duration = (e.timeStamp || Date.now()) - that.startTime,
newPosX = that.x,
newPosY = that.y,
distX, distY,
newDuration,
snap,
scale;
that._unbind(MOVE_EV);
that._unbind(END_EV);
that._unbind(CANCEL_EV);
if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
if (that.zoomed) {
scale = that.scale * that.lastScale;
scale = Math.max(that.options.zoomMin, scale);
scale = Math.min(that.options.zoomMax, scale);
that.lastScale = scale / that.scale;
that.scale = scale;
that.x = that.originX - that.originX * that.lastScale + that.x;
that.y = that.originY - that.originY * that.lastScale + that.y;
that.scroller.style[vendor + 'TransitionDuration'] = '200ms';
that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + that.scale + ')';
that.zoomed = false;
that.refresh();
if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
return;
}
if (!that.moved) {
if (hasTouch) {
if (that.doubleTapTimer && that.options.zoom) {
// Double tapped
clearTimeout(that.doubleTapTimer);
that.doubleTapTimer = null;
if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
if (that.options.onZoomEnd) {
setTimeout(function() {
that.options.onZoomEnd.call(that, e);
}, 200); // 200 is default zoom duration
}
} else {
that.doubleTapTimer = setTimeout(function () {
that.doubleTapTimer = null;
// Find the last touched element
target = point.target;
while (target.nodeType != 1) target = target.parentNode;
if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
ev = document.createEvent('MouseEvents');
ev.initMouseEvent('click', true, true, e.view, 1,
point.screenX, point.screenY, point.clientX, point.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
0, null);
ev._fake = true;
target.dispatchEvent(ev);
}
}, that.options.zoom ? 250 : 0);
}
}
that._resetPos(200);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
if (duration < 300 && that.options.momentum) {
momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
newPosX = that.x + momentumX.dist;
newPosY = that.y + momentumY.dist;
if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
}
if (momentumX.dist || momentumY.dist) {
newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
// Do we need to snap?
if (that.options.snap) {
distX = newPosX - that.absStartX;
distY = newPosY - that.absStartY;
if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
else {
snap = that._snap(newPosX, newPosY);
newPosX = snap.x;
newPosY = snap.y;
newDuration = m.max(snap.time, newDuration);
}
}
that.scrollTo(mround(newPosX), mround(newPosY), newDuration);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
// Do we need to snap?
if (that.options.snap) {
distX = newPosX - that.absStartX;
distY = newPosY - that.absStartY;
if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
else {
snap = that._snap(that.x, that.y);
if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
}
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
that._resetPos(200);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
},
_resetPos: function (time) {
var that = this,
resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
if (resetX == that.x && resetY == that.y) {
if (that.moved) {
that.moved = false;
if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end
}
if (that.hScrollbar && that.options.hideScrollbar) {
if (vendor == 'webkit') that.hScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms';
that.hScrollbarWrapper.style.opacity = '0';
}
if (that.vScrollbar && that.options.hideScrollbar) {
if (vendor == 'webkit') that.vScrollbarWrapper.style[vendor + 'TransitionDelay'] = '300ms';
that.vScrollbarWrapper.style.opacity = '0';
}
return;
}
that.scrollTo(resetX, resetY, time || 0);
},
_wheel: function (e) {
var that = this,
wheelDeltaX, wheelDeltaY,
deltaX, deltaY,
deltaScale;
if ('wheelDeltaX' in e) {
wheelDeltaX = e.wheelDeltaX / 12;
wheelDeltaY = e.wheelDeltaY / 12;
} else if ('detail' in e) {
wheelDeltaX = wheelDeltaY = -e.detail * 3;
} else {
wheelDeltaX = wheelDeltaY = -e.wheelDelta;
}
if (that.options.wheelAction == 'zoom') {
deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
if (deltaScale != that.scale) {
if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
that.wheelZoomCount++;
that.zoom(e.pageX, e.pageY, deltaScale, 400);
setTimeout(function() {
that.wheelZoomCount--;
if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
}, 400);
}
return;
}
deltaX = that.x + wheelDeltaX;
deltaY = that.y + wheelDeltaY;
if (deltaX > 0) deltaX = 0;
else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
if (deltaY > that.minScrollY) deltaY = that.minScrollY;
else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
that.scrollTo(deltaX, deltaY, 0);
},
_mouseout: function (e) {
var t = e.relatedTarget;
if (!t) {
this._end(e);
return;
}
while (t = t.parentNode) if (t == this.wrapper) return;
this._end(e);
},
_transitionEnd: function (e) {
var that = this;
if (e.target != that.scroller) return;
that._unbind('webkitTransitionEnd');
that._startAni();
},
/**
*
* Utilities
*
*/
_startAni: function () {
var that = this,
startX = that.x, startY = that.y,
startTime = Date.now(),
step, easeOut,
animate;
if (that.animating) return;
if (!that.steps.length) {
that._resetPos(400);
return;
}
step = that.steps.shift();
if (step.x == startX && step.y == startY) step.time = 0;
that.animating = true;
that.moved = true;
if (that.options.useTransition) {
that._transitionTime(step.time);
that._pos(step.x, step.y);
that.animating = false;
if (step.time) that._bind('webkitTransitionEnd');
else that._resetPos(0);
return;
}
animate = function () {
var now = Date.now(),
newX, newY;
if (now >= startTime + step.time) {
that._pos(step.x, step.y);
that.animating = false;
if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end
that._startAni();
return;
}
now = (now - startTime) / step.time - 1;
easeOut = m.sqrt(1 - now * now);
newX = (step.x - startX) * easeOut + startX;
newY = (step.y - startY) * easeOut + startY;
that._pos(newX, newY);
if (that.animating) that.aniTime = nextFrame(animate);
};
animate();
},
_transitionTime: function (time) {
time += 'ms';
this.scroller.style[vendor + 'TransitionDuration'] = time;
if (this.hScrollbar) this.hScrollbarIndicator.style[vendor + 'TransitionDuration'] = time;
if (this.vScrollbar) this.vScrollbarIndicator.style[vendor + 'TransitionDuration'] = time;
},
_momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
var deceleration = 0.0006,
speed = m.abs(dist) / time,
newDist = (speed * speed) / (2 * deceleration),
newTime = 0, outsideDist = 0;
// Proportinally reduce speed if we are outside of the boundaries
if (dist > 0 && newDist > maxDistUpper) {
outsideDist = size / (6 / (newDist / speed * deceleration));
maxDistUpper = maxDistUpper + outsideDist;
speed = speed * maxDistUpper / newDist;
newDist = maxDistUpper;
} else if (dist < 0 && newDist > maxDistLower) {
outsideDist = size / (6 / (newDist / speed * deceleration));
maxDistLower = maxDistLower + outsideDist;
speed = speed * maxDistLower / newDist;
newDist = maxDistLower;
}
newDist = newDist * (dist < 0 ? -1 : 1);
newTime = speed / deceleration;
return { dist: newDist, time: mround(newTime) };
},
_offset: function (el) {
var left = -el.offsetLeft,
top = -el.offsetTop;
while (el = el.offsetParent) {
left -= el.offsetLeft;
top -= el.offsetTop;
}
if (el != this.wrapper) {
left *= this.scale;
top *= this.scale;
}
return { left: left, top: top };
},
_snap: function (x, y) {
var that = this,
i, l,
page, time,
sizeX, sizeY;
// Check page X
page = that.pagesX.length - 1;
for (i=0, l=that.pagesX.length; i<l; i++) {
if (x >= that.pagesX[i]) {
page = i;
break;
}
}
if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
x = that.pagesX[page];
sizeX = m.abs(x - that.pagesX[that.currPageX]);
sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
that.currPageX = page;
// Check page Y
page = that.pagesY.length-1;
for (i=0; i<page; i++) {
if (y >= that.pagesY[i]) {
page = i;
break;
}
}
if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
y = that.pagesY[page];
sizeY = m.abs(y - that.pagesY[that.currPageY]);
sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
that.currPageY = page;
// Snap with constant speed (proportional duration)
time = mround(m.max(sizeX, sizeY)) || 200;
return { x: x, y: y, time: time };
},
_bind: function (type, el, bubble) {
(el || this.scroller).addEventListener(type, this, !!bubble);
},
_unbind: function (type, el, bubble) {
(el || this.scroller).removeEventListener(type, this, !!bubble);
},
/**
*
* Public methods
*
*/
destroy: function () {
var that = this;
that.scroller.style[vendor + 'Transform'] = '';
// Remove the scrollbars
that.hScrollbar = false;
that.vScrollbar = false;
that._scrollbar('h');
that._scrollbar('v');
// Remove the event listeners
that._unbind(RESIZE_EV, window);
that._unbind(START_EV);
that._unbind(MOVE_EV);
that._unbind(END_EV);
that._unbind(CANCEL_EV);
if (that.options.hasTouch) {
that._unbind('mouseout', that.wrapper);
that._unbind(WHEEL_EV);
}
if (that.options.useTransition) that._unbind('webkitTransitionEnd');
if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
if (that.options.onDestroy) that.options.onDestroy.call(that);
},
refresh: function () {
var that = this,
offset,
i, l,
els,
pos = 0,
page = 0;
if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
that.wrapperW = that.wrapper.clientWidth || 1;
that.wrapperH = that.wrapper.clientHeight || 1;
that.minScrollY = -that.options.topOffset || 0;
that.scrollerW = mround(that.scroller.offsetWidth * that.scale);
that.scrollerH = mround((that.scroller.offsetHeight + that.minScrollY) * that.scale);
that.maxScrollX = that.wrapperW - that.scrollerW;
that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
that.dirX = 0;
that.dirY = 0;
if (that.options.onRefresh) that.options.onRefresh.call(that);
that.hScroll = that.options.hScroll && that.maxScrollX < 0;
that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
that.hScrollbar = that.hScroll && that.options.hScrollbar;
that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
offset = that._offset(that.wrapper);
that.wrapperOffsetLeft = -offset.left;
that.wrapperOffsetTop = -offset.top;
// Prepare snap
if (typeof that.options.snap == 'string') {
that.pagesX = [];
that.pagesY = [];
els = that.scroller.querySelectorAll(that.options.snap);
for (i=0, l=els.length; i<l; i++) {
pos = that._offset(els[i]);
pos.left += that.wrapperOffsetLeft;
pos.top += that.wrapperOffsetTop;
that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
}
} else if (that.options.snap) {
that.pagesX = [];
while (pos >= that.maxScrollX) {
that.pagesX[page] = pos;
pos = pos - that.wrapperW;
page++;
}
if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
pos = 0;
page = 0;
that.pagesY = [];
while (pos >= that.maxScrollY) {
that.pagesY[page] = pos;
pos = pos - that.wrapperH;
page++;
}
if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
}
// Prepare the scrollbars
that._scrollbar('h');
that._scrollbar('v');
if (!that.zoomed) {
that.scroller.style[vendor + 'TransitionDuration'] = '0';
that._resetPos(200);
}
},
scrollTo: function (x, y, time, relative) {
var that = this,
step = x,
i, l;
that.stop();
if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
for (i=0, l=step.length; i<l; i++) {
if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
}
that._startAni();
},
scrollToElement: function (el, time) {
var that = this, pos;
el = el.nodeType ? el : that.scroller.querySelector(el);
if (!el) return;
pos = that._offset(el);
pos.left += that.wrapperOffsetLeft;
pos.top += that.wrapperOffsetTop;
pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
that.scrollTo(pos.left, pos.top, time);
},
scrollToPage: function (pageX, pageY, time) {
var that = this, x, y;
if (that.options.onScrollStart) that.options.onScrollStart.call(that);
if (that.options.snap) {
pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
that.currPageX = pageX;
that.currPageY = pageY;
x = that.pagesX[pageX];
y = that.pagesY[pageY];
} else {
x = -that.wrapperW * pageX;
y = -that.wrapperH * pageY;
if (x < that.maxScrollX) x = that.maxScrollX;
if (y < that.maxScrollY) y = that.maxScrollY;
}
that.scrollTo(x, y, time || 400);
},
disable: function () {
this.stop();
this._resetPos(0);
this.enabled = false;
// If disabled after touchstart we make sure that there are no left over events
this._unbind(MOVE_EV);
this._unbind(END_EV);
this._unbind(CANCEL_EV);
},
enable: function () {
this.enabled = true;
},
stop: function () {
if (this.options.useTransition) this._unbind('webkitTransitionEnd');
else cancelFrame(this.aniTime);
this.steps = [];
this.moved = false;
this.animating = false;
},
zoom: function (x, y, scale, time) {
var that = this,
relScale = scale / that.scale;
if (!that.options.useTransform) return;
that.zoomed = true;
time = time === undefined ? 200 : time;
x = x - that.wrapperOffsetLeft - that.x;
y = y - that.wrapperOffsetTop - that.y;
that.x = x - x * relScale + that.x;
that.y = y - y * relScale + that.y;
that.scale = scale;
that.refresh();
that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
that.scroller.style[vendor + 'TransitionDuration'] = time + 'ms';
that.scroller.style[vendor + 'Transform'] = trnOpen + that.x + 'px,' + that.y + 'px' + trnClose + ' scale(' + scale + ')';
that.zoomed = false;
},
isReady: function () {
return !this.moved && !this.zoomed && !this.animating;
}
};
if (typeof exports !== 'undefined') exports.iScroll = iScroll;
else window.iScroll = iScroll;
})();
window.ninemsn.portal.common.video.init();
})(ninemsn.portal.common.video.$, ninemsn);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment