gtvzone
Version:
Jquery google tv adapcion, libreria para desarrollo de aplicaciones para smart-TV
559 lines (489 loc) • 18.2 kB
JavaScript
// Copyright 2010 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Common classes used throughout the library. GtvCore contains
* public static methods for processing feeds. SynchronizedCallback
* can be used to aggregate multiple asynch callback events into a single
* call.
*
*/
module.exports = function ($) {
var gtv = {
jq: {}
};
/**
* Static class for utilities used by controls
* @constructor
* @private
*/
gtv.jq.GtvCore = function () {
};
/**
* Triggers a 'load' event on a container when images have finished loading
* @param {jQuery.Element} container Container to trigger after images load.
* If images not supplied, the container will be triggered when images
* in it have finished loading.
* @param {?Array.<jQuery.Element>} images Optional image elements.
* Supply this if container is to be triggered on images that aren't
* descendants of it.
* @private
*/
gtv.jq.GtvCore.triggerOnLoad = function (container, images) {
images = images || container.find('img');
var imgCount = images.length;
if (imgCount == 0) {
container.trigger('load');
return;
}
images.each(function (index) {
if ($(this).complete) {
imgCount--;
if (imgCount == 0) {
container.trigger('load');
}
} else {
images.load(function () {
imgCount--;
if (imgCount == 0) {
container.trigger('load');
}
});
}
});
};
/**
* Creates a function to retrieve the next item from an item parameter,
* which may be a generator function or an array.
* @param {ControlContents} controlContents A ControlContents object with either
* an items attribute or an itemsGenerator attribute set.
* @return {function(jQuery.Element)} A function adds the next item in a
* collection to the supplied container.
* @private
*/
gtv.jq.GtvCore.makeAddNextItemParams = function (controlContents) {
var addNextItem;
if (controlContents.itemsGenerator) {
// If a generator is specified, the return function is a pass-through that
// calls the generator. (This generator creates an item, adds it to the
// parent and returns true; or returns false if it has no item to add.)
addNextItem = function (parent) {
return controlContents.itemsGenerator(parent);
};
} else if (controlContents.items) {
// If an items array is specified, return a function that adds the next
// item in the array to the parent and returns true; or returns false if
// the end of the array has been reached.
var index = 0;
addNextItem = function (parent) {
if (index >= controlContents.items.length) {
return false;
}
var item = controlContents.items[index];
if (!item) {
return false;
}
index++;
parent.append(item);
return true;
};
}
return addNextItem;
};
/**
* Reads a feed in ATOM format and makes callbacks to build an array of
* items from the feed.
* @param {string} feed URL to the feed to read.
* @param {function(Object)} makeItem A callback function that, when passed
* an entry from the feed returns a constructed item from it.
* @param {function(Array.<Object>)} doneCallback A callback that will be passed
* the array of all constructed items.
* @private
*/
gtv.jq.GtvCore.processAtomFeed = function (feed, makeItem, doneCallback) {
$.ajax({
url: feed,
success: function (data) {
var itemsArray = [];
var entries = $(data).find('entry');
for (var i = 0; i < entries.length; i++) {
var item = makeItem(entries[i]);
if (item) {
itemsArray.push(item);
}
}
doneCallback(itemsArray);
}
});
};
/**
* Reads a feed in JSONP format and makes callbacks to build an array of
* items from the feed.
* @param {string} feed URL to the feed to read.
* @param {function(Object)} makeItem A callback function that, when passed
* an entry from the feed returns a constructed item from it.
* @param {function(Array.<Object>)} doneCallback A callback that will be passed
* the array of all constructed items.
* @param {Array.<string>)} entryKey An array of strings that represent, in
* hierarchical order the path to the array of entries in the returned feed.
* @private
*/
gtv.jq.GtvCore.processJsonpFeed = function (feed,
makeItem,
doneCallback,
entryKey) {
entryKey = entryKey || ['feed', 'entry'];
$.ajax({
url: feed,
dataType: 'jsonp',
success: function (data) {
var itemsArray = [];
var entries = data;
for (var j = 0; j < entryKey.length; j++)
entries = entries[entryKey[j]];
for (var i = 0; i < entries.length; i++) {
var item = makeItem(entries[i]);
if (item) {
itemsArray.push(item);
}
}
doneCallback(itemsArray);
}
});
};
gtv.jq.GtvCore.doAjaxCall = function (url, dataType, jsonpCallback, callbackSuccess, callbackError) {
var options = {
url: url,
dataType: dataType,
error: function (httpRequest, textStatus, errorThrown) {
callbackError(errorThrown);
},
success: function (data, textStatus, httpRequest) {
callbackSuccess(data);
}
};
if (dataType == 'jsonp') {
options.jsonpCallback = jsonpCallback;
}
return $.ajax(options);
};
gtv.jq.GtvCore.getZoom = function () {
var zoom = parseFloat($(document.body).css('zoom'));
if (isNaN(zoom)) {
zoom = 1;
}
return zoom;
};
gtv.jq.GtvCore.getInt = function (value) {
value = parseInt(value);
if (isNaN(value)) {
value = 0;
}
return value;
};
gtv.jq.GtvCore.preloadImages = function (images) {
var img = new Image();
for (var i = 0; i < images.length; i++) {
img.src = images[i];
}
};
gtv.jq.GtvCore.formatTime = function (seconds, unit) {
function padCero(num) {
if (num < 10) {
return '0' + num;
}
return num.toString();
}
switch (unit) {
case 'hours':
{
var hours = Math.floor(seconds / 3600);
var minutes = Math.floor(seconds % 3600);
return padCero(hours) + ':' + gtv.jq.GtvCore.formatTime(minutes, 'minutes');
}
case 'minutes':
{
var minutes = Math.floor(seconds / 60);
seconds = Math.floor(seconds % 60);
return padCero(minutes) + ':' + gtv.jq.GtvCore.formatTime(seconds, 'seconds');
}
case 'seconds':
{
return padCero(seconds);
}
}
return padCero(seconds);
};
/**
* A class that tracks by reference count a number of requests for a single
* callback and makes sure that it is called once when all requests are
* completed. The constructor starts the count at 1 and expects this to be
* cleared by the creator calling done().
* @constructor
* @param {function} callback The callback to make when all dependent requests
* are completed.
* @private
*/
gtv.jq.SynchronizedCallback = function (callback) {
this.expectedCallbacks = 1;
this.callback = callback;
};
/**
* Called to acquire a reference to the callback.
* @return {function} The callback function to make when a depedent request is
* completed.
*/
gtv.jq.SynchronizedCallback.prototype.acquireCallback = function () {
var synchronizedCallback = this;
synchronizedCallback.expectedCallbacks++;
return function () {
synchronizedCallback.callbackFinished();
};
};
/**
* Creates a wrapper callback for acquiring a callback
* @return {function} A function that can be called to acquire the callback
* without access to the object instance.
*/
gtv.jq.SynchronizedCallback.prototype.getCallback = function () {
var synchronizedCallback = this;
return function () {
return synchronizedCallback.acquireCallback();
};
};
/**
* Decrements the callback reference count and calls the primary callback
* if all dependent callbacks are completed.
* @private
*/
gtv.jq.SynchronizedCallback.prototype.callbackFinished = function () {
this.expectedCallbacks--;
if (this.expectedCallbacks == 0 && this.callback)
this.callback();
};
/**
* Called by the code that originally constructed the object instance to
* represent that it is finished initiating tasks with dependent callbacks.
*/
gtv.jq.SynchronizedCallback.prototype.done = function () {
this.callbackFinished();
};
/**
* Holds parameters used to create the library controls.
* @param {?gtv.jq.CreationParams} opt_params CreationParams to initialize
* this new object with.
* @constructor
*/
gtv.jq.CreationParams = function (opt_params) {
var params = opt_params || {};
params.styles = params.styles || {};
this.styles = params.styles;
this.styles.page = params.styles.page || '';
this.styles.row = params.styles.row || '';
this.styles.itemDiv = params.styles.itemDiv || '';
this.styles.item = params.styles.item || '';
this.styles.selected = params.styles.selected || 'item-hover';
this.styles.hasData = params.styles.hasData || 'item-hover-active';
this.styles.normal = params.styles.normal || '';
this.styles.chosen = params.styles.chosen || '';
this.containerId = params.containerId;
if (!this.containerId) {
throw new Error('containerId must be provided');
}
this.choiceCallback = params.choiceCallback ||
function () {
};
this.layerNames = params.layerNames;
this.keyController = params.keyController;
};
/**
* Instance of the key controller this control is using.
* @type {KeyController}
*/
gtv.jq.CreationParams.prototype.keyController = null;
/**
* CSS classes used to style the row.
* page {string} CSS class to style the container for each page of rows.
* row {string} CSS class to style the row.
* itemsDiv {string} CSS class to style the DIV holding the items.
* itemDiv {string} CSS class to style the DIV holding a single item.
* item {string} CSS class to style the individual item.
* selected {string} CSS class to style the item that has the selection.
* hasData {string} CSS class to style the item that has the selection,
* for controls that support different selection styles based on
* associated data (see gtv.jq.CaptionItem).
* normal {string} For controls that maintain a sticky item choice, such
* as SideNav. CSS class to style an item that has been 'chosen', that
* is, the ENTER key was pressed while it had selection, or it
* received a mouse click.
* chosen {string} For controls that maintain a sticky item choice, such
* as SideNav. CSS class to style an item that has been 'chosen', that
* is, the ENTER key was pressed while it had selection, or it
* received a mouse click.
* @type Object
*/
gtv.jq.CreationParams.prototype.styles = null;
/**
* The ID of the control container (an element will be created with this ID).
* @type string
*/
gtv.jq.CreationParams.prototype.containerId = null;
/**
* Callback to make when the user chooses an item (if applicable to the control)
* @type Function(selectedItem)
*/
gtv.jq.CreationParams.prototype.choiceCallback = null;
/**
* Array of Layer name to add the control to, or 'default' if not supplied.
* @type string
*/
gtv.jq.CreationParams.prototype.layerNames = null;
/**
* Describes an item that has a caption and a data item to go with it.
* Not all controls support CaptionItem (StackControl, SlidingControl).
* Use this instead of a simple items array when an item that needs
* selection (say, a thumbnail) also needs a caption (say, photo title)
* but the selection outline should only be drawn around the item.
* @constructor
*/
gtv.jq.CaptionItem = function () {
};
/**
* The item that will be outlined by selection. This will be the child of
* the element with the CSS class styles.item.
* @type jQuery.Element
*/
gtv.jq.CaptionItem.prototype.item = null;
/**
* The caption for the item, to be displayed beneath it. The container of this
* caption will be styled so that it will be clipped at the width of the item.
* @type jQuery.Element
*/
gtv.jq.CaptionItem.prototype.caption = null;
/**
* If supplied, this item will be given an active hover style by the key
* controller when selected. This allows items with data to be visually
* distinguished from those without. For example, an item that can be
* navigated to when chosen might have this value non-null; and item that
* cannot will have it null. The two different selection styles applied
* (styles.selected, styles.hasData) provide a visual clue to the user.
*/
gtv.jq.CaptionItem.prototype.data = null;
/**
* Describes the contents to be added to a control. Passed with ShowParams
* object, used when calling showControl on a control object.
*
* items, itemsArray and itemsGenerator, indicate how new items will be
* added to the control being displayed. Only one of these should be supplied
* in an instance of the object.
* @param {gtv.jq.ControlContents} opt_params Optional initialization values.
* @constructor
*/
gtv.jq.ControlContents = function (opt_params) {
var params = opt_params || {};
this.items = params.items;
this.captionItems = params.captionItems;
this.contentsArray = params.contentsArray;
this.itemsGenerator = params.itemsGenerator;
};
/**
* Simple array of items to add to the control. These items will be added to
* the control in the order they appear in the array. Each item is added as
* a child of a separate Element to contain it. These container elements are
* created by the control and given the Styles.item CSS class.
* @type Array.<jQuery.Element>
*/
gtv.jq.ControlContents.prototype.items = null;
/**
* Simple array of items to add to the control. These items will be added to
* the control in the order they appear in the array. Each item is added as
* a child of a separate Element to contain it. These container elements are
* created by the control and given the Styles.item CSS class.
* @type Array.<gtv.jq.CaptionItem>
*/
gtv.jq.ControlContents.prototype.captionItems = null;
/**
* Array of ControlContents objects to add to a control. Some multi-row
* controls (such as the RollerControl) require this so that each row can be
* described explicitly. That is, each row has a very specific contents
* instead of being created as-needed and filled in.
*
* Since this is an array of ControlContents objects, each element is can
* in turn be a simple array of items or an itemsGenerator. (It could also
* take an itemsArray, but no existing controls take an array of arrays of
* arrays.)
* @type Array.<gtv.jq.ControlContents>
*/
gtv.jq.ControlContents.prototype.contentsArray = null;
/**
* A function that generates items as-requested. Clients creating controls
* can use this to create one or more controls in a callback instead of having
* them pre-created an placed in an items array. Generally this callback
* maintains state in its closure and creates the each subsequent item in a
* collection when it is called. This function also must add its control to
* the parent element, which is passed in. The parent element is already in
* the page DOM when the callback is called, so controls added to the parent
* will be in the DOM immediately as well.
*
* This function should return boolean true if it added an element to the
* parent, and false if it did not (and has no further elements to add).
* @type Function(jQuery.Element)
*/
gtv.jq.ControlContents.itemsGenerator = null;
/**
* Holds parameters used to show the library controls.
* @param {?gtv.jq.ShowParams} opt_params Optional parameters to initialize the
* new object with.
* @constructor
*/
gtv.jq.ShowParams = function (opt_params) {
var params = opt_params || {};
this.topParent = params.topParent;
if (!this.topParent) {
throw new Error("topParent must be supplied.");
}
this.contents = new gtv.jq.ControlContents(params.contents);
};
/**
* Parent element on the page that holds the control.
* @type jQuery.Element
*/
gtv.jq.ShowParams.prototype.topParent = null;
/**
* The contents the control should have. See gtv.jq.ControlContents for
* details.
* @type gtv.jq.ControlContents
*/
gtv.jq.ShowParams.prototype.contents = null;
/**
* Size class holds a width/height dimension pair.
* @param {number} width
* @param {number} height
* @constructor
*/
gtv.jq.Size = function (width, height) {
this.width = width;
this.height = height;
};
/**
* Width dimension in pixels.
* @type number
*/
gtv.jq.Size.prototype.width;
/**
* Height dimension in pixels.
* @type number
*/
gtv.jq.Size.prototype.height;
return gtv;
};