jQuery's toggle class requires two clicks in Internet Explorer? - javascript

Works great in Firefox / Chrome / Microsoft Edge, but when the button is clicked in the latest Internet Explorer 11, it takes two clicks to toggle class when it should only take one. Everything else performs as it should (it plays and stops the music when it should).
JSFiddle Example
<script>
$(".play").on('click', function () {
var key = $(this).attr('key');
EvalSound(this, key);
var this_play = $(this);
$(".play").each(function () {
if ($(this)[0] != this_play[0]) {
$(this).removeClass("pause");
}
});
$(this).toggleClass("pause");
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
});
if (currentKey !== key) thissound.src = "exclusive/" + key + ".mp3";
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
thissound.currentTime = 0;
currentPlayer = thissound;
}
</script>

Since toggleClass normally works in IE I think the problem was just something to do with the way this code was written: Here is an IE one click working version in JS Fiddle: http://jsfiddle.net/jeffd/2fjnmdkb/22/
$(".play").on('click', function () {
var key = $(this).attr('key');
var this_play = $(this);
$(".play").each(function () {
if ($(this)[0] != this_play[0]) {
$(this).removeClass("pause");
}
});
$(this).toggleClass("pause");
var player_bottom = $(".playerbottom");
if (currentKey == key || !player_bottom.hasClass('pausebottom')) {
player_bottom.toggleClass("pausebottom");
}
EvalSound(this, key);
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
$(".playerbottom").removeClass("pausebottom");
});
if (currentKey !== key) thissound.src = "http://99centbeats.com/1e4cb5f584d055a0992385c1b2155786/" + key + ".mp3";
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
//thissound.currentTime = 0;
currentPlayer = thissound;
}
$(".volume_slider").slider({
value : 75,
step : 1,
range : 'min',
min : 0,
max : 100,
slide : function(){
var value = $(".volume_slider").slider("value");
thissound.volume = (value / 100);
}
});

Related

Javascript function triggered twice

