Initialize youtube api to target ajax loaded iframe - ajax

it's my first time to work with Youtube API and after I got most things done, I'm having one last issue with it which i can't seem to solve, so I would appreciate if you could take a few minutes to help.
Here it goes in simple words:
I have a video slider (carousel). Under the main video, are thumbnails of other related videos (this is the site: kushtube.com)
when I click on a related video thumbnail, the main player content is loaded via AJAX
What I wanted to ultimately achieve is that when the current video ends,the next vicdo starts playing automatically.
Now after I did some work, I managed to make it work like that, BUT
it only work on page load...
If i click on one of the related video thumbnails, the content of the player loads via AJAX and I cant seem to be able to re-initialize Youtube API to target the new ajax-loaded player.
This is my current code:
<script>
// global variable for the player
var player;
function ytInit(){
// create the global player from the specific iframe (#video)
player = new YT.Player('test', {
events: {
// call this function when player is ready to use
'onReady': onPlayerReady,
'onStateChange': onPlayerStatusChange
}
});
}
// this function gets called when API is ready to use
function onYouTubeIframeAPIReady() {
ytInit();
}
jQuery(document).ready( function($){
jQuery('ul.carousel-list li').click( function(){
ytInit();
jQuery('ul.carousel-list li.active').removeClass('active');
});
});
function onPlayerStatusChange(event) {
/* video status
----------------
-1 (unstarted)
0 (ended)
1 (playing)
2 (paused)
3 (buffering)
5 (video cued)
*/
console.log( event );
if( event.data == 0 ){
var thisLI = jQuery('ul.carousel-list li.active'); //get active slider item
var thisLINext = jQuery('ul.carousel-list li.active').next(); //get next slider item
var nextVideoCode = thisLINext.attr('video_code'); //get next video code
var nextVideoTitle = thisLINext.attr('video_title'); //get next video code
var nextVideoUrl = thisLINext.attr('video_url'); //get next video code
thisLINext.addClass('active'); //activate next slider item
thisLI.removeClass('active'); //deactivate current cslider item
//load next video
player.loadVideoById(nextVideoCode);
//update video title in header
jQuery('.entry-header h1.entry-title a').attr('href', decodeURIComponent(nextVideoUrl)).text(decodeURIComponent(nextVideoTitle));
}
}
function onPlayerReady(event) {
// bind events
var playButton = document.getElementById("play-button");
playButton.addEventListener("click", function() {
player.playVideo();
});
var pauseButton = document.getElementById("pause-button");
pauseButton.addEventListener("click", function() {
player.pauseVideo();
});
}
// Inject YouTube API script
var tag = document.createElement('script');
tag.src = "//www.youtube.com/player_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
</script>
Do you have any helpful suggestions? I would really appreciate.

Calling ytInit() when you click the <li> creates a new player object. I think that's not quite what you want.
Have you tried:
jQuery('ul.carousel-list li').click( function(){
// ytInit();
// just load the video from the "video_code" attr
player.loadVideoById(this.getAttribute('video_code'));
jQuery('ul.carousel-list li.active').removeClass('active');
});
If that doesn't autoplay, then you may have to wait for the YT.PlayerState.CUED (i.e. 5) event in your player status change event listener to start the player.

Related

Why does my Teams userscript have no effect?

