Trouble updating API object once instantiated in Javascript - javascript

I'm instantiating a new Vimeo object when clicked. This allows me to use the event target to grab the videoUrl depending on which element is clicked. Then the vimeo api automagically creates an iframe with the video embed. The problem is that once the Vimeo player is created, I can't destroy it and recreate it with another videoUrl. It stays stuck on the first element I clicked. If I refresh and click another element, it works with the new videoUrl, so it means that it works on any element I choose but only the first click. I'm guessing this is a JS issue that I'm not familiar with. I'm used to C++ where we can use pointers to address this kind of thing. I would appreciate any suggestions.
function openModal(e) {
var modal = document.getElementById('Modal');
var videoUrl = e.target.dataset.videoLink;
//JS Player Code
alert(e.target.dataset.videoLink);
var options = {
url: videoUrl,
width: 640,
loop: false
};
var player = new Vimeo.Player('Modal', options);
modal.style.display = "block";
//Doesn't seem to do anything
delete player;
}

Unlike C++, JavaScript has a garbage collector in which you don't have to manage your memory. The delete operator in JS is completely different than the one you have in C++. Instead of pointers, JS uses "references" which you can't destroy manually.
Now, I don't quite understand what you expect to happen when you do delete player. But I assume you want to remove the iframe (which doesn't really make any sense.)
But anyway, you have two choices. You either
Hide it with CSS via display: none
Replace the element with a new one.
By the way, the delete operator in JS is equivalent to the std::map::erase method in C++.

Related

Howler js pause/resume trouble

I'm using the Howler js library to set a player in an app running through Electron. First everything seemed to work well, but after a few weeks using the app, a bug occurs repeatedly, but not constantly : the pause() function doesn't work. Here's some piece of code :
Initialization :
var is_paused = true;
var currentTrack = "track1";
var tracks = {"track1" : new Howl({urls: ['path/to/track1.mp3']}),
"track2" : new Howl({urls: ['path/to/track2.mp3']}),
"track3" : new Howl({urls: ['path/to/track3.mp3']})
};
Then I have a few buttons for play/resume, pause, stop, and play a specific track :
$('#playS').click(function(){
if (is_paused){
tracks[currentTrack].play();
is_paused = false;
}
});
$('#pauseS').click(function(){
tracks[currentTrack].pause();
is_paused = true;
});
$('.trackBtn').click(function(){
tracks[currentTrack].stop();
currentTrack = $(this).attr('id');
tracks[currentTrack].play();
is_paused = false;
});
The problem is that sometimes (generally after 40-45 min of a track playing), the pause() function just do nothing, which is really annoying cause I need to pause the track and play another 30 sec file and then resume the current track. I checked the console while the bug occurs, it says absolutely nothing. I have no idea where the bug comes from, there's not a lot of information about how works the library. I really need some help here, thank's in advance.
EDIT : one more thing, when pause() doesn't work, if I click play() the track plays from the begining, and I have control on this second instance of the track. It's like the first instance has reached end, but still playing.
Without knowing what version of Howler you're using, or what other code might be messing things up, there is one thing I think might help: You don't need to track the paused state. The "playing" method takes care of that. I've made it work using something like this:
// If it's paused, it's not playing, so...
paused = !myHowlInstance.playing();
Another thing I noticed is that you have currentTrack = $(this).attr('id'); in your (I think it's a) stop button. Unfortunately I don't know JQuery well enough to know if there's anything wrong with that (I'm more of a Dojo fan myself). But it looks like currentTrack may be set to some value not in your list (which would break tracks[currentTrack]). You might want to go into the console and type tracks["track1"], currentTrack etc. to see their values. You can even do tracks[currentTrack].play(); and see what happens. I wasn't sure if you knew you could do that (it was a huge help to me when I found out about it).
And as far as the "un-pausing" starting from the beginning, I'm currently struggling with it myself; at this time there's no clear way to do this (no resume(), pause(false) etc.), and I've seen a few more questions on the subject on Google and SO, so you're not alone. I've experimented with the seek method, but with no luck. I'll post a comment if/when I reach a breakthrough on that. :)
EDIT: I figured out the play-from-beginning thing. It does involve "seek", and also the whole "instance ID" concept (which I never really understood the importance of from the documentation).
Here's an example from a project I'm working on (also a game); it doesn't involve JQuery (sorry), but it should give you the gist of how to fix the problem.
var myBgMusic = new Howl(...);
var myMusicID = myBgMusic.play(); // The docs say play() returns an ID, and I'll be passing that to "seek" later.
var paused = false;
var saveSeek;
function TogglePause() {
if (paused) {
myBgMusic.play(myMusicID);
myBgMusic.seek(saveSeek, myMusicID);
} else {
myBgMusic.pause();
saveSeek = myBgMusic.seek(myMusicID);
}
};