I currently have a javascript application that plays a couple of videos and asks a series of questions, based on the wait time in each question.
However, after a new video is triggered (2th video), my code skips the first question and I can't really find out why. Any ideas? Thank you.
Settings.js
var settings = {
'appname': 'ExperimentX',
'masterpassword': 'xxxx'
};
var videos = [
{
'video': 'movie 1.mp4',
'questions': [
{
'text': `
blabla
`,
'wait': 2 * 60 + 51
},
{
'text': 'How sad are you right now',
'wait': 1 * 60 + 57
},
{
'text': '',
'wait': 57
}
]
},
{
'video': 'movie 2.mp4',
'questions': [
{
'text': 'How happy are you right now',
'wait': 2
},
{
'text': 'How sad are you right now',
'wait': 5
}
]
}
}
And the real JS code:
// -- base settings
identifier = new Date().getTime();
videos_path = 'videos/';
// -- create elements
var player = videojs('video');
var slider = $('#ex1');
// -- variables
var debug = true;
var timer = null;
var questions = [];
var currquestion = 0;
var currvideo = 0;
function log(msg){
if (debug)
console.log(msg);
}
function checkForLocalStorage(){
var result = false;
try {
result = (typeof window.localStorage == 'undefined');
} catch (err){
result = false;
}
return result;
}
function save(key, value){
log('Saving ' + key + ' -> ' + value);
var sessionObject = localStorage.getItem( identifier );
sessionObject = (null == sessionObject) ? {} : JSON.parse(sessionObject);
sessionObject[key] = value;
localStorage.setItem(identifier, JSON.stringify(sessionObject));
}
function toDate(ms){
var d = new Date(0);
d.setUTCSeconds(ms / 1000);
return d.toLocaleString();
}
function loadAll(){
var result = [];
log('Loading from localstorage:');
for (var i = 0; i < localStorage.length; i++){
var key = localStorage.key(i);
var obj = JSON.parse( localStorage.getItem(key) );
obj['timestamp'] = toDate(key);
log(obj);
result.push( obj );
}
return result;
}
function refreshVideoCount(){
log('Refreshing video counter');
$('#currvideoCounter').text( currvideo +1 );
$('#totalvideoCounter').text( videos.length );
}
function showEnd(){
log('Showing end page');
$('#ending').removeClass('hidden');
$('#videoPlayer').addClass('hidden');
$('#menuEnd').addClass('active');
$('#menuVideos').removeClass('active');
}
function showQuestion(){
console.log('Showing question, currquestion ' + currquestion + ' currvideo ' + currvideo);
clearTimeout(timer);
$('#modalTitle').html( questions[currquestion]['text'] );
$('#modalQuestion').modal('show');
$('#btnModal').on('click', function(){
log('btnModal clicked, saving answer');
save('V' + currvideo + ' Q' + currquestion, slider.slider('getValue'));
log('Refreshing slider');
slider.slider('refresh');
var next = (currquestion >= questions.length-1);
if (next == true){
log('currquestion is the last one, cycling to next video');
currvideo = currvideo +1;
currquestion = 0;
cycleVideos();
} else {
log('cycling to next question of this video');
currquestion = currquestion +1;
cycleQuestions();
}
});
}
function cycleQuestions(){
log('Resuming video');
var questionText = questions[currquestion]['text'];
var questionWait = questions[currquestion]['wait'];
player.play();
if (timer){
log('Clearing timer (cycleQuestions)');
clearTimeout(timer);
timer = null;
}
log('Setting new timer');
timer = setTimeout(function(){
log('Timer triggered, pausing player and showing question');
player.pause();
showQuestion();
}, questionWait * 1000);
}
function cycleVideos(){
log('Cycling to next video');
if (timer){
log('Clearing timer (cycleVideos)');
clearTimeout(timer);
timer = null;
}
if (currvideo > videos.length -1){
log('Video is the last one, showing end page');
player.pause();
player.exitFullscreen();
return showEnd();
}
log('Setting videofile and question variable');
videoFile = videos_path + videos[currvideo]['video'];
questions = videos[currvideo]['questions'];
refreshVideoCount();
log('Playing player');
player.src({ 'src' : videoFile });
player.play();
cycleQuestions();
}
function showOverview(){
log('Showing management page');
$('#intro').addClass('hidden');
$('#overview').removeClass('hidden');
var items = loadAll();
var content = '';
log('Generating table');
var table =
$('<table>')
.addClass('table')
.append('<thead><tr>');
for (var prop in items[0])
table.append('<th>' + prop + '</th>');
table
.append('</tr></thead>')
.append('<tbody>');
items.forEach(function(object){
// for every entry
var row = '<tr>';
for (var property in items[0]) {
if (object.hasOwnProperty(property)) {
// for every property
row = row.concat(
'<td>' + object[property] + '</td>'
);
}
}
row.concat('</tr>');
table.append(row);
});
table.append('</table>');
$('#overviewText').html(table);
$('#btnClear').on('click', function(){
log('Clearing storage');
if ( confirm('Do you really want to clear all results?') ){
localStorage.clear();
location.reload();
}
});
}
function showIntro(){
log('Showing intro page');
$('#menuIntro').addClass('active');
refreshVideoCount();
$('#intro').removeClass('hidden');
$('#introInput').keyup(function(event){
if(event.keyCode == 13)
$("#introBtn").click();
});
$('#introBtn').on('click', function(){
var name = $('#introInput').val();
var age = $('#introAge').val();
var gender = $('#introGender').val();
if (name.trim().length == 0)
return alert('You need to fill in your name.');
if (age.trim().length == 0)
return alert('You need to fill in your age.');
if (name === settings['masterpassword'])
return showOverview();
save('name', name);
save('age', age);
save('gender', gender);
$('#intro').addClass('hidden');
$('#videoPlayer').removeClass('hidden');
$('#menuIntro').removeClass('active');
$('#menuVideos').addClass('active');
slider.slider({});
player.requestFullscreen();
cycleVideos();
});
}
function disableRefresh(){
log('Disabling F5');
$(document).on("keydown", function(e){
if ((e.which || e.keyCode) == 116)
e.preventDefault();
});
}
// setup base stuff
checkForLocalStorage();
$('#logo').text( settings['appname'] );
$('#title').text( settings['appname'] );
disableRefresh();
// show intro page
showIntro( identifier );

