NEED HELP. Author has abandoned to fix this jQuery plugin! - javascript

I am trying to implemented this jQuery news ticker style plugin from http://www.makemineatriple.com/2007/10/bbcnewsticker
Like mentioned in the comments (around May) there is a bug and the author lost its will to give a bug fix.
The bug is:
In Mac browsers (Firefox, Opera and Safari, all OSX) - links (a href) don’t ‘work’ until each list item has finished scrolling/revealing. Basically after this plugin has loaded, all the a href stops working.
Here is the code for the plugin (http://plugins.jquery.com/project/BBCnewsTicker):
/*
News ticker plugin (BBC news style)
Bryan Gullan,2007-2010
version 2.2
updated 2010-04-04
Documentation at http://www.makemineatriple.com/news-ticker-documentation/
Demo at http://www.makemineatriple.com/jquery/?newsTicker
Use and distrubute freely with this header intact.
*/
(function($) {
var name='newsTicker';
function runTicker(settings) {
tickerData = $(settings.newsList).data('newsTicker');
if(tickerData.currentItem > tickerData.newsItemCounter){
// if we've looped to beyond the last item in the list, start over
tickerData.currentItem = 0;
}
else if (tickerData.currentItem < 0) {
// if we've looped back before the first item, move to the last one
tickerData.currentItem = tickerData.newsItemCounter;
}
if(tickerData.currentPosition == 0) {
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList).empty().append('<li></li>');
}
else {
$(tickerData.newsList).empty().append('<li></li>');
}
}
//only start the ticker itself if it's defined as animating: otherwise it's paused or under manual advance
if (tickerData.animating) {
if( tickerData.currentPosition % 2 == 0) {
var placeHolder = tickerData.placeHolder1;
}
else {
var placeHolder = tickerData.placeHolder2;
}
if( tickerData.currentPosition < tickerData.newsItems[tickerData.currentItem].length) {
// we haven't completed ticking out the current item
var tickerText = tickerData.newsItems[tickerData.currentItem].substring(0,tickerData.currentPosition);
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerText + placeHolder);
}
else {
$(tickerData.newsList + ' li').text(tickerText + placeHolder);
}
tickerData.currentPosition ++;
setTimeout(function(){runTicker(settings); settings = null;},tickerData.tickerRate);
}
else {
// we're on the last letter of the current item
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerData.newsItems[tickerData.currentItem]);
}
else {
$(tickerData.newsList + ' li').text(tickerData.newsItems[tickerData.currentItem]);
}
setTimeout(function(){
if (tickerData.animating) {
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(settings); settings = null;
}
},tickerData.loopDelay);
}
}
else {// settings.animating == false
// display the full text of the current item
var tickerText = tickerData.newsItems[tickerData.currentItem];
if(tickerData.newsLinks[tickerData.currentItem].length > 0) {
$(tickerData.newsList + ' li a').text(tickerText);
}
else {
$(tickerData.newsList + ' li').text(tickerText);
}
}
}
// Core plugin setup and config
jQuery.fn[name] = function(options) {
// Add or overwrite options onto defaults
var settings = jQuery.extend({}, jQuery.fn.newsTicker.defaults, options);
var newsItems = new Array();
var newsLinks = new Array();
var newsItemCounter = 0;
// Hide the static list items
$(settings.newsList + ' li').hide();
// Store the items and links in arrays for output
$(settings.newsList + ' li').each(function(){
if($(this).children('a').length) {
newsItems[newsItemCounter] = $(this).children('a').text();
newsLinks[newsItemCounter] = $(this).children('a').attr('href');
}
else {
newsItems[newsItemCounter] = $(this).text();
newsLinks[newsItemCounter] = '';
}
newsItemCounter ++;
});
var tickerElement = $(settings.newsList); // for quick reference below
tickerElement.data(name, {
newsList: settings.newsList,
tickerRate: settings.tickerRate,
startDelay: settings.startDelay,
loopDelay: settings.loopDelay,
placeHolder1: settings.placeHolder1,
placeHolder2: settings.placeHolder2,
controls: settings.controls,
ownControls: settings.ownControls,
stopOnHover: settings.stopOnHover,
newsItems: newsItems,
newsLinks: newsLinks,
newsItemCounter: newsItemCounter - 1, // -1 because we've incremented even after the last item (above)
currentItem: 0,
currentPosition: 0,
firstRun:1
})
.bind({
stop: function(event) {
// show remainder of the current item immediately
tickerData = tickerElement.data(name);
if (tickerData.animating) { // only stop if not already stopped
tickerData.animating = false;
}
},
play: function(event) {
// show 1st item with startdelay
tickerData = tickerElement.data(name);
if (!tickerData.animating) { // if already animating, don't start animating again
tickerData.animating = true;
setTimeout(function(){runTicker(tickerData); tickerData = null;},tickerData.startDelay);
}
},
resume: function(event) {
// start from next item, with no delay
tickerData = tickerElement.data(name);
if (!tickerData.animating) { // if already animating, don't start animating again
tickerData.animating = true;
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(tickerData); // no delay when resuming.
}
},
next: function(event) {
// show whole of next item
tickerData = tickerElement.data(name);
// stop (which sets as non-animating), and call runticker
$(tickerData.newsList).trigger("stop");
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem ++;
runTicker(tickerData);
},
previous: function(event) {
// show whole of previous item
tickerData = tickerElement.data(name);
// stop (which sets as non-animating), and call runticker
$(tickerData.newsList).trigger("stop");
// set the character position as 0 to ensure on resume we start at the right point
tickerData.currentPosition = 0;
tickerData.currentItem --;
runTicker(tickerData);
}
});
if (settings.stopOnHover) {
tickerElement.bind({
mouseover: function(event) {
tickerData = tickerElement.data(name);
if (tickerData.animating) { // stop if not already stopped
$(tickerData.newsList).trigger("stop");
if (tickerData.controls) { // ensure that the ticker can be resumed if controls are enabled
$('.stop').hide();
$('.resume').show();
}
}
}
});
}
tickerData = tickerElement.data(name);
// set up control buttons if the option is on
if (tickerData.controls || tickerData.ownControls) {
if (!tickerData.ownControls) {
$('<ul class="ticker-controls"><li class="play">Play</li><li class="resume">Resume</li><li class="stop">Stop</li><li class="previous">Previous</li><li class="next">Next</li></ul>').insertAfter($(tickerData.newsList));
}
$('.play').hide();
$('.resume').hide();
$('.play').click(function(event){
$(tickerData.newsList).trigger("play");
$('.play').hide();
$('.resume').hide();
$('.stop').show();
event.preventDefault();
});
$('.resume').click(function(event){
$(tickerData.newsList).trigger("resume");
$('.play').hide();
$('.resume').hide();
$('.stop').show();
event.preventDefault();
});
$('.stop').click(function(event){
$(tickerData.newsList).trigger("stop");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
$('.previous').click(function(event){
$(tickerData.newsList).trigger("previous");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
$('.next').click(function(event){
$(tickerData.newsList).trigger("next");
$('.stop').hide();
$('.resume').show();
event.preventDefault();
});
};
// tell it to play
$(tickerData.newsList).trigger("play");
};
// News ticker defaults
jQuery.fn[name].defaults = {
newsList: "#news",
tickerRate: 80,
startDelay: 100,
loopDelay: 3000,
placeHolder1: " |",
placeHolder2: "_",
controls: true,
ownControls: false,
stopOnHover: true
}
})(jQuery);
Any solutions? I am not a programmer so if someone could point out where to patch it greatly appreciated!
UPDATE: it seems only the links with ? mark becomes disabled.
Example: http://url.com/blog/index.html?page=2

I just happened to come across this post. I do still support the ticker, and there have been a few releases since last July.
The way to mitigate this issue was that there's now a "stop on hover" option, which pauses the ticker and completes (immediately) the display of an item when the user hovers over it (including of course being about to click it).
If this is still of relevance to you, if you still have issues with the latest version it'd be worth reading through the thread of comments; please do get in touch if you've still a problem (if one of the comments was yours and I missed it, then sorry!). The "official" way is to post a bug report on the jQuery plugins site, which fully tracks any reported issues, but I do try to respond to anyone who requests support via the blog.

If there are any elements with the ID of news in your document, there might be a collision happening... Might this be the case? I'd search your html document for any occurrences of id="news" and correct them, seeing as though passing the proper parameters into the plugin might require a bit of extra research.

Related

Trigger rendering of all `content-visibility: auto` elements BEFORE a user scrolls to them without blocking main thread for >50ms

I want to have a fast page-load but also not have the user see a delay before content is rendered while scrolling down the page.
I have a large html page with many <dl> elements.
To speed up page load, I have set content-visibility: auto in css. See https://web.dev/content-visibility/
dl {
content-visibility: auto;
contain-intrinsic-size: 1000px;
}
Due to the complexity of the contents of the <dl>s there is a noticeable delay when a user scrolls while the <dl>s are rendered as they come into the viewport.
Thus, soon after page-load I want to render all the offscreen <dl> straight away (before a user scrolls to them) but in such a way that it does not block the main thread and scrolling remains responsive.
So, I want to set content-visibility: visible on the <dl>s starting from the top one, and not blocking the main thread (for more than say 50ms). So, maybe allowing user interaction after rendering each <dl>.
So, I need a version of the below, that doesn't block the main thread:
document.querySelectorAll('dl').forEach(function(dlElement, currentIndex, listObj) { dlElement.style['content-visibility'] = 'visible' });
My use case: My page is of math notes, which I want all on one page to reduce friction. I use katex which (for now, before we can use mathml on chrome) produces very large and complex html, which even server-side rendered still takes a lot of time for layout and rendering on the browser.
Rather than leave this unanswered, let me paste my (unperfected) code I have been testing for the last few weeks.
// --------- Shim requestIdleCallback if not supported in browser ----------------------------------
window.requestIdleCallback =
window.requestIdleCallback ||
function (cb) {
var start = Date.now();
return setTimeout(function () {
cb({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 - (Date.now() - start));
}
});
}, 1);
}
window.cancelIdleCallback =
window.cancelIdleCallback ||
function (id) {
clearTimeout(id);
}
// Global
let isRequestIdleCallbackScheduled = false;
let nodeToRemove = null;
let isVisualUpdateScheduled = false;
let totalDlElementsLeftToShow = 0;
function startIfNeeded() {
totalDlElementsLeftToShow = document.querySelectorAll('dl:not([style*="content-visibility: visible;"]), .ra:not([style*="content-visibility: visible;"]').length;
if (totalDlElementsLeftToShow > 0) {
console.log('Not a mobile - Let\'s make things visible when we are next idle');
scheduleVisibilityChanges();
}
else {
console.log('Apparently, all visible');
}
}
function scheduleVisibilityChanges() {
// Only schedule the rIC if one has not already been set.
if (isRequestIdleCallbackScheduled) {
//console.log('returning because idle callback scheduled');
startIfNeeded();
}
isRequestIdleCallbackScheduled = true;
//console.log('scheduling visibility changes when next idle or in 30 seconds at the latest');
requestIdleCallback(processHiddenElements, { timeout: 30000 });
}
function processHiddenElements(deadline) {
// Since our operation takes a while, we only want to go ahead if we have at least 50ms.
while (deadline.timeRemaining() > 49 && totalDlElementsLeftToShow > 0) {
// console.log('time remaining is ', deadline.timeRemaining(), '- scheduling next visual update');
// Don't set content-visibility immediately wait for the next
// requestAnimationFrame callback.
scheduleVisualUpdateIfNeeded();
}
// console.log('Deadline reached, will check again the next time the user is idle if there are more events still to send');
if (totalDlElementsLeftToShow > 0) {
requestIdleCallback(processHiddenElements, { timeout: 30000 });
}
}
function scheduleVisualUpdateIfNeeded() {
if (isVisualUpdateScheduled) {
// console.log('returning - visual update already scheduled')
return;
};
isVisualUpdateScheduled = true;
// console.log('requesting animation frame');
requestAnimationFrame(setContentToVisible);
}
function setContentToVisible() {
// console.log('changing visibility of element ');
let completeHiddenNodeList = document.querySelectorAll('dl:not([style*="content-visibility: visible;"]), .ra:not([style*="content-visibility: visible;"]');
// We chunk the layout changes
let i;
let numberToChunk = 20;
if (completeHiddenNodeList.length < 20) {
numberToChunk = completeHiddenNodeList.length
}
for (i = 0; i < numberToChunk; ++i) {
completeHiddenNodeList[i].style.contentVisibility = 'visible';
}
isVisualUpdateScheduled = false;
isRequestIdleCallbackScheduled = false;
totalDlElementsLeftToShow = totalDlElementsLeftToShow - numberToChunk;
}
if (!navigator.userAgentData.mobile) {
startIfNeeded();
}