youtube repeat oneliner

I am trying to make a oneliner to repeat videos.
I started looking for that replay button to trigger another round:
$("[title='Replay']")[0].click();
A self calling function to loop in the background while the vid is running.
rpt=function(){setTimeout(function(){alert("blarg");rpt()},5000)}
putting those two things together and adding a tiny bit of fluff:
$ = jQuery to initialize shiny $()-syntax and finally rpt();to get things rolling:
$=jQuery,rpt=function(){setTimeout(function(){$("[title='Replay']")[0].click(),rpt()},100)};rpt();
alas, the parts work but not the whole thing
I noticed that the console is printing an error message if I enter the final line before the video has finished; since the button is not found yet and therefore a call to .click() on undefined isn't working.
Shouldn't the function still loop in the background and trigger during a later call, as soon as the replay button is there for jQuery to grab?
I'm using chrome 44.0.2403.130 and jQuery: 1.10.1
Add a verification to make sure there is a replay element available.
Use setInterval() instead of setTimeout().
By default (and unless you use other conflicting libraries), jQuery is assigned to the $ variable on its initialization.
setInterval(function(){if($("[title='Replay']").length)$("[title='Replay']").trigger('click');},100);
one line repeat + number of repeat appended in title:
var title=$('#eow-title').innerHTML; var replaysN = 1; setInterval(function(){if($('.ytp-play-button').title == 'Replay') {$('.ytp-play-button').click();$('#eow-title').innerHTML = title+' (x'+replaysN+')';replaysN++;} }, 1000);
..after some weeks after making this post, there was a new feature in youtube :D
After right-click on video -> Loop
So every customization is useless :)

Cocos2d-html5 - Restarting/quitting engine possible?

With Cocos2d-html5, is there any way to “quit” the engine and re-initialize its state so you can later restart the engine. We are using a Cocos2d game in a single page web app. If the user navigates to another page, we want to programmatically remove the canvas div and attempt to exit the Cocos2d engine. Unfortunately, it seems there’s no good way to do this and attempting to load a new game causes errors.
How can you cleanly unload a scene and quit the engine?
We are using V3.1 and tried several approaches, none of them seem to work. For example:
Trying to reset many variables that are held in the cc object (detailed below). This approach forces you to reset variables that look private as they start with _ and are not in the documentation.
picking, choosing and rewriting some of CCBoot.js but this appeared complicated and not sustainable for engine updates as so much of it is depended upon throughout the library.
Other approaches I thought of but all sound like a hack:
3. Null the whole cc object and somehow run the script again but that might mean stripping out a script tag or module and adding and running it again.
4. Wrap the cc object in another object so it is easier to reset. CCBoot.js looks like it might attach some things to the window object.
I have got furthest with the first approach but am stuck with context issues. When leaving the canvas, before I remove it from the DOM I call these:
// Remove anything that might possibly keep a reference to the old context
cc.textureCache.removeAllTextures();
cc._drawingUtil = null;
cc.stencilBits = null;
// Purge the cc.director, schedules, event listeners, running scene, animations, cached data.
cc.director.purgeDirector();
// Remove references to the context
cc._renderContext = null;
cc.webglContext = null;
window.gl = null;
cc._mainRenderContextBackup = null;
// Remove reference to DOM elements
cc._canvas = null;
cc.container = null;
cc._gameDiv = null;
// Reset CCBoot variables that might stop us from re-initialising
cc._rendererInitialized = false;
cc._setupCalled = false;
cc._renderType = -1;
Then when we restart on the second or subsequent time call
// Reset all system and flag variables
cc._initSys(cc.game.config, cc.game.CONFIG_KEY);
cc.game.run();
And here are the kind of errors I get. It looks like it's not properly resetting the context:
WebGL: INVALID_OPERATION: bindTexture: object not from this context
WebGL: INVALID_OPERATION: texImage2D: no texture
WebGL: INVALID_OPERATION: uniformMatrix4fv: location is not from current program
WebGL: INVALID_OPERATION: vertexAttribPointer: no bound ARRAY_BUFFER
I've managed to get it stopping/resuming enough for a specific use case now, here is a demo:
http://plnkr.co/edit/BQmmHi?p=preview
There is now a public way to pause a game in v3.13, so I can call:
cc.game.pause();
followed by removing the cc.container from the DOM:
cc.container.parentNode.removeChild(cc.container);
Then I can place it back in the DOM again anywhere I would like:
targetContainerEl.appendChild(cc.container);
Then resume the game by calling:
cc.game.resume();
Note: The next line was was needed after replacing in the DOM in a complex app in cocos2d v3.5, but not sure if it's needed in v3.13 any more:
cc.EGLView._instance._frame = cc.container.parentNode;
The demo from the link above is being removed and placed in 2 different DOM elements and pausing/resuming.