Re Toggle / Re add the class of a variable in jquery

I am devoloping a master control panel for an audio player, Everything works fine except for if I play another track while one track is already playing then hit stop on the master control then hit play again on the master control it doesn't add the class ".pause" back to the track.
JsFiddle: http://jsfiddle.net/jeffd/2fjnmdkb/15/
$(".play").on('click', function () {
var key = $(this).attr('key');
var nowplay = $(this); // variable for now playing class .play
EvalSound(this, key);
$(".play").not(this).removeClass("pause");
$(this).toggleClass("pause");
$(this).hasClass("pause") ? $(".playerbottom").addClass("pausebottom") : $(".playerbottom").removeClass("pausebottom");
$(".playerbottom").on('click', function () {
nowplay.toggleClass("pause");
$(".play").not(nowplay).removeClass("pause");
});
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
$(".playerbottom").removeClass("pausebottom");
});
if (currentKey !== key) thissound.src = "http://99centbeats.com/1e4cb5f584d055a0992385c1b2155786/" + key;
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
currentPlayer = thissound;
}
$(".volume_slider").slider({
value : 75,
step : 1,
range : 'min',
min : 0,
max : 100,
slide : function(){
var value = $(".volume_slider").slider("value");
thissound.volume = (value / 100);
}
});
$(".playerbottom").on('click', function () {
$(this).toggleClass("pausebottom");
if (thissound.paused) thissound.play();
else thissound.pause();
});
after making nowplay a global variable it works: window.nowplay = $(this);
Working Solution: http://jsfiddle.net/jeffd/2gbz7agp/
$(".play").on('click', function () {
var key = $(this).attr('key');
window.nowplay = $(this); // variable for now playing class .play
EvalSound(this, key);
$(".play").not(this).removeClass("pause");
$(this).toggleClass("pause");
$(this).hasClass("pause") ? $(".playerbottom").addClass("pausebottom") : $(".playerbottom").removeClass("pausebottom");
$(".playerbottom").on('click', function () {
$(this).hasClass("pausebottom") ? nowplay.addClass("pause") : nowplay.removeClass("pause");
});
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
$(".playerbottom").removeClass("pausebottom");
});
if (currentKey !== key) thissound.src = "http://99centbeats.com/1e4cb5f584d055a0992385c1b2155786/" + key;
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
currentPlayer = thissound;
}
$(".volume_slider").slider({
value : 75,
step : 1,
range : 'min',
min : 0,
max : 100,
slide : function(){
var value = $(".volume_slider").slider("value");
thissound.volume = (value / 100);
}
});
$(".playerbottom").on('click', function () {
$(this).toggleClass("pausebottom");
if (thissound.paused) thissound.play();
else thissound.pause();
});

Jquery Slider that controls jquery audio player