How to enable Keyboard navigation between full-screen images in ant design images

How to add keyboard navigation to this ant design full screen images as of now it is accessible only through click of pointer
This component adds a bit of bloat and I really can't see a callback for after it loads a preview. However, that being said... This code does what you want. It's pretty fragile, and might break on updates of the module.
Update: Because I felt like I was taking something away with this answer, I fixed it now so all arrows are in sync with keyboard actions.
*Final Update I fixed an issue where having more than one gallery would break things. Should be perfect now.
Here's a CodeSandbox Example
// Must be assigned to an onClick event
function onClickImage(e, parentContainer = null) {
let currentImgSRC;
if (e.currentTarget) {
currentImgSRC = e.currentTarget.querySelector("img").src;
// Keep track of our parent container, as not to include other containers
parentContainer = e.currentTarget.parentElement;
} else {
currentImgSRC = e;
}
let PreviewWrapDoms = document.getElementsByClassName(
"ant-image-preview-wrap"
);
let ImgPreviewBodyDom = document.getElementsByClassName(
"ant-image-preview-body"
)[0];
// I don't see any kind of callback accessible for when the target
// gets rendered, so we simply wait until the time is right.
setTimeout(function () {
// Previous viewers aren't self clearing, so I added that in.
// Otherwise this breaks with multiple galleries
if (typeof ImgPreviewBodyDom === "undefined" || PreviewWrapDoms.length > 1 ) {
for (let WrapIndex = 0; WrapIndex < PreviewWrapDoms.length; WrapIndex++) {
if ( window.getComputedStyle(PreviewWrapDoms[WrapIndex]).display === "none") {
PreviewWrapDoms[WrapIndex].parentElement.parentElement.remove();
}
}
onClickImage(currentImgSRC, parentContainer);
return;
}
let ImgPreviewDom = ImgPreviewBodyDom.getElementsByClassName(
"ant-image-preview-img"
)[0];
let LeftArrowDom = ImgPreviewBodyDom.getElementsByClassName(
"ant-image-preview-switch-left"
)[0];
let RightArrowDom = ImgPreviewBodyDom.getElementsByClassName(
"ant-image-preview-switch-right"
)[0];
// Assigning event listeners for the left and right arrows.
if (LeftArrowDom.getAttribute("listener") !== "true")
LeftArrowDom.addEventListener("click", (e) => {
e.preventDefault();
onClickImage(
LeftArrowDom.getAttribute("data-img-prev"),
parentContainer
);
});
LeftArrowDom.setAttribute("listener", "true");
// Now the right arrow
if (RightArrowDom.getAttribute("listener") !== "true")
RightArrowDom.addEventListener("click", (e) => {
e.preventDefault();
onClickImage(
LeftArrowDom.getAttribute("data-img-next"),
parentContainer
);
});
RightArrowDom.setAttribute("listener", "true");
// Set these previous and next img sources to the current
// for the edge cases that may be there is no next or previous
let previousImgSRC = currentImgSRC;
let nextImgSRC = currentImgSRC;
let ImgDoms = parentContainer.getElementsByClassName("ant-image-img");
// Cycle through the dom in the container to see which we are
for (let ImgDomIndex = 0; ImgDomIndex < ImgDoms.length; ImgDomIndex++) {
if (currentImgSRC === ImgDoms[ImgDomIndex].src) {
if (ImgDomIndex > 0) { //If greater than zero, we know there's a previous
previousImgSRC = ImgDoms[ImgDomIndex - 1].src;
LeftArrowDom.setAttribute("data-img-prev", previousImgSRC);
LeftArrowDom.classList.remove(
"ant-image-preview-switch-left-disabled"
);
} else {
LeftArrowDom.classList.add("ant-image-preview-switch-left-disabled");
}
if (ImgDomIndex + 1 < ImgDoms.length) { // if the next index doesn't exist, no next
nextImgSRC = ImgDoms[ImgDomIndex + 1].src;
LeftArrowDom.setAttribute("data-img-next", nextImgSRC);
RightArrowDom.classList.remove(
"ant-image-preview-switch-right-disabled"
);
} else {
RightArrowDom.classList.add(
"ant-image-preview-switch-right-disabled"
);
}
// Once we know where we are in the index, we can set the preview
// Image source to our desired result.
ImgPreviewDom.src = currentImgSRC;
// We break here because once we know our index, we don't need more
break;
}
}
// checks for keydown events on the dom.
this.onkeydown = (e) => {
e = e || window.event;
switch (e.keyCode) {
// we use recursion here to keep everything contained nicely.
case 37:
onClickImage(previousImgSRC, parentContainer);
break;
case 39:
onClickImage(nextImgSRC, parentContainer);
break;
default:
break;
}
};
}, 500);
}
Here's the code you'll need for an Image preview group:
<Image.PreviewGroup>
<Image
onClick={onClickImage}
width={200}
src="https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg"
/>
<Image
onClick={onClickImage}
width={200}
src="https://gw.alipayobjects.com/zos/antfincdn/aPkFc8Sj7n/method-draw-image.svg"
/>
</Image.PreviewGroup>
This Link can help you in similar way actually this is a image gallery that uses onclick event to open images you can use similar concept to get response.
https://www.codespeedy.com/how-to-create-a-tab-image-gallery-html-css-and-javascript/