When I paste URLs pointing to my ticketing system into other systems, I want them to look nice without a lot of manual reformatting. I have a userscript that works in GitHub taking <rootURL>/ticket/1234 and pasting it in GitHub as [#1234](<rootURL>/ticket/1234) which GitHub renders nicely.
I want to do the same thing for Teams. The Teams app for Windows has some programmability but I can't find what I need there so I've resorted to using Teams on the web and writing another userscript. (By all means, I'm happy to hear, "The way to do that in Teams is ...." but this is the best I've come up with so far.)
Whereas GitHub messages are composed in a textarea, Teams has a div that it updates as you type. I have a paste handler that creates what seem to be the right DOM elements but when my function is done, I see the original, unformatted URL in the Teams message.
My userscript is below. The logging tells me its doing the right thing but my new DOM elements don't show up in the UI. Any thoughts?
// ==UserScript==
// #name Teams Trac link
// #namespace http://tampermonkey.net/
// #version 0.1
// #description Reformat pasted link to Trac ticket to look pretty in Teams
// #author Chris Nelson, PE
// #match https://teams.microsoft.com/*
// #icon https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// #grant none
// ==/UserScript==
// Handle paste event by making custom link, when appropriate.
// If handled, suppress the browser handling of the event.
function handlePaste(event) {
console.log("Handling paste");
var target = event.target;
// Get the text that the user is trying to paste
var text = (event.clipboardData || window.clipboardData).getData('text');
try {
var url = new URL(text);
if (url.pathname.startsWith('/trac/ticket')) {
console.log("Pasting a Trac ticket link: " + text);
var parts = url.pathname.split('/');
var ticketNumber = parts[3];
// Don't let the browser also paste
event.preventDefault();
// Create a link
var link = document.createElement('a');
link.innerHTML = '#' + ticketNumber;
link.href = text;
link.title = 'Trac ticket #' + ticketNumber;
// FIXME - nothing from here on works to insert the link
// Get all divs
var divs = Array.from(document.querySelectorAll('div'));
// Filter to those with an ID that starts 'new-message-'
divs = divs.filter(d => d.id.startsWith('new-message-'));
var parent = divs[0];
console.log('Before adding, div has ' + parent.childNodes.length + ' children');
parent.appendChild(link);
console.log('After adding, div has ' + parent.childNodes.length + ' children');
}
}
catch (error) {
// Nothing, just let the browser do its thing.
}
}
(function() {
console.log("Attaching paste handler");
// Intercept a paste event anywhere on the page but
// only handle it if pasting into a new message.
document.body.addEventListener('paste', (event) => {
var target = event.target;
console.log("Got paste event for " + target);
if (target.tagName.toLowerCase() == 'br'
&& target.dataset.ckeFiller == 'true') {
handlePaste(event);
}
}, false);
})();

Add vimeo event listeners for multiple videos on same page

I have multiple Vimeo videos iframes on the same page. So I want to add event listeners for all the iframes. But somehow it is not working for me.
here is the code which I add on document.ready.
var iframes = document.querySelectorAll('iframe');
var player;
//loop through all and add event
for (i = 0; i < iframes.length; i++) {
// when vimeo player is ready add other events
player = $f(iframes[i]);
player.addEvent('ready', function () {
player.addEvent('play', onPlay);
player.addEvent('pause', onPause);
});
function onPlay(el) {
console.log('play');
}
function onPause(el) {
console.log('pause');
}
}
I get all the iframes in variable 'iframes', it also loops through all and add ready event. But cannot add play and pause events. Where am I going wrong?
The following code would help you with attaching events to your frames.
<script>
$(document).ready(function () {
var x = document.querySelectorAll("iframe");
var nodelist = x.length;
alert(nodelist);
for (i = 0; i < nodelist; i++) {
var player = new Vimeo.Player(x[i]);
player.on('play', function () {
console.log('played the video!');
});
player.on('ended', function () {
console.log('ended the video!');
});
}
});
</script>
Actually multiple videos play/pause issue as mentioned in my question got solved using froogaloop2.js. I am not writing any extra code for this now as specified by me in question. and my iframe src url does not append api=1 param.

Google apps script UI services to HTML services

I try to convert this simple google apps script code below to HTML services code.
The code below is written with the deprecated google apps script UI services!
Can anyone help me with HTML services example code in this usecase?
// Script with deprecated UI-services
// How to create this app with HTML-services?!!!?
//This script runs in a google website.
//It has one textobject and 1 button.
//when the button is pressed the value entered is stored in the spreadsheet
ssKey = 'sheetkey....';
function doGet(){
var app = UiApp.createApplication().setTitle('myApp');
//Create panels en grid
var MainPanel = app.createVerticalPanel();
var Vpanel1 = app.createVerticalPanel().setId('Vpanel2');
var grid = app.createGrid(4, 2).setId('myGrid');
//Vpanel1 widgets
var nameLabel = app.createLabel('Name');
var nameTextBox = app.createTextBox().setWidth('400px').setName('name').setId('name');
var submitButton = app.createButton('Verstuur').setId('submitButton');
grid.setWidget(0, 0, nameLabel)
.setWidget(0, 1, nameTextBox)
.setWidget(1, 1, submitButton);
//Set handlers en callbackelement
var handler = app.createServerClickHandler('InsertInSS');
handler.addCallbackElement(Vpanel1);
submitButton.addClickHandler(handler);
// build screen
Vpanel1.add(grid);
app.add(Vpanel1);
return app;
}
function InsertInSS(e){
var app =UiApp.getActiveApplication();
var collectedData = [new Date(), e.parameter.name] ;
var SS = SpreadsheetApp.openById(ssKey);
var Sheet = SS.getSheetByName('Contacts');
Sheet.getRange(Sheet.getLastRow()+1, 1, 1, collectedData.length).setValues([collectedData]);
app.getElementById('submitButton').setVisible(false);
//Reset fields on screen
app.getElementById('name').setText("");
return app;
}
Your Ui output looks like this:
Create an HTML file, and enter this code:
testForm.html
<div>
<div>
Name: <input id='idNameField' type='text'/>
</div>
<br/>
<input type='button' value='Verstuur' onmouseup='runGoogleScript()'/>
</div>
<script>
function onSuccess(argReturnValue) {
alert('was successful ' + argReturnValue);
//Reset fields on screen
Document.getElementById('idNameField').value = "";
}
function runGoogleScript() {
console.log('runGoogleScript ran!');
var inputValue = document.getElementById('idNameField').value;
google.script.run.withSuccessHandler(onSuccess)
.InsertInSS(inputValue);
};
</script>
Copy the follow code into:
Code.gs
function doGet() {
return HtmlService.createTemplateFromFile('testForm')
.evaluate() // evaluate MUST come before setting the NATIVE mode
.setTitle('The Name of Your Page')
.setSandboxMode(HtmlService.SandboxMode.NATIVE);
};
In a seperate .gs file add this code:
function InsertInSS(argPassedInName){
var ssKey = 'sheetkey....';
var SS = SpreadsheetApp.openById(ssKey);
var Sheet = SS.getSheetByName('Contacts');
Sheet.getRange(Sheet.getLastRow()+1, 1, 1, argPassedInName.length).setValue(argPassedInName);
}

Cannot update label on Google Apps Script GUI Builder Interface at runtime

I have an interface that calls a script for spreadsheet creation using data taken from other spreadsheet. I want the interface to update its labels at runtime in order to give visual feedback to the user and let him know the script is running and it's not stuck. When I try to update the label I put in the interface, it doesn't update the first time, but updates correctly after myFunction() reaches its end. Which means I can see the message "Creation Completed", but the message "Creating file..." is never shown. Also, the button buttonCompile is never disabled so it seems that the instructions before myFunction() are not executed at all. How can I get the labels updated and the button disabled before myFunction() starts executing? (I already double-checked variable references)
function doGet() {
var app = UiApp.createApplication();
app.add(app.loadComponent("File creation"));
var buttonCreate = app.getElementById('createBtn');
var handlerCrea = app.createServerHandler('createClickHandler');
buttonCreate.addClickHandler(handlerCreate);
return app;
}
function createClickHandler(e) {
var app = UiApp.getActiveApplication();
var label = app.getElementById('createLbl');
label.setText("Creating file...");
var buttonCompile = app.getElementById('compileBtn');
buttonCompile.setEnabled(false);
myFunction();
label.setText("Creation completed.");
buttonCompile.setEnabled(true);
app.close();
return app;
}
The cause of this behavior is that the GUI is updated only after leaving a handler. A workaround is to use two handlers. The 1st one sets the label text to Creating file... and disables the button, the 2nd one executes the myFunction function, changes the text to Creation completed, and eanbles the button. Here is an example. It disables/enables the button and the worker handler simply waits 5 seconds.
function doGet(e) {
var app = UiApp.createApplication();
var container = app.createHorizontalPanel().setId('container');
var btnPerformance = app.createButton("Performance Demo").setId('btnPerformance');
var handlerPerformance = app.createServerHandler('onBtnPerformanceClick');
var handlerWait = app.createServerHandler('onWait');
btnPerformance.addClickHandler(handlerPerformance);
btnPerformance.addClickHandler(handlerWait);
container.add(btnPerformance);
app.add(container);
return app;
}
function enableControls(enable) {
var lstControls = [ 'btnPerformance' ];
var app = UiApp.getActiveApplication();
for (var i = 0; i < lstControls.length; i++) {
var ctl = app.getElementById(lstControls[i]);
ctl.setEnabled(enable);
}
}
function onWait(e) {
enableControls(false);
return UiApp.getActiveApplication();
}
function onBtnPerformanceClick(e) {
Utilities.sleep(5000);
enableControls(true);
return UiApp.getActiveApplication();
}

iviewer jquery pluggin, center image

I'm using the iviewer plugin with a lightbox and I have issue to center my image everytime it load a new image.
I know that there is a pre-built method center() I just don't undertand how and where to call it.
You can find the function I'm using under. The function is called when I click on an element, it open a box div(#iviewer). In which I would like my image center. I also use a zoom pourcentage at the beginning so my image doesn't fit the box (var viewer).
function open(src, id) {
var firstZoom = true;
$("#iviewer").fadeIn().trigger('fadein');
var viewer = $("#iviewer .viewer").
width(920).
height(560).
iviewer({
src : src,
ui_disabled : true,
zoom : '50%',
initCallback : function() {
var self = this;
},
onZoom : function() {
if (!firstZoom) return;
$("#iviewer .loader").fadeOut();
$("#iviewer .viewer").fadeIn();
firstZoom = true;
}
}
);
//load new pic
viewer.iviewer('loadImage', src);
}
Thanks for the help.
The "onFinishLoad" callback hook in the initialization worked for me:
onFinishLoad: function(ev, src){ viewer.iviewer('center')}

Resources