I am working on an audio slider for a jquery player the goal is to get the audio slider to control the volume. The audio player is initiated using Jquery instead of the audio tags and has the class .play For some reason the slider isn't changing volume.
Edit: Working Solution - http://jsfiddle.net/jeffd/2fjnmdkb/2/
JS Fiddle: http://jsfiddle.net/jeffd/2fjnmdkb/1/
$(".play").on('click', function () {
var key = $(this).attr('key');
EvalSound(this, key);
var this_play = $(this);
$(".play").each(function () {
if ($(this)[0] != this_play[0]) {
$(this).removeClass("pause");
}
});
$(this).toggleClass("pause");
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
});
if (currentKey !== key) thissound.src = "http://99centbeats.com/1e4cb5f584d055a0992385c1b2155786/" + key + ".mp3";
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
thissound.currentTime = 0;
currentPlayer = thissound;
}
$(".volume_slider").slider({
value : 75,
step : 1,
range : 'min',
min : 0,
max : 100,
slide : function(){
var value = $(".volume_slider").slider("value");
$('.play').prop('volume', (value/100));
}
});
I changed .play selector to the var thissound and it works
Working Js Fiddle: http://jsfiddle.net/jeffd/2fjnmdkb/2/
$(".play").on('click', function () {
var key = $(this).attr('key');
EvalSound(this, key);
var this_play = $(this);
$(".play").each(function () {
if ($(this)[0] != this_play[0]) {
$(this).removeClass("pause");
}
});
$(this).toggleClass("pause");
});
var thissound = new Audio();
var currentKey;
function EvalSound(el, key) {
thissound.addEventListener('ended', function () {
// done playing
$(el).removeClass("pause");
});
if (currentKey !== key) thissound.src = "http://99centbeats.com/1e4cb5f584d055a0992385c1b2155786/" + key + ".mp3";
currentKey = key;
if (thissound.paused) thissound.play();
else thissound.pause();
thissound.currentTime = 0;
currentPlayer = thissound;
}
$(".volume_slider").slider({
value : 75,
step : 1,
range : 'min',
min : 0,
max : 100,
slide : function(){
var value = $(".volume_slider").slider("value");
thissound.volume = (value / 100);
}
});

Up/Down/Left/Right keyboard navigation with jQuery?

I have a list of div's all with a set and equal height/width that are float:left so they sit next to each other and fold under if that parent is smaller than the combined with of the items.
Pretty standard.
This is to create a list of the twitter bootstrap icons, it gives something like this:
I have added next/previous keyboard navigation using the code below, however you will notice that the up/down arrow keys are mapped to call the left/right functions. What I have no idea how to do is to actually do the up/down navigation?
JsFiddle
(function ($) {
$.widget("ui.iconSelect", {
// default options
options: {
},
$select: null,
$wrapper: null,
$list: null,
$filter: null,
$active: null,
icons: {},
keys: {
left: 37,
up: 38,
right: 39,
down: 40
},
//initialization function
_create: function () {
var that = this;
that.$select = that.element;
that.$wrapper = $('<div class="select-icon" tabindex="0"></div>');
that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper);
that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper);
//build the list of icons
that.element.find('option').each(function () {
var $option = $(this);
var icon = $option.val();
that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>');
if ($option.is(':selected')) {
that.icons[icon].addClass('selected active');
}
that.$list.append(that.icons[icon]);
});
that.$wrapper.insertBefore(that.$select);
that.$select.addClass('hide');
that._setupArrowKeysHandler();
that._setupClickHandler();
that._setupFilter();
that.focus('selected');
},
focus: function (type) {
var that = this;
if (that.$active === null || that.$active.length == 0) {
if (type == 'first') {
that.$active = that.$list.find('a:visible:first');
} else if (type == 'last') {
that.$active = that.$list.find('a:visible:last');
} else if (type == 'selected') {
that.$active = that.$list.find('a.selected:visible:first');
that.focus('first');
}
}
that.$active.addClass('active');
var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2;
//that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2);
that.$list.stop(true).animate({
scrollTop: toScroll,
queue: false,
easing: 'linear'
}, 200);
if (type === 'selected') {
return false;
}
that.$select.val(that.$active.data('class'));
that.$select.trigger('change');
},
_setupArrowKeysHandler: function () {
var that = this;
that.$wrapper.on('keydown', function (e) {
switch (e.which) {
case that.keys.left:
that.moveLeft();
break;
case that.keys.up:
that.moveUp();
break;
case that.keys.right:
that.moveRight();
break;
case that.keys.down:
that.moveDown();
break;
case 16:
return true;
case 9:
return true;
break;
default:
that.$filter.focus();
return true;
}
return false;
});
},
_setupFilter: function(){
var that = this;
that.$filter.on('keydown keyup keypress paste cut change', function(e){
that.filter(that.$filter.val());
});
},
_setupClickHandler: function () {
var that = this;
that.$list.on('click', 'a', function () {
that.$wrapper.focus();
that.$active.removeClass('active');
that.$active = $(this);
that.focus('first');
});
},
moveUp: function () {
var that = this;
return that.moveLeft();
},
moveDown: function () {
var that = this;
return that.moveRight();
},
moveLeft: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.prevAll(':visible:first');
that.focus('last');
return false;
},
moveRight: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.nextAll(':visible:first');
that.focus('first');
return false;
},
filter: function(word){
var that = this;
var regexp = new RegExp(word.toLowerCase());
var found = false;
$.each(that.icons, function(i, $v){
found = regexp.test(i);
if(found && !$v.is(':visible')){
$v.show();
} else if(!found && $v.is(':visible')){
$v.hide();
}
});
}
});
})(jQuery);
Perhaps something like this: http://jsfiddle.net/QFzCY/
var blocksPerRow = 4;
$("body").on("keydown", function(e){
var thisIndex = $(".selected").index();
var newIndex = null;
if(e.keyCode === 38) {
// up
newIndex = thisIndex - blocksPerRow;
}
else if(e.keyCode === 40) {
// down
newIndex = thisIndex + blocksPerRow;
}
if(newIndex !== null) {
$(".test").eq(newIndex).addClass("selected").siblings().removeClass("selected");
}
});
Basically, you set how many items there are in a row and then find the current index and subtract or add that amount to select the next element via the new index.
If you need to know how many blocks per row there are, you could do this:
var offset = null;
var blocksPerRow = 0;
$(".test").each(function(){
if(offset === null) {
offset = $(this).offset().top;
}
else if($(this).offset().top !== offset) {
return false;
}
blocksPerRow++;
});
To deal with your 'edge' cases, you could do:
if(newIndex >= $(".test").length) {
newIndex = $(".test").length - newIndex;
}
moveUp: function () {
var that = this;
var index = $(this).index();
var containerWidth = parseInt( $('.select-icon-list').innerWidth(), 10);
var iconWidth = parseInt( $('.select-icon-list > a').width(), 10);
var noOfCols = Math.floor( containerWidth / iconWidth );
var newIndex = ( (index - noOfCols) < 0 ) ? index : (index - noOfCols);
var elem = $('.select-icon-list > a')[index];
},
Cache what ever remains static.