JS - How to run something when a function has ended

Here is a code that should open and close my site's menu. The menu is divided to divs and each one is timed to enter the screen after the other.
<script type="text/javascript">
var s=0;
function menuOpen() {
if (s==0){
document.getElementById("menu_icon").src = "x.png";
document.getElementById("nav_menu").style.zIndex = "3";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.remove('loading');
}, index * 100);
});
s++;
} else {
document.getElementById("menu_icon").src = "menu_icon.png";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.add('loading');
}, index * 100);
});
s=0;
// how to make this part run after the menu has finished folding?
setTimeout(function(){
document.getElementById("nav_menu").style.zIndex = "1";
}, 1500);
}
}
</script>
The content of the page is at z-index 2. The menu when folded is at 1 and when open at 3.
Is there a way to run the command moving the menu to z-index 1 after the menu has finished folding completely?
Currently what I did was to time the animation (1600ms) and use setTimeout. But this timing will change if I'll add more lines to my menu or if someone is clicking rapidly on the menu icon.
I'm rather new to JS and Jquery so go easy on me (:
Thanks of your help.
Below you can find the code and link to jsfiddle. Unfortunetly jsfiddle blocks the animate method for unknown reason so I don't debug, but even if it code will not work :))) I hope you will cathch the idea. And also some explanation.
Firstly our items are hidden. There are two functions displayMenu and hideMenu, they are similar, but display - run animations from the top invisible, and hide - start hide items from the bottom visible. To prevent mess I use two flags and two classes, first openFlag it is say what animations should be played now. Our hide and display functions are recursive and after they end current animation(hide or show) they check openFlag, and play next hide/show or start another chain of hide/show functions. It is the most difficult to understand part) But important that with it you can click as many times as you want and all would be fine and would be never broken by clicks.
Two classes we use as animation-chain can change behaviour and we need the way to choose items that alredy visible or hidden, so this why after each animation we set only one of this classes and remove another.
Now there is one problem if all animation are ended when we click button we should start new chain of animations, but if chain has been already started we need just to switch openFlag, and when current animation stops, it will change the behaviour. So this is the reason for btnFlag it is 1 if no active chain-animations at this moment.
After the last execution of element of animation-chain it will call callback arg, that you should pass, also at this moment will set btnFlag to 0, that means that animation-chain stopped. The openFlag as you remember changed at moment og click.
function end() {
console.log("here you can set zIndex");
}
var openFlag = 0; //become 1 after we start open elems
var btnFlag = 1;
$(document).ready(function() {
$('.toggleMenu').click(function() {
if (!$('.menuBlocks').hasClass('visible')) {
if (openFlag == 0) {
openFlag = 1;
if (btnFlag) {
var items = $('.invisibleItem');
var amount = items.length;
displayMenu(0, amount, items, end);
}
}
} else {
openFlag = 0;
if (btnFlag) {
var items = $('.visibleItem');
var amount = items.length;
hideMenu(amount - 1, items, end);
}
}
});
});
function displayMenu(i, amount, items, callback) {
if (i < amount && openFlag) {
items[i].animate({
"width": "100px"
}, 1000, function() {
items[i].removeClass('invisibleItem');
items[i].addClass('visibleItem');
displayMenu(i + 1, amount, items);
});
} else if (!openFlag) {
var items = $('.visibleItem');
var amount = items.length;
hideMenu(amount - 1, items, makeToggleVisible);
} else {
btnFlag = 1; //all aniimations ended
callback();
}
}
function hideMenu(i, items, callback) {
if (i < 0 && openFlag) {
items[i].animate({
"width": "0px"
}, 1000, function() {
items[i].removeClass('visibleItem');
items[i].addClass('invisibleItem');
hideMenu(i - 1, amount, items);
});
} else if (!openFlag) {
var items = $('.invisibleItem');
var amount = items.length;
displayMenu(0, amount, items, makeToggleVisible);
} else {
btnFlag = 1; //all animations are ended
callback();
}
}
https://jsfiddle.net/ShinShil/nrtyshv5/4/
Ok fixed it.
I moved everything to jquery. Used animate and promise.
This is what came out at the end. It is a side menu that will open it's li elements one-by-one.
var s=0;
var navMenu = document.getElementById("nav_menu");
var navBtn = document.getElementById("btn");
$(document).ready(function(){
$("button").click(function(){
if (s==0) {
navMenu.style.zIndex = "4";
navBtn.classList.add('close');
$('ul').each(function() {
$(this).children().each(function(i) {
$(this).delay(i * 100).animate({left:0});
});
});
$( "li" ).promise().done(function() {
navMenu.style.zIndex = "4";
});
s++;
}
else {
navBtn.classList.remove('close');
$('ul').each(function() {
$(this).children().each(function(i) {
$(this).delay(i * 100).animate({left:"100%"});
});
});
s=0;
$( "li" ).promise().done(function() {
navMenu.style.zIndex = "1";
});
}
});
});
and with CSS transitions.
var s=0;
function menuOpen() {
if (s==0){
document.getElementById("menu_icon").src = "x.png";
document.getElementById("nav_menu").style.zIndex = "3";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.remove('loading');
}, index * 100);
});
s++;
$("#last").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
document.getElementById("nav_menu").style.zIndex = "3";
});
} else {
document.getElementById("menu_icon").src = "menu_icon.png";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.add('loading');
}, index * 100);
});
s=0;
$("#last").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
document.getElementById("nav_menu").style.zIndex = "1";
$("#nav_menu").scrollTop(0);
});
}
}

