Delay scrolling to anchor link - javascript

I am terrible with JS and possibly even worse at explaining what I'm doing so please bear with me. I have an external script that smooths the transitions on scrolling to anchor links. I want to delay the scroll on just one element.
External Script:
$(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
$('a[href*=#]').each(function() {
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath && (location.hostname == this.hostname || !this.hostname) && this.hash.replace(/#/,'') ) {
var $target = $(this.hash), target = this.hash;
if (target) {
var targetOffset = $target.offset().top;
$(this).click(function(event) {
event.preventDefault();
$(scrollElem).animate({scrollTop: targetOffset}, 2600, function() {
location.hash = target;
});});}}});
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}}}return [];}});
It is embedded in the main php file like so:
<script src="smoothScroll.js"></script>
So this is totally wrong but what i want to do essentially:
<a href="#whatwedo" onClick="setTimeout(smoothScroll.js, 5000)">
What would be the best way of delaying the scroll for just this one element?

I guess you could match a specific anchor value from the href statically, even though it's sloppy.
https://jsfiddle.net/cpcnsd0v/
var delay;
$('a').click(function(e) {
e.preventDefault();
delay = 0;
if ($(this).attr('href').split('#')[1] === 'whatwedo') {
delay = 1000;
}
setTimeout(function() {
// do scroll here
},delay);
});

Related

conflicting scripts not functioning