onHashChange: native Javascript function works well, but!

I found this peace of code some where on the web.
I tried it and it works fine:
var onHashChange = function(event) {
//get hash function
var getHashValue = function() {
var arr = window.location.hash.split("#");
var hasValue = arr[1];
//sets default
if (typeof hasValue == "undefined") {
return false;
}
var hashLen = hasValue.indexOf("?");
if(hashLen>0){
hasValue = hasValue.substring(0,hashLen);
}
return hasValue;
}
//last hash
var lastHash = getHashValue();
//checker
(function watchHash() {
var hash = getHashValue();
if (hash !== lastHash) {
event();
lastHash = hash;
}
var t = setTimeout(watchHash, 100);
})();
}
BUT when the function that would be called in the onHashChange many time, it will be repeated for ever.
onHashChange(function() {
console.log("changed");
});
when am at the same page and the hash is being changed, the console.log will be full of "changed" text even when I made only 3 changes for the hash in the page!
Well, am calling a function "instead of console.log" that at the same time will callback onHashChange again
Any trick to get over it?
Thanks :)
This should work well on hash change and url change via history.replaceState and history.pushState!
var onUrlChange = function(event) {
var getHashValue = function () {
var arr = window.location.hash.split("#");
var hasValue = arr[1];
if (typeof hasValue == "undefined") {
return false;
}
var hashLen = hasValue.indexOf("?");
if (hashLen > 0) {
hasValue = hasValue.substring(0, hashLen);
}
return hasValue;
}
var getUrlValue = function () {return window.location.pathname;}
var lastHash = getHashValue();
var lastUrl = getUrlValue();
(function watchPath() {
var hash = getHashValue();
var url = getUrlValue();
if (hash !== lastHash) {
event();
lastHash = hash;
}
if (url !== lastUrl) {
event();
lastUrl = url;
}
var t = setTimeout(watchPath, 100);
})();
}
onUrlChange(function () {
//somthing
});

Categories