How to handle click event being called multiple times with jquery animation?

I have a click event that has a Jquery animation in it.
How can i guarantee that the animation has finished when multiple click events are being fired.
$(this._ScrollBarTrack).click(function(e) {
if(e.target === this && _self._horizontalClickScrollingFlag === false){
_self._horizontalClickScrollingFlag = true;
if(_self._isVertical){
} else{ //horizontal
if(e.offsetX > (this.firstChild.offsetWidth + this.firstChild.offsetLeft)){ // Moving Towards Right
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep + 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition+ scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition + scrollBarAmountToMove)});
_self._scrollBarCurrentStep += 1;
} else{
var scrollableAmountToMove = _self._arrayOfCellSizes[_self._scrollBarCurrentStep - 1]; // additional amount to move
var scrollableCurrentPosition = -($(_self._bodyScrollable).position().left);
var scrollBarCurrentPosition = $(_self._ScrollBarTrackPiece).position().left;
var scrollBarAmountToMove = _self.getScrollBarTrackPiecePositionBasedOnScrollablePosition(scrollableAmountToMove);
$(".event-scroll-horizontally").animate({left:-(scrollableCurrentPosition - scrollableAmountToMove)});
$(_self._ScrollBarTrackPiece).animate({left: (scrollBarCurrentPosition - scrollBarAmountToMove)});
_self._scrollBarCurrentStep -= 1;
}
}
_self._horizontalClickScrollingFlag = false;
}
});
jQuery has a hidden (I'm not sure why it's not in the docs someplace) variable $.timers that you can test against.
I made this function a long time ago to handle situations like this. Mind you, this will test to make sure there are NO animations currently being executed.
function animationsTest (callback) {
var testAnimationInterval = setInterval(function () {
if ($.timers.length === 0) { // any page animations finished
clearInterval(testAnimationInterval);
callback(); // callback function
}
}, 25);
};
Useage: jsFiddle DEMO
animationsTest(function () {
/* your code here will run when no animations are occuring */
});
If you want to test against one individually you could do a class/data route.
$('#thing').addClass('animating').animate({ left: '+=100px' }, function () {
// your callback when the animation is finished
$(this).removeClass('animating');
});
You could declare a global boolean called isAnimating and set it to true right when you begin the animation. Then add a done or complete function to the animation that sets it back to false. Then set your click event to only begin the animation if isAnimating is false.

