From 3070d7b2a3b96609eace60825c721951c85405cc Mon Sep 17 00:00:00 2001 From: François Frisch Date: Sat, 17 Mar 2012 18:05:23 -0700 Subject: Adding the youtube player --- .../examples/youtube-channel-example/index.html | 44 +++ .../examples/youtube-channel-example/package.json | 7 + .../examples/youtube-channel-example/style.css | 47 +++ .../youtube-channel-example.js | 8 + .../youtube-channel.reel/youtube-channel.html | 34 ++ .../youtube-channel.reel/youtube-channel.js | 101 ++++++ .../montage/test/ui/youtube-player-spec.js | 363 +++++++++++++++++++++ .../youtube-player-test/youtube-player-test.html | 47 +++ .../ui/youtube-player-test/youtube-player-test.js | 9 + .../ui/youtube-player.reel/youtube-player.html | 29 ++ .../ui/youtube-player.reel/youtube-player.js | 179 ++++++++++ 11 files changed, 868 insertions(+) create mode 100755 node_modules/montage/examples/youtube-channel-example/index.html create mode 100755 node_modules/montage/examples/youtube-channel-example/package.json create mode 100755 node_modules/montage/examples/youtube-channel-example/style.css create mode 100755 node_modules/montage/examples/youtube-channel-example/youtube-channel-example.js create mode 100644 node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.html create mode 100644 node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.js create mode 100755 node_modules/montage/test/ui/youtube-player-spec.js create mode 100644 node_modules/montage/test/ui/youtube-player-test/youtube-player-test.html create mode 100755 node_modules/montage/test/ui/youtube-player-test/youtube-player-test.js create mode 100644 node_modules/montage/ui/youtube-player.reel/youtube-player.html create mode 100644 node_modules/montage/ui/youtube-player.reel/youtube-player.js (limited to 'node_modules') diff --git a/node_modules/montage/examples/youtube-channel-example/index.html b/node_modules/montage/examples/youtube-channel-example/index.html new file mode 100755 index 00000000..71baba29 --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/index.html @@ -0,0 +1,44 @@ + + + + + Youtube Channel + + + + + +
+
Youtube Channel
+ +
+
+ + diff --git a/node_modules/montage/examples/youtube-channel-example/package.json b/node_modules/montage/examples/youtube-channel-example/package.json new file mode 100755 index 00000000..ecfbdd8a --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/package.json @@ -0,0 +1,7 @@ +{ + "name": "youtube-channel-example", + "version": "0.0.0", + "mappings": { + "montage": "../../" + } +} \ No newline at end of file diff --git a/node_modules/montage/examples/youtube-channel-example/style.css b/node_modules/montage/examples/youtube-channel-example/style.css new file mode 100755 index 00000000..c281cd65 --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/style.css @@ -0,0 +1,47 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ + + +/* Base ----------------------------- */ + +html { + background-color: hsl(0,0%,85%); + height: 100%; +} + +body { + margin: 0; + width: 100%; + height: 100%; + display: -webkit-box; + -webkit-box-align: center; + -webkit-box-pack: center; + + display: -moz-box; + -moz-box-align: center; + -moz-box-pack: center; +} + + +/* Converter ----------------------------- */ + +.youtube-channel-example { + padding: 10px; + text-shadow: #fff 0 1px 0; + border-radius: 8px; + background-color: hsl(0,0%,95%); + box-shadow: inset 0px 1px 2px 1px hsla(0,0%,100%,1), 0px 2px 5px hsla(0,0%,0%,.1); +} + +.youtube-channel-example #title { + margin: 0 0 5px 0; + text-align: center; + font: 24px/40px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; +} + +.youtube-channel-example-url { + width: 100%; +} diff --git a/node_modules/montage/examples/youtube-channel-example/youtube-channel-example.js b/node_modules/montage/examples/youtube-channel-example/youtube-channel-example.js new file mode 100755 index 00000000..4ca12757 --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/youtube-channel-example.js @@ -0,0 +1,8 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +var Montage = require("montage").Montage; + +exports.YoutubeChannelExample = Montage.create(Converter, {}); diff --git a/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.html b/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.html new file mode 100644 index 00000000..8514f5ce --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.html @@ -0,0 +1,34 @@ + + + + + + + + +
+
+
+ + diff --git a/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.js b/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.js new file mode 100644 index 00000000..1f5aa2d1 --- /dev/null +++ b/node_modules/montage/examples/youtube-channel-example/youtube-channel.reel/youtube-channel.js @@ -0,0 +1,101 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/*global require,exports*/ +var Montage = require("montage").Montage, + Component = require("montage/ui/component").Component, + Uuid = require("montage/core/uuid").Uuid; + + +var YoutubeChannel = exports.YoutubeChannel = Montage.create(Component, { + + _userRe: { + enumerable: false, + value: /youtube.com\/(user\/)?([a-z0-9]+)/i + }, + + _channelUrl: { + enumerable: false, + value: null + }, + channelUrl: { + depends: ["channel"], + get: function() { + return this._channelUrl; + }, + set: function(value, fromChannel) { + if (this._channelUrl !== value) { + this._channelUrl = value; + + // prevent infinite loop + if (!fromChannel) { + var match = this._userRe.exec(value); + if (match && match[2]) { + Object.getPropertyDescriptor(this, "channel").set.call(this, match[2], true); + } + } + } + } + }, + + _channel: { + enumerable: false, + value: null + }, + channel: { + get: function() { + return this._channel; + }, + set: function(value, fromUrl) { + if (this._channel !== value) { + this._channel = value; + + // prevent infinite loop + if (!fromUrl) { + Object.getPropertyDescriptor(this, "channelUrl").set.call(this, "http://www.youtube.com/user/" + value, true); + } + + this._loadChannel(); + } + } + }, + + _loadChannel: { + enumerable: false, + value: function() { + var self = this; + + var callbackName = "scriptCallback" + Uuid.generate().replace(/-/g, "_"); + + window[callbackName] = function(data) { + self.handleData(data); + delete window[callbackName]; + }; + + // create url + var url = "http://gdata.youtube.com/feeds/api/users/" + this._channel + "/uploads?v=2&alt=json-in-script&callback=" + callbackName; + + var script = document.createElement("script"); + script.src = url; + this._element.appendChild(script); + } + }, + + handleData: { + value: function(data) { + var entries = data.feed.entry || []; + + var playlist = []; + + for (var i = 0, len = entries.length; i < len; i++) { + var id = entries[i]["media$group"]["yt$videoid"]["$t"]; + playlist.push(id); + } + + this.player.playlist = playlist; + } + } + +}); \ No newline at end of file diff --git a/node_modules/montage/test/ui/youtube-player-spec.js b/node_modules/montage/test/ui/youtube-player-spec.js new file mode 100755 index 00000000..dc57e3ec --- /dev/null +++ b/node_modules/montage/test/ui/youtube-player-spec.js @@ -0,0 +1,363 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +var Montage = require("montage").Montage, + TestPageLoader = require("support/testpageloader").TestPageLoader; + +var testPage = TestPageLoader.queueTest("buttontest", function() { + var test = testPage.test; + + var click = function(component, el, fn) { + el = el || component.element; + + var listener = testPage.addListener(component, fn); + + testPage.mouseEvent({target: el}, "mousedown"); + testPage.mouseEvent({target: el}, "mouseup"); + testPage.mouseEvent({target: el}, "click"); + + // Return this so that it can be checked in tha calling function. + return listener; + }; + var testButton = function(component, value) { + expect(component).toBeDefined(); + expect(click(component)).toHaveBeenCalled(); + expect(component.label).toBe(value); + }; + + describe("ui/button-spec", function() { + it("should load", function() { + expect(testPage.loaded).toBe(true); + }); + + describe("button", function(){ + + it("can be created from a div element", function(){ + testButton(test.divbutton, "div button"); + }); + it("can be created from an input element", function(){ + testButton(test.inputbutton, "input button"); + }); + it("can be created from a button element", function(){ + testButton(test.buttonbutton, "button button"); + }); + + describe("disabled property", function(){ + it("is taken from the element's disabled attribute", function() { + expect(test.disabledbutton.disabled).toBe(true); + expect(click(test.disabledbutton)).not.toHaveBeenCalled(); + expect(test.disabledinput.disabled).toBe(true); + expect(click(test.disabledinput)).not.toHaveBeenCalled(); + expect(test.inputbutton.disabled).toBe(false); + }); + it("can be set", function(){ + expect(test.disabledbutton.disabled).toBe(true); + test.disabledbutton.disabled = false; + expect(test.disabledbutton.disabled).toBe(false); + // TODO click the button and check that it wasn't pressed + + expect(test.disabledinput.disabled).toBe(true); + test.disabledinput.disabled = false; + expect(test.disabledinput.disabled).toBe(false); + // TODO click the button and check that it wasn't pressed + }); + it("can can be set in the serialization", function(){ + expect(test.disabledinputszn.disabled).toBe(true); + // TODO check button pressibility + }); + it("is the inverse of the enabled property", function(){ + expect(test.enabledinputszn.disabled).toBe(false); + expect(test.enabledinputszn.enabled).toBe(true); + test.enabledinputszn.enabled = false; + expect(test.enabledinputszn.disabled).toBe(true); + expect(test.enabledinputszn.enabled).toBe(false); + // TODO click the button and check that it wasn't pressed + }); + }); + + describe("label property", function() { + it("is set from the serialization on a button", function() { + expect(test.buttonlabelszn.label).toBe("pass"); + testPage.waitForDraw(); + runs(function(){ + expect(test.buttonlabelszn.element.firstChild.data).toBe("pass"); + }); + }); + it("is set from the serialization on an input", function() { + expect(test.inputlabelszn.label).toBe("pass"); + expect(test.inputlabelszn.element.value).toBe("pass"); + }); + it("sets the value on an input", function() { + expect(test.inputbutton.label).toBe("input button"); + test.inputbutton.label = "label pass"; + expect(test.inputbutton.label).toBe("label pass"); + expect(test.inputbutton.value).toBe("label pass"); + test.inputbutton.label = "input button"; + }); + it("sets the first child on a non-input element", function() { + expect(test.buttonbutton.label).toBe("button button"); + test.buttonbutton.label = "label pass"; + expect(test.buttonbutton.label).toBe("label pass"); + + testPage.waitForDraw(); + runs(function(){ + expect(test.buttonbutton.element.firstChild.data).toBe("label pass"); + test.buttonbutton.label = "button button"; + }); + }); + }); + + describe("value property", function() { + it("is set from the value on an input", function() { + expect(test.inputbutton.element.value).toBe("input button"); + expect(test.inputbutton.value).toBe("input button"); + }); + it("is set by the label property in the serialization", function() { + expect(test.inputlabelszn.label).toBe("pass"); + //expect(test.inputlabelszn.value).toBe("pass"); + }); + it("sets the label property when using an input element", function() { + expect(test.inputbutton.label).toBe("input button"); + test.inputbutton.value = "value pass"; + expect(test.inputbutton.value).toBe("value pass"); + expect(test.inputbutton.label).toBe("value pass"); + test.inputbutton.value = "input button"; + }); + it("doesn't set the label property when using a non-input element", function() { + expect(test.buttonbutton.label).toBe("button button"); + test.buttonbutton.value = "value fail"; + expect(test.buttonbutton.label).toBe("button button"); + testPage.waitForDraw(); + runs(function(){ + expect(test.buttonbutton.element.firstChild.data).toBe("button button"); + test.buttonbutton.value = "button button"; + }); + }); + + }); + + + it("responds when child elements are clicked on", function(){ + expect(click(test.buttonnested, test.buttonnested.element.firstChild)).toHaveBeenCalled(); + }); + + it("supports converters for label", function(){ + expect(test.converterbutton.label).toBe("PASS"); + expect(test.converterbutton.element.value).toBe("PASS"); + }); + + // TODO should be transplanted to the press-composer-spec + // it("correctly releases the pointer", function() { + // var l = testPage.addListener(test.scroll_button); + + // testpage.mouseEvent({target: test.scroll_button.element}, "mousedown");; + // expect(test.scroll_button.active).toBe(true); + // test.scroll_button.surrenderPointer(test.scroll_button._observedPointer, null); + // expect(test.scroll_button.active).toBe(false); + // testPage.mouseEvent({target: test.scroll_button.element}, "mouseup");; + + // expect(l).not.toHaveBeenCalled(); + + // }); + + if (window.Touch) { + + describe("when supporting touch events", function() { + + it("should dispatch an action event when a touchend follows a touchstart on a button", function() { + + }); + + }); + + } else { + + describe("when supporting mouse events", function() { + it("dispatches an action event when a mouseup follows a mousedown", function() { + expect(click(test.inputbutton)).toHaveBeenCalled(); + }); + + it("does not dispatch an action event when a mouseup occurs after not previously receiving a mousedown", function() { + // reset interaction + // test.inputbutton._endInteraction(); + var l = testPage.addListener(test.inputbutton); + testPage.mouseEvent({target: test.inputbutton.element}, "mouseup");; + expect(l).not.toHaveBeenCalled(); + }); + + it("does not dispatch an action event when a mouseup occurs away from the button after a mousedown on a button", function() { + var l = testPage.addListener(test.inputbutton); + + testpage.mouseEvent({target: test.inputbutton.element}, "mousedown");; + // Mouse up somewhere else + testPage.mouseEvent({target: test.divbutton.element}, "mouseup");; + + expect(l).not.toHaveBeenCalled(); + }); + }); + } + + describe("inside a scroll view", function() { + it("fires an action event when clicked", function() { + testButton(test.scroll_button, "scroll button"); + }); + it("doesn't fire an action event when scroller is dragged", function() { + var el = test.scroll_button.element; + var scroll_el = test.scroll.element; + + var listener = testPage.addListener(test.scroll_button); + + var press_composer = test.scroll_button.composerList[0]; + + // mousedown + testPage.mouseEvent({target: el}, "mousedown"); + + expect(test.scroll_button.active).toBe(true); + expect(test.scroll_button.eventManager.isPointerClaimedByComponent(press_composer._observedPointer, press_composer)).toBe(true); + + // Mouse move doesn't happen instantly + waits(10); + runs(function() { + // mouse move up + var moveEvent = document.createEvent("MouseEvent"); + // Dispatch to scroll view, but use the coordinates from the + // button + moveEvent.initMouseEvent("mousemove", true, true, scroll_el.view, null, + el.offsetLeft, el.offsetTop - 100, + el.offsetLeft, el.offsetTop - 100, + false, false, false, false, + 0, null); + scroll_el.dispatchEvent(moveEvent); + + expect(test.scroll_button.active).toBe(false); + expect(test.scroll_button.eventManager.isPointerClaimedByComponent(press_composer._observedPointer, press_composer)).toBe(false); + + // mouse up + testPage.mouseEvent({target: el}, "mouseup");; + + expect(listener).not.toHaveBeenCalled(); + }); + + }); + }); + }); + + describe("toggle button", function() { + it("alternates between unpressed and pressed", function() { + expect(test.toggleinput.pressed).toBe(false); + expect(test.toggleinput.label).toBe("off"); + + click(test.toggleinput); + expect(test.toggleinput.pressed).toBe(true); + expect(test.toggleinput.label).toBe("on"); + + click(test.toggleinput); + expect(test.toggleinput.pressed).toBe(false); + expect(test.toggleinput.label).toBe("off"); + }); + + describe("toggle()", function() { + it("swaps the state", function() { + test.toggleinput.pressed = false; + test.toggleinput.toggle(); + expect(test.toggleinput.pressed).toBe(true); + test.toggleinput.toggle(); + expect(test.toggleinput.pressed).toBe(false); + test.toggleinput.toggle(); + expect(test.toggleinput.pressed).toBe(true); + }); + }); + + describe("label property", function() { + it("alternates between unpressed and pressed", function() { + test.toggleinput.pressed = false; + + // The expectations are in a closure because the draw can + // happen at any point after we click on the button + var checker = function(e) { + return function(){ + expect(test.toggleinput.pressed).toBe(e); + expect(test.toggleinput.element.value).toBe((e)?"on":"off"); + }; + }; + + runs(checker(false)); + + runs(function(){ click(test.toggleinput); }); + testPage.waitForDraw(); + runs(checker(true)); + }); + it("changes pressed state when set to unpressedLabel or pressedLabel", function(){ + test.toggleinput.pressed = false; + test.toggleinput.label = "on"; + expect(test.toggleinput.pressed).toBe(true); + test.toggleinput.label = "off"; + expect(test.toggleinput.pressed).toBe(false); + }); + it("doesn't change pressed state when set to a non-matching string", function(){ + expect(test.toggleinput.pressed).toBe(false); + test.toggleinput.label = "random"; + expect(test.toggleinput.pressed).toBe(false); + expect(test.toggleinput.label).toBe("random"); + + test.toggleinput.pressed = true; + expect(test.toggleinput.label).toBe("on"); + }); + }); + describe("unpressedLabel", function() { + it("is set as the value when the button is unpressed", function() { + test.toggleinput.pressed = false; + expect(test.toggleinput.label).toBe("off"); + test.toggleinput.unpressedLabel = "unpressed"; + expect(test.toggleinput.label).toBe("unpressed"); + + testPage.waitForDraw(); + runs(function(){ + expect(test.toggleinput.element.value).toBe("unpressed"); + }); + }); + it("is taken from `value` on init if the button is unpressed and unpressedLabel isn't set", function() { + expect(test.toggleinput2.unpressedLabel).toBe(test.toggleinput2.label); + }); + }); + + describe("pressedLabel", function() { + it("is set as the value when the button is pressed", function() { + test.toggleinput.pressed = true; + expect(test.toggleinput.label).toBe("on"); + test.toggleinput.pressedLabel = "pressed"; + expect(test.toggleinput.label).toBe("pressed"); + + testPage.waitForDraw(); + runs(function(){ + expect(test.toggleinput.element.value).toBe("pressed"); + }); + }); + it("is taken from `value` on init if the button is pressed and pressedLabel isn't set", function() { + expect(test.toggleinput3.pressedLabel).toBe(test.toggleinput3.label); + }); + }); + + describe("pressedClass", function() { + it("is not in the classList when the button is unpressed", function() { + test.toggleinput.pressed = false; + + testPage.waitForDraw(); + runs(function(){ + expect(test.toggleinput.element.className).not.toContain("pressed"); + }); + }); + it("is added to the classList when the button is pressed", function() { + test.toggleinput.pressed = true; + + testPage.waitForDraw(); + runs(function(){ + expect(test.toggleinput.element.className).toContain("pressed"); + }); + }); + }); + }); + }); +}); diff --git a/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.html b/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.html new file mode 100644 index 00000000..a82f50e9 --- /dev/null +++ b/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.html @@ -0,0 +1,47 @@ + + + + + + Youtube player test + + + + + +

Youtube Player test

+ +

Basic

+
+ + + diff --git a/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.js b/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.js new file mode 100755 index 00000000..8319fc93 --- /dev/null +++ b/node_modules/montage/test/ui/youtube-player-test/youtube-player-test.js @@ -0,0 +1,9 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +var Montage = require("montage").Montage, + YoutubePlayer = require("montage/ui/youtube-player").YoutubePlayer; + +var YoutubePlayerTest = exports.YoutubePlayerTest = Montage.create(Montage, {}); diff --git a/node_modules/montage/ui/youtube-player.reel/youtube-player.html b/node_modules/montage/ui/youtube-player.reel/youtube-player.html new file mode 100644 index 00000000..ae757626 --- /dev/null +++ b/node_modules/montage/ui/youtube-player.reel/youtube-player.html @@ -0,0 +1,29 @@ + + + + + + + + +
+ + + +
+ + diff --git a/node_modules/montage/ui/youtube-player.reel/youtube-player.js b/node_modules/montage/ui/youtube-player.reel/youtube-player.js new file mode 100644 index 00000000..2f7709d7 --- /dev/null +++ b/node_modules/montage/ui/youtube-player.reel/youtube-player.js @@ -0,0 +1,179 @@ +//data="https://www.youtube.com/v/u1zgFlCw8Aw?version=3&enablejsapi=1&playerapiid=ytplayer" +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/*global require,exports*/ +var Montage = require("montage").Montage, + Component = require("ui/component").Component; + +var YoutubePlayer = exports.YoutubePlayer = Montage.create(Component, { + + // Stores a queue of function calls to make on the player in the draw + // function + _playerQueue: { + enumerable: false, + value: [] + }, + + _ready: { + enumerable: false, + value: false + }, + + _player: { + enumerable: false, + value: null + }, + player: { + get: function() { + return this._player; + }, + set: function(value) { + // TODO don't allow this to be changed + if (this._player !== value) { + this._player = value; + } + } + }, + + _autoplay: { + enumerable: false, + value: false + }, + autoplay: { + get: function() { + return this._autoplay; + }, + set: function(value) { + if (this._autoplay !== value) { + this._autoplay = value; + } + } + }, + + _videoId: { + enumerable: false, + value: null + }, + videoId: { + get: function() { + return this._videoId; + }, + set: function(value) { + if (this._videoId !== value) { + // TODO handle URLs as well + this._videoId = value; + + // If the video isn't in the playlist, clear the playlist, + if (this._playlist && this._playlist.indexOf(value) === -1) { + this._playlist = null; + } + // TODO if the video is in the playlist use playVideoAt + + if (this._autoplay) { + this._playerQueue.push(["loadVideoById", value]); + } else { + this._playerQueue.push(["cueVideoById", value]); + } + this.needsDraw = true; + } + } + }, + + _playlist: { + enumerable: false, + value: null + }, + playlist: { + get: function() { + return this._playlist; + }, + set: function(value) { + if (this._playlist !== value) { + this._playlist = value; + + if (this._autoplay) { + this._playerQueue.push(["loadPlaylist", value]); + } else { + this._playerQueue.push(["cuePlaylist", value]); + } + this.needsDraw = true; + } + } + }, + + play: { + value: function() { + this._playerQueue.push("playVideo"); + this.needsDraw = true; + } + }, + pause: { + value: function() { + this._playerQueue.push("pauseVideo"); + this.needsDraw = true; + } + }, + stop: { + value: function() { + this._playerQueue.push("stopVideo"); + this.needsDraw = true; + } + }, + + prepareForDraw: { + value: function() { + // Create the callback if it doesn't exist, and make it dispatch + // an event on the document instead + if (!window.onYouTubePlayerReady) { + window.onYouTubePlayerReady = function(playerId) { + var event = document.createEvent("CustomEvent"); + event.initEvent("youtubePlayerReady", true, true); + event.playerId = playerId; + document.dispatchEvent(event); + }; + } + + document.addEventListener("youtubePlayerReady", this, false); + + // If there's no videoId set one the doesn't exist + this._player.data = "https://www.youtube.com/v/" + (this._videoId || "xxxxxxxxxxx") + "?version=3&enablejsapi=1&playerapiid=" + this.uuid; + } + }, + + handleYoutubePlayerReady: { + value: function(event) { + if (event.playerId !== this.uuid) { + return; + } + + this._ready = true; + this.needsDraw = true; + } + }, + + draw: { + value: function() { + if (!this._ready) { + return; + } + + for (var i = 0, len = this._playerQueue.length; i < len; i++) { + var fnName, args; + if (typeof this._playerQueue[i] === "string") { + fnName = this._playerQueue[i]; + args = []; + } else { + fnName = this._playerQueue[i].shift(); + args = this._playerQueue[i]; + } + + this._player[fnName].apply(this._player, args); + } + + this._playerQueue.length = 0; + } + } +}); \ No newline at end of file -- cgit v1.2.3