I have using 2 scripts declared on my footer. each script works perfectly when declared alone but if I declared the second one. the other function the other not.
Here is the code that works when declared alone and with the other script.
This has his own js file.
var fixed = false;
$(document).scroll(function() {
if( $(this).scrollTop() > 20 ) {
if( !fixed ) {
fixed = true;
$('.navbar-fixed-top').addClass('scroll');
}
} else {
if( fixed ) {
fixed = false;
$('.navbar-fixed-top').removeClass('scroll');
}
}
});
/*
* Smooth Scroll
*/
$(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
var locationPath = filterPath(location.pathname);
var scrollElem = scrollableElement('html', 'body');
// Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
$('a[href*=#]').each(function() {
// Ensure it's a same-page link
var thisPath = filterPath(this.pathname) || locationPath;
if ( locationPath == thisPath
&& (location.hostname == this.hostname || !this.hostname)
&& this.hash.replace(/#/,'') ) {
// Ensure target exists
var $target = $(this.hash), target = this.hash;
if (target) {
// Find location of target
var targetOffset = $target.offset().top;
$(this).click(function(event) {
// Prevent jump-down
event.preventDefault();
// Animate to target
$(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
// Set hash in URL after animation successful
location.hash = target;
});
});
}
}
});
// Use the first element that is "scrollable" (cross-browser fix?)
function scrollableElement(els) {
for (var i = 0, argLength = arguments.length; i <argLength; i++) {
var el = arguments[i],
$scrollElement = $(el);
if ($scrollElement.scrollTop()> 0) {
return el;
} else {
$scrollElement.scrollTop(1);
var isScrollable = $scrollElement.scrollTop()> 0;
$scrollElement.scrollTop(0);
if (isScrollable) {
return el;
}
}
}
return [];
}
});
The other one is this declared below the first script. now this didn't work when the other is present but works perfectly when alone. also I tried the no conflicting script but same goes for the result.
<script>
$(document).ready(function(){
$(function(){
document.querySelector( "#nav-toggle" )
.addEventListener( "click", function() {
this.classList.toggle( "active" );
$(".navmobile").slideToggle();
});
});
$(window).resize(function() {
if ($(window).width() >= 767) {
$(".navmobile").hide();
}
else {
$("#nav-toggle").removeClass("active");
$(".navmobile").hide();
}
});
});
</script>
You probably have this element in your code:
Note the href="#" part - the first script is using event.preventDefault() for every A element with href that containing "#", so the second script doesn't get click event. remove the href="#" from that element (or leave the attribute empty) and it should work.
Change
// Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
$('a[href*=#]').each(function() {
to
// Any links with hash tags in them (can't do ^= because of fully qualified URL potential)
$('a[href*=#]').not("#av-toggle").each(function() {
so the first script ignore the link you are clicking to do the toggling.

How to scroll to certain div using Javascript in two pages

I have a compare button that appears in two different pages in my project. When I click on it calls a javascript function. I want to edit this function so it does the following: first to determine which page i'm in and then scroll up to a certain DIV in this page
Here is the function:
$(function() {
$('.cont_fontsicon').click(function compareProduct(event) {
event.preventDefault();
var currentId = $(this).attr('id');
console.log("currentId : "+currentId)
if(currentId.search("#") > 0){
var span= $(this).find('span.icon-copy_icon.icon_circle_base.icon_gray_878881.bord_rad30.selected');
if ($(this).find('span').is('.selected')){
return false;
evt.preventDefault();
}
var valueSplit=currentId.split('+#+');
var currentIdCat=valueSplit[0];
var currentIdStr=valueSplit[1];
var currentPrdType=valueSplit[2];
var resultClassName = $("#prodBoxId"+currentIdStr).attr('class');
var catId = document.getElementById("category_list").value;
var catIdStr = catId.trim();
var listSize = document.getElementById("productlistSize").value;
var comparisonProductType = document.getElementById("productType").value;
var catEndecaId=currentIdCat;
var catEndecaIdStr = catEndecaId.trim();
var userHead=document.getElementById("userHeader").value;
var errorMessagesValue=document.getElementById("errorMessagesContainer").value;
if(catIdStr == 0){
addProductToComparisonList(currentIdStr,$(this),listSize);
}
/*To be uncommented if we get more than one type of product for one category
*
* if(catIdStr == catEndecaIdStr && currentPrdType==comparisonProductType){ */
else if(catIdStr == catEndecaIdStr ){
if(userHead.search("Android")>0 || userHead.search("Mobi")>0)
{ if(listSize<2 ){
addProductToComparisonList(currentIdStr,$(this),listSize);
}
else
{
$("#prodBoxId"+currentIdStr).append('<div class="error_message"><div class="cont_img_alert inline_block"></div><span class="text_error_message inline_block">'+errorMessagesValue.compare2Products+'</span></div>');
var divPosition = $('#prodBoxId'+currentIdStr+' .error_message').offset();
$('html, body').animate({scrollTop: divPosition.top}, "fast");
}
}
else
{
if(listSize<3){
addProductToComparisonList(currentIdStr,$(this),listSize);
}
else
$("#prodBoxId"+currentIdStr).append('<div class="error_message"><div class="cont_img_alert inline_block"></div><span class="text_error_message inline_block">'+errorMessagesValue.compare3Products+'</span></div>');
var divPosition = $('#prodBoxId'+currentIdStr+' .error_message').offset();
$('html, body').animate({scrollTop: divPosition.top}, "fast");
}
}
//Fix for defect# 1660
if(catIdStr != 0 && catIdStr != catEndecaIdStr ){
$("#prodBoxId"+currentIdStr).append('<div class="error_message"><div class="cont_img_alert inline_block"></div><span class="text_error_message inline_block">'+errorMessagesValue.compareSameCategory+'</span></div>');
var divPosition = $('#prodBoxId'+currentIdStr+' .error_message').offset();
$('html, body').animate({scrollTop: divPosition.top}, "fast");
}
}
else {
var loggedInUser = document.getElementById("checkLoggedIn").value;
if(loggedInUser == 'true')
{
document.getElementById(currentId).href = '#';
/*showPopUp("wishlist",currentId);*/
$(this).closest('div').find('a#customPopup').trigger("click");
}
else
{
document.getElementById(currentId).submit();
}
}
});

Start fixed position in determinated position

I have this code in Javascript:
var menuPosition = $('.scroll-nav').offset().top;
var menuPos = 110;
if (menuPosition = menuPos) {
$('.scroll-nav').addClass('stick-menu');
$('.fake-nav').removeClass('stick-menu');
}
My idea is when the position of the menuPostion be in 110px stick the .scroll-nav... but when I load the page the code is executed automaticaly.
Any idea?
EDIT
Solution to my question:
var distance = $('.scroll-nav').offset().top + 200, //+200 BECAUSE JQUERY OFFSET DONT GET MARGINS AND PADDINGS (+200 is an estimative of my total)
$window = $(window);
$window.scroll(function() {
if ( $window.scrollTop() >= distance ) {
$('.scroll-nav').addClass('is-sticky');
$('.fake-nav').removeClass('is-sticky');
}
if ( $window.scrollTop() <= distance ) {
$('.scroll-nav').removeClass('is-sticky');
$('.fake-nav').addClass('is-sticky');
}
});
Wrap this into a function and add event listener on scroll which would fire it when scrolled.
So you want to add a class if the menuPos is exactly 110? You can use:
$(document).ready(callback)
And instead of callback you can write anonymous function that will be executed when the page is loaded. You can attach a function on this item in particular.
You can write and a custom eventListener that will catch a position change on an item:
jQuery.fn.onPositionChanged = function (trigger, millis) {
if (millis == null) millis = 100;
var o = $(this[0]); // our jquery object
if (o.length < 1) return o;
var lastPos = null;
var lastOff = null;
setInterval(function () {
if (o == null || o.length < 1) return o; // abort if element is non existend eny more
if (lastPos == null) lastPos = o.position();
if (lastOff == null) lastOff = o.offset();
var newPos = o.position();
var newOff = o.offset();
if (lastPos.top != newPos.top || lastPos.left != newPos.left) {
$(this).trigger('onPositionChanged', { lastPos: lastPos, newPos: newPos });
if (typeof (trigger) == "function") trigger(lastPos, newPos);
lastPos = o.position();
}
if (lastOff.top != newOff.top || lastOff.left != newOff.left) {
$(this).trigger('onOffsetChanged', { lastOff: lastOff, newOff: newOff});
if (typeof (trigger) == "function") trigger(lastOff, newOff);
lastOff= o.offset();
}
}, millis);
return o;
};
you can trigger this event like this:
$(document).ready(function() {
$('.scroll-nav').onPositionChanged(someFunctionForExample());
}
*the condition in the if statement should be with '=='
P.s. I hope I understood your problem right. If I did not. Share some more thoughts on this so we can help

Applying a transition in between two states with Javascript behaving erratically

I'm struggling to understand why the transitions don't behave as expected. It's supposed to apply the "from", then add the "transition" to the "el", then it's supposed to run "to" and finally onTransitionEnd it's supposed to run "callback" (prepended to which is a bit of code which clears the transition properties).
In Webkit browsers, it transitions slideDown correctly, but slideUp is instant. Reverse is true in Firefox.
Erg?
JSFiddle: http://jsfiddle.net/enhTd/
var $ = function(query) {
var a = [],
n = document.querySelectorAll(query),
l = n.length;
for( var i = 0; i<l; i++){
a.push(n[i]);
}
if(l>1) {return a;} else {return a[0];}
},
$id = function(query) { return document.getElementById(query);},
getSupportedPropertyName = function(properties) {
for (var i = 0; i < properties.length; i++) {
if (typeof document.body.style[properties[i]] != "undefined") {
return properties[i];
}
}
return null;
},
vendorTransitions = ["transition", "msTransition", "webkitTransition", "MozTransition", "OTransition"],
prefixedTransitionProperty = getSupportedPropertyName(vendorTransitions),
transition = function(opts){
opts.from && opts.from();
if(prefixedTransitionProperty){
var c = opts.callback || function() {},
el = opts.el,
cb = function(event){
var ev = event, callback = c;
ev.target.removeEventListener(prefixedTransitionProperty+"End", cb);
ev.target.style[prefixedTransitionProperty] = "none";
if(callback) {
callback(ev);
}
};
el.style[prefixedTransitionProperty] = opts.transition || "";
el.addEventListener(prefixedTransitionProperty+"End", cb);
}
opts.to && opts.to();
},
slideDown = function(el, t){
var style = el.style,
h, oh = el.offsetHeight,
t = t || 1000;
//Grab real height
style.height = "";
h = el.offsetHeight;
transition({
"el": el,
transition: "height "+t+"ms ease",
from: function() {
style.height = oh+"px";
},
to: function(){
style.overflow = "hidden";
style.height = h+"px";
},
callback: function(event){
event.target.style.height = "";
}
});
},
slideUp = function(el, t){
var style = el.style,
h = el.offsetHeight,
t = t || 1000;
transition({
"el": el,
transition: "height "+t+"ms ease",
from: function() {
style.height = h+"px";
},
to: function(){
style.overflow = "hidden";
style.height = "0";
}
});
},
slideToggle = function(el, t){
var t = t || 1000;
if(el.style.height=="0px"){
slideDown(el, t);
} else {
slideUp(el, t);
}
};
slideUp($id("intro"));
$("a[href='#intro']").forEach(function(el){
el.addEventListener("click", function(ev) {
ev.preventDefault();
if(ev.target.classList.contains("hide")){
slideUp($(ev.target.hash));
} else {
slideDown($(ev.target.hash));
}
});
});
$("li h3").forEach(function(el){
el.addEventListener("click", function(ev) {
ev.preventDefault();
slideToggle(ev.target.parentNode);
});
});
In some browsers, you cannot just set the initial state, set the final state and expect a CSS transition to work.
Instead, the initial state must be set and then it must be rendered before you can set the final state and expect the transition to run. The simplest way to cause it to be rendered is to return back to the event loop and then do any further processing (like setting the final state) after a setTimeout() call.
try this: http://jsfiddle.net/enhTd/1/ (tested in chrome and ff)
first: do what jfriend00 talked about:
in your transition function:
transition = function (opts) {
..
setTimeout(function() {
opts.to && opts.to();
}, 1)
}
second: the callback wasn't necessary in your slideDown() method:
slideDown = function (el, t) {
..
take this out:
/*callback: function (event) {
event.target.style.height = "";
}*/
});
from a design point of view.. the callback function wasn't adding any value.. you should just continue from where you left off when it comes to transitions.
third: disable slide down when the slide is already down.. but I'll leave that to you.

Get caret HTML position in contenteditable DIV

I am having troubles figuring out how to get caret position in a DIV container that contains HTML tags.
I am using this JavaScript function to do that:
function getCaretPosition()
{
if (window.getSelection && window.getSelection().getRangeAt)
{
var range = window.getSelection().getRangeAt(0);
var selectedObj = window.getSelection();
var rangeCount = 0;
var childNodes = selectedObj.anchorNode.parentNode.childNodes;
for (var i = 0; i < childNodes.length; i++)
{
if (childNodes[i] == selectedObj.anchorNode)
{
break;
}
if(childNodes[i].outerHTML)
{
rangeCount += childNodes[i].outerHTML.length;
}
else if(childNodes[i].nodeType == 3)
{
rangeCount += childNodes[i].textContent.length;
}
}
return range.startOffset + rangeCount;
}
return -1;
}
However, it finds a caret position of the text in my DIV container, when I need to find the caret position including HTML tags.
For example:
<DIV class="peCont" contenteditable="true">Text goes here along with <b>some <i>HTML</i> tags</b>.</DIV>;
(please note, that HTML tags are normal tags and are not displayed on the screen when the function is returning caret position)
If I click right between H and TML, the aforementioned function will find caret position without any problems. But I am getting the contents of DIV box in HTML format (including all tags), and if I want to insert something at that caret's position, I will be off by a few or many characters.
I went through many posts, but all I could find is either <TEXTAREA> caret postions, or functions similar to what I have posted. So far I still cannot find a solution to get a caret position in a text that has HTML formatting.
Can anyone help, please?
PS. Here's JQuery/Javascript code that I wrote for the link button:
$('#pageEditor').on('click', '.linkURL', function()
{
var cursorPosition;
cursorPosition = getCaretPosition();
var contentID = $(this).parent().parent().attr('id');
var userSelected = getSelectionHtml();
var checkLink = userSelected.search('</a>');
var anchorTag = 0;
if(checkLink == -1)
{
var currentContents = $('#'+contentID+' .peCont').html();
var indexOfSelection = currentContents.indexOf(userSelected);
var getPossibleAnchor = currentContents.slice(indexOfSelection, indexOfSelection+userSelected.length+6);
anchorTag = getPossibleAnchor.search('</a>');
}
if(checkLink > 0 || anchorTag > 0)
{
//alert(checkLink);
document.execCommand('unlink', false, false);
}
else
{
$('#'+contentID+' .peCont').append('<div id="linkEntry"><label for="urlLink">Please enter URL for the link:<label><input type="text" id="urlLink" /></div>');
$('#linkEntry').dialog({
buttons: {
"Ok": function()
{
var attribute = $('#urlLink').val();
var newContentWithLink = '';
if(attribute != '')
{
if(userSelected != '')
{
var currentContent = $('#'+contentID+' .peCont').html();
var replacement = ''+userSelected+'';
newContentWithLink = currentContent.replace(userSelected, replacement);
}
else
{
var currentTextContent = $('#'+contentID+' .peCont').html();
var userLink = ''+attribute+'';
if(cursorPosition > 0)
{
var contentBegin = currentTextContent.slice(0,cursorPosition);
var contentEnd = currentTextContent.slice(cursorPosition,currentTextContent.length);
newContentWithLink = contentBegin+userLink+contentEnd;
}
else
{
newContentWithLink = attribute+currentTextContent;
}
}
$('#'+contentID+' .peCont').empty();
$('#'+contentID+' .peCont').html(newContentWithLink);
}
$(this).dialog("close");
} },
closeOnEscape:true,
modal:true,
resizable:false,
show: { effect: 'drop', direction: "up" },
hide: { effect: 'drop', direction: "down" },
width:460,
closeText:'hide',
close: function()
{
$(this).remove();
}
});
$('#linkEntry').on('keypress', function(urlEnter)
{
if(urlEnter.which == 13)
{
var attribute = $('#urlLink').val();
var newContentWithLink = '';
if(userSelected != '')
{
var currentContent = $('#'+contentID+' .peCont').html();
var replacement = ''+userSelected+'';
newContentWithLink = currentContent.replace(userSelected, replacement);
}
else
{
var currentTextContent = $('#'+contentID+' .peCont').html();
var userLink = ''+attribute+'';
if(cursorPosition > 0)
{
var contentBegin = currentTextContent.slice(0,cursorPosition);
var contentEnd = currentTextContent.slice(cursorPosition,currentTextContent.length);
newContentWithLink = contentBegin+userLink+contentEnd;
}
else
{
newContentWithLink = attribute+currentTextContent;
}
}
$('#'+contentID+' .peCont').empty();
$('#'+contentID+' .peCont').html(newContentWithLink);
$(this).dialog("close");
}
});
}
});
I created a simple fiddle for you that does what you want.
This should work in recent versions of Firefox, Chrome and Safari.
It's your homework to add Opera and IE support if you need.

Categories

Resources