if (!slideOutObserver && doc.querySelector('.slide-out-cms')) {
mutObv.observe(doc.querySelector('.slide-out-cms'), { attributeFilter: ['class'] });
slideOutObserver = true;
}
The console error is as follows: script5022: SyntxError
Which I click on and it takes me to the above code
Any ideas or workarounds?
Entire script if needed, in this script we are showing the user a cookie consent message, which overlaps some fixed elements on the page. We are doing some other things to reposition and slide things up and down based on what elements are visible:
// On document ready
$(function() {
var cookieAckId = 'cookie-acknowledgment',
pureCloudId = 'chatTrigger',
slideOutClass = 'slide-out-cms.show',
mobileContinue = 'fixed-button-container',
slideOutObserver = false,
consentText = 'This site uses essential cookies to function correctly. For more detailed information, please see our privacy policy. By continuing to use this website you consent to our use of cookies.',
mutObv;
//If the user closes/accepts the acknowledgment
function closeAck() {
// Remove the Acknowledgment from the page and shift floaters back
$('#' + cookieAckId).slideUp().queue(function() {
$(this).remove();
repositionFloaters();
});
//Kill Mutation Observer
mutObv.disconnect();
//Kill the resize listener
$(root).off('resize', repositionFloaters);
//set cookie
var d = new Date;
d.setFullYear(d.getFullYear() + 2);
$.cookie('acceptedGdprCookies', 'true', {
path: '/',
domain: '.' + browser.getDomain(),
expires: d,
});
}
// floaters are there, let's alter their position!
function repositionFloaters() {
var $cookieAck = $('#' + cookieAckId),
cookieAckHeight = 0,
$pureCloud = $('#' + pureCloudId),
$slideOut = $('.' + slideOutClass),
$mobileContinue = $('.' + mobileContinue);
if (!slideOutObserver && doc.querySelector('.slide-out-cms')) {
mutObv.observe(doc.querySelector('.slide-out-cms'), { attributeFilter: ['class'] });
slideOutObserver = true;
}
// If cookie Acknowledgment exists, grab it's height
if ($cookieAck.length) {
cookieAckHeight = $cookieAck.outerHeight();
}
// Shift up Purecloud and Slide Out if they exist
[$pureCloud, $slideOut, $mobileContinue].forEach(function($item) {
if ($item.length) {
$item.css('transform', 'translateY(-' + cookieAckHeight + 'px)');
}
});
// If both Slideout and purecloud exist, stop trying to observe for their addition
if ($pureCloud.length && $slideOut.length && cookieAckHeight > 0) {
mutObv.disconnect();
}
}
// Create the Cookie Acknowledgment
var $cookieAck = $('<div id="' + cookieAckId + '"><div class="relative"><div class="ca-text col-xs-12"><span>' + consentText + '</span><div class="ca-accept"></div></div></div>'),
$acceptBtn = $('<button class="ca-accept-btn b">ACCEPT</button>').on('click', closeAck),
$closeBtn = $('<span class="ca-close-btn icon-closepositive"></span>').on('click', closeAck);
$cookieAck.append($closeBtn);
$cookieAck.find('.ca-accept').append($acceptBtn);
$('body').append($cookieAck);
// Create Mutation Observer to watch for Purecloud and Slideout being added to the page
mutObv = new MutationObserver(repositionFloaters);
mutObv.observe(doc.body, { childList: true });
// Add Listener if the page is resized
$(root).on('resize', repositionFloaters);
// Upon creating of Cookie Acknowledgment element, try to shift floaters
repositionFloaters();
});
If anyone is happens to need the answer for this, I finally solved it!
MS Edge does not like the mutation observer without the argument attributes: true.
So the correct code would look like this:
if (!slideOutObserver && doc.querySelector('.slide-out-cms')) {
mutObv.observe(doc.querySelector('.slide-out-cms'), {
attributes: true,
attributeFilter: ['class']
});
}
Related
I have a gallery of images that load a vimeo video into an overlay. That part was very easy!!
The more difficult part:
If a user clicks one of the videos, then the remaining videos should automatically load and autoplay until the last video. I have this (almost) working too, (but I may not be doing it in the best way).
And now the trickiest part for me, and my question:
How can I get the last video to stop, and not trigger the on ended event listener?
Here is a pen on codepen I have been working on:
https://codepen.io/mginter/pen/LvMmjK
I have tried forking the logic several ways. I have also tried using the destroy method and rebuild the iframe method (but I can't get the new iframe to show up and put itself into the vacancy left by the destroy method).
I thought if I wrapped the newPlayer.on('ended', function() {}); in a separate function then I could prevent it from triggering, but NO! This is an event listener and it doesn't matter where it is in the code. I have tried turning off the event listener with the newPlayer.off(); method, but apparently I am doing it wrong.
Does anyone out there have any suggestions?? I have been at this for three days with no luck yet.
// Query All Needed Elements
var overlay = document.querySelector("#videomodal");
var iframePlayer = document.querySelector(".iframe-respwrap");
var videoIframe = document.querySelector(".iframe-respwrap iframe");
var newPlayer = new Vimeo.Player(videoIframe);
// Expose the Source Attribute of the iframe
var iframeSrcAtt = videoIframe.src;
// console.log("Iframe Source: " + iframeSrcAtt);
// Get all of the links
var allItems = document.querySelectorAll('.lightbox a');
console.log(allItems + " - Total (NodeList) Length: " + (allItems.length));
// Get source of Last Item in Array
const finalVideoSrc = allItems[allItems.length-1].children[0].dataset.vidsrc;
// Open/Close overlay
function toggleOverlay(state) { overlay.classList.toggle('video-on'); }
function closeOverlay(e) {
overlay.classList.toggle('video-on');
newPlayer.pause().then(function() {newPlayer.unload();}).catch(function(error) { console.log(error); });
}
overlay.addEventListener('click', closeOverlay, false);
// Get initial clicked item source and number
function clickedItem(e) {
e.preventDefault();
let clickedSource = e.target.dataset.vidsrc;
let clickedNumber = parseInt(e.target.parentNode.dataset.number, 10);
startVidLoop(clickedSource, clickedNumber);
}
// ------------------------------------------
// START HERE!! Add Event listener to each link
var z;
for (z=0; z < allItems.length; z++) {
// console.log(allItems[z].children[0].dataset.vidsrc);
allItems[z].addEventListener('click', clickedItem, false);
allItems[z].addEventListener('click', toggleOverlay, false);
}
function startVidLoop(vidSrc, vidNumber) {
if (vidSrc == finalVideoSrc) {
console.log("Incoming: "+ vidSrc + ", Equals Final Video in List: " + finalVideoSrc);
newPlayer.loadVideo(vidSrc).then(function(src) {console.log("END! " + src); newPlayer.play(src);}).catch(function(error) {console.log(error);});
newPlayer.off();
return;
} else {
let nextNumber = vidNumber + 1;
let comingUp = allItems[nextNumber].children[0].dataset.vidsrc;
console.log("Playing Now: "+vidNumber+" - "+vidSrc); console.log("Coming Up: "+nextNumber+" - "+comingUp);
newPlayer.loadVideo(vidSrc).then(function(src) {playVideo(src,comingUp,nextNumber);}).catch(function(error) {console.log(error);});
}
}
function playVideo(vimeoSource,nextVid,nextNumber) {
console.log("Play: " + vimeoSource + " Next: " + nextVid);
newPlayer.play(vimeoSource);
if (nextVid == finalVideoSrc) {
console.log("Last Video is Next!");
nextVid = finalVideoSrc;
}
newPlayer.on('ended', function go(data) {
startVidLoop(nextVid, nextNumber)
});
}
We are getting data from the backend and need to write it to an iframe. We have to set the iframe height to the height of the content. We can't get the correct height until the content is actually IN the iframe, which is not instantaneous for a large amount of content. Is there a callback to know when the write is done?
Right now, we have a timer, but it is brittle code:
//data received from backend
//write data to iframe
//$iframe is a jQuery DOM element
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
setTimeout(function (){
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight );
}, 1000);
Have you tried listening for the load event on the iframe?
var doc = $iframe[0].contentDocument
doc.open()
doc.write(data)
doc.close()
$iframe.on('load', function () {
this.style.height = doc.body.scrollHeight + 'px'
})
iframes do have an onload event:
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
$iframe.onload = function() {
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight);
};
Your best option is to use mutationObserver in the iFrame. This is not quite as simple as a callback I'm afraid.
Here's is the code the iFrame-resizer library uses to work this out. You would need to change the line that calls sendSize To call your callback method.
function setupBodyMutationObserver(){
function addImageLoadListners(mutation) {
function addImageLoadListener(element){
if (false === element.complete) {
console.log('Attach listeners to ' + element.src);
element.addEventListener('load', imageLoaded, false);
element.addEventListener('error', imageError, false);
elements.push(element);
}
}
if (mutation.type === 'attributes' && mutation.attributeName === 'src'){
addImageLoadListener(mutation.target);
} else if (mutation.type === 'childList'){
Array.prototype.forEach.call(
mutation.target.querySelectorAll('img'),
addImageLoadListener
);
}
}
function removeFromArray(element){
elements.splice(elements.indexOf(element),1);
}
function removeImageLoadListener(element){
console.log('Remove listeners from ' + element.src);
element.removeEventListener('load', imageLoaded, false);
element.removeEventListener('error', imageError, false);
removeFromArray(element);
}
function imageEventTriggered(event,type,typeDesc){
removeImageLoadListener(event.target);
sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined);
}
function imageLoaded(event) {
imageEventTriggered(event,'imageLoad','Image loaded');
}
function imageError(event) {
imageEventTriggered(event,'imageLoadFailed','Image load failed');
}
function mutationObserved(mutations) {
sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type);
//Deal with WebKit asyncing image loading when tags are injected into the page
mutations.forEach(addImageLoadListners);
}
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
};
observer = new MutationObserver(mutationObserved);
console.log('Create body MutationObserver');
observer.observe(target, config);
return observer;
}
var
elements = [],
MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
observer = createMutationObserver();
return {
disconnect: function (){
if ('disconnect' in observer){
console.log('Disconnect body MutationObserver');
observer.disconnect();
elements.forEach(removeImageLoadListener);
}
}
};
}
maybe postMessage will help you.
var testData = 'test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n';
var $iframe = document.querySelector('#test-iframe');
var $button = document.querySelector('button');
// listen the callback message from iframe
window.self.addEventListener('message', function(ev) {
if (ev.data && ev.data.status === 'ready') {
$iframe.style.height = ev.data.height + 'px';
}
});
$button.addEventListener('click', function() {
// render content
$iframe.contentDocument.body.innerText = testData;
// send message to the top window
window.self.postMessage({
status: 'ready',
height: $iframe.contentDocument.body.scrollHeight
}, '*');
});
`
https://jsfiddle.net/caoyy/Lb5k13bw/2/
I am attempting to implement toggling functionality into a program I am working on. Specifically, there are 3 possible scenarios when a user clicks a button.
Tool clicked while no other tool is currently active.
Tool clicked while another tool is currently active
Same tool is clicked to toggle it on/off
I am having trouble implementing this. Here is my code so far:
var toolState = {
img_draw_point: false,
img_draw_line: false,
img_draw_rectangle: false,
img_draw_ellipse: false,
img_draw_FreehandPolygon: false,
img_draw_FreehandPolyline: false,
img_draw_text: false,
img_draw_eraser: false,
};
var lastActiveTool;
on(dom.byId("div-tools-draw"), "click", function (evt) {
function disableActiveCSS() {
for (var property in toolState) {
$("img#" + property + ".k-button.single").removeClass("buttonSelected");
$("img#" + property + ".k-button.single").removeClass("buttonHoverState");
}
}
function enableCSS() {
$("img#" + evt.target.id + ".k-button.single").addClass("buttonSelected");
$("img#" + evt.target.id + ".k-button.single").addClass("buttonHoverState");
}
toolState[evt.target.id] = !toolState[evt.target.id];
if (toolState[evt.target.id] == toolState[lastActiveTool]) {
toolState[lastActiveTool] = false;
}
disableActiveCSS();
enableCSS();
if (evt.target.id == lastActiveTool) {
disableActiveCSS();
}
}
Any help would be greatly appreciated.
I see that your code contains the '$' notation so I used jQuery in my response. It also assumes that we only care if another tool is currently "ON". So the 3 options in my response are:
Turn on the selected tool if no tool is on.
Turn off the current tool and turn on the selected tool.
Turn off the current tool if it is currently on.
var lastActiveTool = false;
$.click("#div-tools-draw", function(evt) {
// Disable Active CSS
$("img.k-button.single").removeClass("buttonSelected").removeClass("buttonHoverState");
if (!lastActiveTool) {
activateTool(evt.target.id);
} else if (evt.target.id == lastActiveTool) {
sameToolToggle(evt.target.id);
} else {
otherToolToggle(evt.target.id);
}
};
var activateTool = function (id) {
$("img#" + id + ".k-button.single").addClass("buttonSelected")addClass("buttonHoverState");
lastActiveTool = evt.target.id;
};
var otherToolToggle = function(id) {
$("img#" + id + ".k-button.single").addClass("buttonSelected")addClass("buttonHoverState");
lastActiveTool = evt.target.id;
// Whatever else you need to do to toggle between tools
}
// Only gets called when the same tool is currently toggled ON
var sameToolToggle = function(id) {
lastActiveTool = false;
}
I have this notification system that works with the following jQuery / javascript and displays a notification when called.
What I am having some trouble doing and what I am trying to do is once a new notification is create to hide and remove / destroy any existing notifications.
I've tried something like this: $('.notification').not(this).hide().remove();, but that didn't work.
Here is the jQuery behind the notifications:
;(function($) {
$.notificationOptions = {
className: '',
click: function() {},
content: '',
duration: 5000,
fadeIn: 400,
fadeOut: 600,
limit: false,
queue: false,
slideUp: 200,
horizontal: 'right',
vertical: 'top',
afterShow: function(){},
afterClose: function(){}
};
var Notification = function(board, options) {
var that = this;
// build notification template
var htmlElement = $([
'<div class="notification ' + options.className + '" style="display:none">',
'<div class="close"></div>',
options.content,
'</div>'
].join(''));
// getter for template
this.getHtmlElement = function() {
return htmlElement;
};
// custom hide
this.hide = function() {
htmlElement.addClass('hiding');
htmlElement.animate({ opacity: .01 }, options.fadeOut, function() {
var queued = queue.shift();
if (queued) {
$.createNotification(queued);
}
});
htmlElement.slideUp(options.slideUp, function() {
$(this).remove();
options.afterClose();
});
};
// show in board
this.show = function() {
// append to board and show
htmlElement[options.vertical == 'top' ? 'appendTo' : 'prependTo'](board);
htmlElement.fadeIn(options.fadeIn, options.afterShow());
//$('.notification').css('marginLeft', -$('.notification').outerWidth()/2);
$('.notification-board.center').css('marginLeft', -($('.notification-board.center').width()/2));
$(window).on('resize', function(){
$('.notification-board.center').css('marginLeft', -($('.notification-board.center').width()/2));
});
};
// set custom click callback
htmlElement.on('click', function() {
options.click.apply(that);
});
// helper classes to avoid hide when hover
htmlElement.on('mouseenter', function() {
htmlElement.addClass('hover');
if (htmlElement.hasClass('hiding')) {
// recover
htmlElement.stop(true);
// reset slideUp, could not find a better way to achieve this
htmlElement.attr('style', 'opacity: ' + htmlElement.css('opacity'));
htmlElement.animate({ opacity: 1 }, options.fadeIn);
htmlElement.removeClass('hiding');
htmlElement.addClass('pending');
}
});
htmlElement.on('mouseleave', function() {
if (htmlElement.hasClass('pending')) {
// hide was pending
that.hide();
}
htmlElement.removeClass('hover');
});
// close button bind
htmlElement.children('.close').on('click', function() {
that.hide();
});
if (options.duration) {
// hide timer
setTimeout(function() {
if (htmlElement.hasClass('hover')) {
// hovering, do not hide now
htmlElement.addClass('pending');
} else {
that.hide();
}
}, options.duration);
}
return this;
};
var queue = [];
$.createNotification = function(options) {
options = $.extend({}, $.notificationOptions, options || {});
// get notification container (aka board)
var board = $('.notification-board.' + options.horizontal + '.' + options.vertical);
if (!board.length) {
board = $('<div class="notification-board ' + options.horizontal + ' ' + options.vertical + '" />');
board.appendTo('body');
}
if (options.limit && board.children('.notification:not(.hiding)').length >= options.limit) {
// limit reached
if (options.queue) {
queue.push(options);
}
return;
}
// create new notification and show
var notification = new Notification(board, options)
notification.show(board);
return notification;
};
})(jQuery);
and here is how the notifications are called / created:
$.createNotification({
horizontal:'center',
vertical:'top',
content:'No more cards at this time.',
duration:6000,
click:function(){
this.hide();
}
});
The code:
$('.notification').not(this).hide().remove();
will work just fine to remove all .notification DOM elements currently in the DOM except the current one IF this is the current notification DOM element. If that code isn't working, then it's likely because this isn't the desired notification DOM element that you want to keep. If this is an instance of your Notification class, then that's the wrong type of object. For that above code to work, this has to be the notification DOM object.
If you want to just remove all old notification DOM elements BEFORE you insert your new one, then you can just do this before your new one is in the DOM:
$('.notification').remove();
That will clear out the old ones before you insert your new one.
Since you don't have this line of code in your currently posted code, I can't tell where you were trying to use it so can't advise further on what might be wrong. Please describe further where in your code you were trying to use this.
I have this page developed for listing people out. When you click on their names I have another section built out to hold the content of that individual. It has been working fine, but now I have a need to add more than 9 people to the list.
When Adding the 10th element you can no longer click the name on the left and load the correct persons information. It is selected and jumps to the #1 element. I have provided the code below and a link to the page on https://github.com/supasmo/Management-Testing.
I need help with correcting this problem so it can take on as many people as I need to add to the list. Thanks in Advance for any suggestions.
JS
management = {
debug: true,
defaultItem: 1,
currentItem: 0,
bios: ".bios .bio",
bio: "#bio",
manager: ".managers div.bio",
managerLinks: ".managers a",
topLinks: ".bio a.top",
paging: ".bio .paging",
bioNames: ".bio h1",
yellowArrowSrc: "public/assets/common/arrow-link.png",
blueArrowSrc: "public/assets/common/arrow-link-blue.png",
init: function() {
this.log("management.init()");
// count bios
this.bioCount = $(this.bios).length;
this.log("Found " + this.bioCount + " bios.");
// hide bios, names and "top" links, show paging links
$(this.bios).hide();
$(this.topLinks).hide();
$(this.bioNames).hide();
$(this.paging).show();
// show default item
this.showItem(this.defaultItem);
// adjust bio links
$(this.managerLinks).click(function(e) {
e.preventDefault();
management.linkClick($(this).parent());
});
// enable next and prev clicks
$(this.paging + " .next").css("cursor", "pointer").click(function() {
management.nextClick();
});
$(this.paging + " .prev").css("cursor", "pointer").click(function() {
management.prevClick();
});
},
prevClick: function() {
this.log("prevClick()");
newItem = this.currentItem - 1;
if (newItem < 1) {
newItem = this.bioCount;
}
this.showItem(newItem);
},
nextClick: function() {
this.log("nextClick()");
newItem = this.currentItem + 1;
if (newItem > this.bioCount) {
newItem = 1;
}
this.showItem(newItem);
},
linkClick: function(which) {
this.showItem(which.attr("class").substr(3, 1));
},
showItem: function(which) {
this.log("showItem(" + which + ")");
if (which == this.currentItem) {
this.log("--> aborted: item is already showing");
} else {
$(this.bio + this.currentItem).hide();
$(this.bio + which).show();
$(this.manager).removeClass("current");
$(this.manager + which).addClass("current");
$(this.manager + " img.arrow").attr("src", this.yellowArrowSrc);
$(this.manager + which + " img.arrow").attr("src", this.blueArrowSrc);
this.currentItem = which;
}
},
log: function(message) {
if (this.debug) {
console.log(message);
}
},
// ===== End of Object =====
endOfObject: 1
}
$(document).ready(function() {
management.init();
});
this.showItem(which.attr("class").substr(3, 1));
This part doesn’t work for more than one digit, and is just not the right way to do that in general, since the order of classes in class is not supposed to matter. At the very least, you should use a data attribute:
<div class="bio" data-bio="10">
this.showItem(which.data("bio"));
If you want to be substringy, though, you’ve got a perfectly good link:
// adjust bio links
$(this.managerLinks).click(function(e) {
management.linkClick(this);
e.preventDefault();
});
linkClick: function(which) {
this.showItem(which.getAttribute("href").match(/\d+/)[0]);
},