javascript-jquery carousel function error

I am having an issue with this carousel that I am building with javaScript/jQuery.
I know I could probably find a plugin to do the same thing, but I am fairly new to javaScript and need the practice. Chrome is throwing me an
Uncaught TypeError: Undefined is not a function
I'm assuming its a syntax error, but I am unable to find it. Chrome claims in on line 42 which is the doc.ready function. What am I doing wrong?
/* carousel
has a list of items
if the list size is greater than x, only show n based on screen size
each list item is composed of an image, title, description and button
the carousel will have an arrow on the left and right, allowing users to scroll through the list items
the list should wrap
the "show" strategy is:
-- if user clicks right arrow
---- get the last visible list item
---- check for the existence of a next item
---- if there isn't a next item
------ moved the first item of the list the then end of the list
------ display it
-- the inverse is also true*/
function initFeaturedWork() {
var $work = $('.featuredWork');
var $pageWrap = $('.page-wrap');
if ($work && $work.length > 0) {
if ($work.length <= 3) {
$work.show();
} else {
$.each($work, function(index) {
if (index < 4)
$(this).show();
else return;
});
$pageWrap.before(".backArrow");
$pageWrap.after(".forwardArrow");
$(".backArrow").show();
$(".forwardArrow").show();
}
}
}
$(document).ready(function() {
initFeaturedWork();
/*
* EVENT HANDLERS
*/
$(document).on('click', '.backArrow', function(e) {
var $lastWrap = $(this).siblings('.page-wrap').last();
var $threecolumn = $lastWrap.find('.threecolumn');
var $first_visible = $threecolumn.filter(':visible').first();
var $prev = $first_visible.prev();
var $moveFirst = $threecolumn.last();
if ($prev && $prev.length > 0) {
$threecolumn.filter(':visible').last().hide();
$prev.show();
} else {
$lastWrap.prepend(moveFirst);
moveFirst.show();
}
});
$(document).on('click', '.forwardArrow', function(e) {
var $firstWrap = $(this).siblings('.page-wrap').first();
var $threecolumn = $firstWrap.find('.threecolumn');
var $last_visible = $threecolumn.filter(':visible').last();
var $next = $last_visible.next();
var $moveLast = $threecolumn.first();
if ($next && $next.length > 0) {
$threecolumn.filter(':visible').first().hide();
$next.show();
} else {
$firstWrap.prepend(moveLast);
moveLast.show();
}
});
});

Categories

Resources