Trigger on DOM text changed

Im developing some web-automatization tool (C# but this topic is not abou it..).
Tool unsing WebBrowser as a browser and connect to some web-site.
Web site has dynamic content, it updates once per second. Web site using setTimeout to update its content. Then data resopnsed web site update content inside DOM element (table). Its delete 3 old rows and insert 3 new rows.
My target is to make a trigger for this event.
I checked and the website doesn't use document.write. As I understand there are some ways the site can modify content. First is innerHTML property, but table has 4 rows , site dont update/delete first row. So another way is appendChild and removeChild its more real.
So my question is how i can trigger this action?
As i know it possible to define my own funcs for DOM element. So how i can redefine appendChild and removeChild methods?
Possible something like this?:
var realRC = contentTable.removeChild;
contentTable.removeChild = function(el){
alert("Trigged!");
realRC(el);
}
I assume you mean trigger when you say "trig".
Triggering it
In browsers timeouts and intervals all have IDs, you can clear them but you can't trigger it directly. The best bet would be looking for setTimeout/setInterval statements and replicating them.
Listening to the event
Anyway, there is a dirty way and a clean way. Let's assume you have access to your table in:
var target = document.querySelector('#some-id');
The clean way would be using DOM Mutation Observers
// Example from MDN
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.type); // here you'll get the changes
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
The dirty way would be dirty checking
It's better supported and more stable since observers are really new and there are still issues.
Every 16 miliseconds check if the .innerHTML value of the table changed.
var oldHTML = "";
setTimeout(function(){
if(target.innerHTML !== oldHTML){
changed(); // changed is a function that you define and notify
}
},16);
If there are HTML changes like position/etc you can use .textContent instead.
Honestly, the dirty way is simpler and more stable - but uglier. Still I'd go for it.
Benjamin Gruenbaum solve it)
Im post this here for more readable!
var dataTable = document.getElementById("event_1538016");
dataTable.appendChild = function(node)
{
console.log("trigged!");
document.appendChild.apply(dataTable,[node]); // args is array!!
return node;
}
works perfectly on mozilla! Im hope it will works on IE9+

mediaElementjs: how to get instance of the player

I'm stuck with a little problem with MediaElement.js player.
To get the instance of the player, I do this (works with html5 compatible browser):
// Get player
this.playerId = $('div#shotlist-player video').attr('id');
this.player = window[this.playerId];
But it's not working as soon as it fallback in flash. In fact, it's not working because I'm not calling an instance of MediaElement itself. But I don't see how I can call it.
The player is created with
$('video').mediaelementplayer({....});
How can I get the mediaelement object?
------------EDIT----------------
Ok I finally found how to make it works:
// Get player
mePlayer = $('div#shotlist-player video.video-js')[0];
this.player = new MediaElementPlayer(mePlayer);
Now I can user mediaElement instance correctly.
This post is a lot of speculation, but may be correct. Docs are lacking (;
The answer by sidonaldson is perfectly acceptable if you wish to create a new MediaElement instance and get a handle on it. If there's one already present, it seems to try to reinitialize another instance on that element and freaks out.
I am pretty sure mediaelement.js augments the builtin HTML5 controls by providing a JavaScript API to manipulate Flash/Silverlight players via those elements. I may be wrong, but other advice I've seen on this issue in multiple places is to do something like:
$playButton.click(function() {
$('video, audio').each(function() {
$(this)[0].player.play();
});
});
To create a play button as an external DOM element which will fire off all players on the page. This indicates to me that the implementation is something like I've described.
Try:
var player = $('video').mediaelementplayer({
success: function (me) {
me.play();
}
});
// then you can use player.id to return the id
// or player.play();

Categories