Fixing GF scroll logic
August 11, 2025 · AI Conversations
$(this).siblings('input').trigger('click'); // update GF conditional logic first
var scrollToEl = '';
var $sourceBlockEl = $(this).closest('.gfield');
var $nextBlockEl = $sourceBlockEl.next();
var headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : $('#et-main-area').offset().top;
// Only treat as "correct" if not flagged incorrect AND gating allows
var isCorrectClick = ((($(this).attr('onclick') || '').indexOf('incorrect') === -1) && (isOverride || (typeof availableProducts !== 'undefined' && availableProducts.length > 0)));
if (isCorrectClick) {
// 1) Try going UP to nearest previous incorrect/error
var $incorrectFields = $('.gfield:visible').filter(function(){
var $f = $(this);
return $f.hasClass('gfield_error') ||
$f.hasClass('gquiz-field-incorrect') ||
$f.find('.gquiz-incorrect-choice:visible').length > 0 ||
$f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
var srcTop = $sourceBlockEl.offset().top, $prevIncorrect = $();
$incorrectFields.each(function(){
var $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f; // last one above = nearest previous
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if (scrollToEl.outerHeight() > $(window).outerHeight()) {
var $choice = scrollToEl.find('.gquiz-incorrect-choice:visible, .choice_incorrect:visible').first();
if ($choice.length) scrollToEl = $choice;
headerHeight = $(window).outerHeight() / 4;
}
}
}
// 2) If no incorrect above, fall back to normal DOWN auto-scroll
if (!scrollToEl) {
// next visible unanswered block (fix typo: .length)
if ($nextBlockEl.is(':visible')
&& $nextBlockEl.find('input:checked').length === 0
&& $nextBlockEl.find('.choice_selected').length === 0) {
scrollToEl = $nextBlockEl;
} else {
// first visible unanswered anywhere (required OR optional)
var found = false;
$('.gfield:visible').each(function(){
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip HTML/section
var answered = false;
if ($f.find('.ginput_container_choice').length) {
answered = $f.find('input:radio:checked, input:checkbox:checked').length > 0;
} else {
answered =
$f.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea')
.filter(function(){ return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('select').filter(function(){ var v=$(this).val(); return v !== '' && v !== null; }).length > 0
|| $f.find('input[type="date"], input[type="time"]').filter(function(){ return $.trim($(this).val()) !== ''; }).length > 0;
}
if (!answered) { scrollToEl = $f; found = true; return false; }
});
if (!found) {
// nothing left unanswered → center submit
scrollToEl = $('.gform_footer');
headerHeight = headerHeight + ($(window).outerHeight() / 4);
}
}
}
}
// No scroll on incorrect clicks (per your requirement)
if (scrollToEl) {
var elOffset = $(scrollToEl).is(':visible')
? $(scrollToEl).offset().top
: $sourceBlockEl.offset().top + $sourceBlockEl.outerHeight();
$('html, body').animate({ scrollTop: elOffset – headerHeight }, 1000);
}
});
above is skipped non required question I want to fix this so that it also considere non required also persist current functioanlity
1) don’t bind to “not(:last) label” (that skips the last choice);
2) treat selects with placeholder (e.g. `gf_placeholder`, disabled) as **unanswered** so optional questions aren’t skipped.
Drop-in replacement:
“`js
// Delegate so dynamically-shown fields also work
$(document).on('click', '.gfield_choice label', function () {
$(this).siblings('input').trigger('click'); // update GF conditional logic first
const $sourceBlockEl = $(this).closest('.gfield');
let scrollToEl = '';
let headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : $('#et-main-area').offset().top;
// helper: is a field answered?
function isFieldAnswered($f) {
// skip non-question blocks
if ($f.find('.ginput_container').length === 0) return true;
// choices
if ($f.find('.ginput_container_choice').length) {
return $f.find('input:radio:checked, input:checkbox:checked').length > 0;
}
// text-like inputs
const hasFilledText = $f
.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea, input[type="date"], input[type="time"]')
.filter(function () { return $.trim($(this).val() || '') !== ''; })
.length > 0;
// selects (placeholder should NOT count as answered)
const hasValidSelect = $f.find('select').filter(function () {
const $sel = $(this);
const $opt = $sel.find('option:selected');
const val = $sel.val();
// treat as unanswered if: empty/null, selected option is disabled, or has gf_placeholder
if (val === '' || val === null) return false;
if ($opt.is(':disabled') || $opt.hasClass('gf_placeholder')) return false;
return true;
}).length > 0;
// file inputs
const hasFile = $f.find('input[type="file"]').filter(function () { return this.files && this.files.length; }).length > 0;
return hasFilledText || hasValidSelect || hasFile;
}
// Only treat as "correct" if not flagged incorrect AND gating allows
const isCorrectClick = (
((($(this).attr('onclick') || '').indexOf('incorrect') === -1)) &&
(typeof isOverride !== 'undefined' && isOverride || (typeof availableProducts !== 'undefined' && availableProducts.length > 0))
);
if (isCorrectClick) {
// 1) Go UP to nearest previous incorrect/error (if any)
const $incorrectFields = $('.gfield:visible').filter(function () {
const $f = $(this);
return $f.hasClass('gfield_error')
|| $f.hasClass('gquiz-field-incorrect')
|| $f.find('.gquiz-incorrect-choice:visible').length > 0
|| $f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
const srcTop = $sourceBlockEl.offset().top;
let $prevIncorrect = $();
$incorrectFields.each(function () {
const $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f;
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if ($prevIncorrect.outerHeight() > $(window).outerHeight()) {
const $choice = $prevIncorrect.find('.gquiz-incorrect-choice:visible,
// first visible unanswered anywhere (required OR optional)
var found = false;
$('.gfield:visible').each(function(){
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip HTML/section
var answered = false;
...
if (!answered) { scrollToEl = $f; found = true; return false; }
});
The **problem** is in the logic for `$nextBlockEl` before that —
you only scroll down if **`$nextBlockEl` is visible AND unanswered**.
If it’s optional and already skipped by Gravity Forms’ required check, it gets bypassed.
—
### Minimal change to include non-required questions
Replace:
if ($nextBlockEl.is(':visible')
&& $nextBlockEl.find('input:checked').length === 0
&& $nextBlockEl.find('.choice_selected').length === 0) {
scrollToEl = $nextBlockEl;
} else {
with:
if ($nextBlockEl.is(':visible')) {
// always go to next visible block, regardless of required/answered
scrollToEl = $nextBlockEl;
} else {
—
### Why this works
– The first branch will now always scroll to the next visible `.gfield` — even if it’s optional or already answered — keeping the natural order.
– If `$nextBlockEl` is hidden (conditional logic), it falls back to the full “find first visible unanswered” loop.
—
Do you want me to **rewrite the whole script** with this fix cleanly applied so that both the “go up to incorrect” and “scroll down” behaviours remain intact but no non-required question is skipped? That would avoid touching multiple places later.
given script skipped non required question and scroll to next required question event if in betwen there is non require question
SO I just want it simply should scroll to next question wheter it is reqired or non required
and also keep existing functionality
Use delegated binding (works with GF’s dynamic DOM) and replace your handler with this:
$(document).on('click', '.gfield_choice label', function () {
// Let GF update conditional logic first
$(this).siblings('input').trigger('click');
var $sourceBlockEl = $(this).closest('.gfield');
var scrollToEl = '';
var headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : $('#et-main-area').offset().top;
// treat as "correct" only if not flagged incorrect AND gating allows
var isCorrectClick =
((($(this).attr('onclick') || '').indexOf('incorrect') === -1)) &&
( (typeof isOverride !== 'undefined' && isOverride) ||
(typeof availableProducts !== 'undefined' && availableProducts.length > 0) );
if (isCorrectClick) {
// 1) Go UP to nearest previous incorrect/error
var $incorrectFields = $('.gfield:visible').filter(function () {
var $f = $(this);
return $f.hasClass('gfield_error') ||
$f.hasClass('gquiz-field-incorrect') ||
$f.find('.gquiz-incorrect-choice:visible').length > 0 ||
$f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
var srcTop = $sourceBlockEl.offset().top, $prevIncorrect = $();
$incorrectFields.each(function () {
var $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f;
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if ($prevIncorrect.outerHeight() > $(window).outerHeight()) {
var $choice = $prevIncorrect.find('.gquiz-incorrect-choice:visible, .choice_incorrect:visible').first();
if ($choice.length) scrollToEl = $choice;
headerHeight = $(window).outerHeight() / 4;
}
}
}
// 2) If no incorrect above, ALWAYS go to the next VISIBLE question
if (!scrollToEl) {
var $nextVisibleQuestion = $sourceBlockEl
.nextAll('.gfield:visible')
.filter(function () { return $(this).find('.ginput_container').length > 0; }) // skip sections/HTML blocks
.first();
if ($nextVisibleQuestion.length) {
scrollToEl = $nextVisibleQuestion;
} else {
// 3) Fallbacks unchanged: first visible unanswered anywhere, else center submit
var found = false;
$('.gfield:visible').each(function () {
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip non-question blocks
var answered = false;
if ($f.find('.ginput_container_choice').length) {
answered = $f.find('input:radio:checked, input:checkbox:checked').length > 0;
} else {
answered =
$f.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea')
.filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('select').filter(function () { var v = $(this).val(); return v !== '' && v !== null; }).length > 0
|| $f.find('input[type="date"], input[type="time"]').filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('input[type="file"]').filter(function () { return this.files && this.files.length; }).length > 0;
}
if (!answered) { scrollToEl = $f; found = true; return false; }
});
if (!found) {
scrollToEl = $('.gform_footer');
headerHeight += ($(window).outerHeight() / 4);
}
}
}
}
// No scroll on incorrect clicks
if (scrollToEl) {
var elOffset = $(scrollToEl).is(':visible')
? $(scrollToEl).offset().top
: $sourceBlockEl.offset().top + $sourceBlockEl.outerHeight();
$('html, body').animate({ scrollTop: elOffset - headerHeight }, 1000);
}
});
What changed:
– The down-scroll step now picks `nextAll('.gfield:visible')` and **doesn’t care** if it’s required or optional—just the next visible question.
– Everything else (go up to previous incorrect; fallbacks to first unanswered / submit centering; no scroll on incorrect) stays intact.
Add To Cart
this click stoped working on other page
You’ve got:
href="javascript:void(0}"
That closing brace `}` makes the browser try to run invalid JS on click, so your upsell handler never fires.
Fix it:
<a href="javascript:void(0)" class="upsell-addtocart" data-prodid="191361" style="text-decoration:none!important">
<span class="upsell-cart" style="background:#acabab;padding:9px;color:white;border-radius:5px;text-transform:unset;font-weight:600;font-size:11px">
Add To Cart
</span>
</a>
Even better (more robust):
<a href="#" class="upsell-addtocart" data-prodid="191361" role="button">Add To Cart</a>
$(document).on('click', '.upsell-addtocart', function (e) {
e.preventDefault(); // don’t navigate
const id = $(this).data('prodid');
// your add-to-cart logic here…
});
Optional safety so your GF script can’t affect other pages:
if ($('.gform_wrapper').length) {
$(document).on('click', '.gfield_choice label', function(){ /* … */ });
}
After the fix, refresh and check the console—if you still see errors, paste them here and I’ll zero in.
(function ($) {
function onUpsellClick(e) {
e.preventDefault();
e.stopPropagation(); // avoid theme/global handlers grabbing it first
const $a = $(this);
const id = $a.data('prodid');
// TODO: your add-to-cart logic here…
// $.post('/cart/add', { product_id: id, qty: 1 }) ...
}
// bind for current + future elements
$('.upsell-addtocart').off('click.upsell').on('click.upsell', onUpsellClick);
$(document).off('click.upsell', '.upsell-addtocart')
.on('click.upsell', '.upsell-addtocart', onUpsellClick);
// keyboard accessibility
$(document).on('keydown.upsell', '.upsell-addtocart', function (e) {
if (e.key === 'Enter' || e.key === ' ') onUpsellClick.call(this, e);
});
})(jQuery);
And tweak the HTML for a11y:
<a href="#" class="upsell-addtocart" data-prodid="191361" role="button" tabindex="0" style="text-decoration:none!important">
<span class="upsell-cart" style="background:#acabab;padding:9px;color:#fff;border-radius:5px;text-transform:unset;font-weight:600;font-size:11px">Add To Cart</span>
</a>
If it still doesn’t fire, quick checks:
– Open DevTools → Console: any JS errors?
– Inspect the element: is there a parent with `pointer-events:none`?
– Search code for a global `$('a[href^="#"]').on('click', …)` that uses `stopImmediatePropagation()`. If found, keep the handler above and consider switching to `href="javascript:void(0)"` or add a class the global script excludes.
// Let GF update conditional logic first
$(this).siblings('input').trigger('click');
var $sourceBlockEl = $(this).closest('.gfield');
var scrollToEl = '';
var headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : $('#et-main-area').offset().top;
// treat as "correct" only if not flagged incorrect AND gating allows
var isCorrectClick =
((($(this).attr('onclick') || '').indexOf('incorrect') === -1)) &&
( (typeof isOverride !== 'undefined' && isOverride) ||
(typeof availableProducts !== 'undefined' && availableProducts.length > 0) );
if (isCorrectClick) {
// 1) Go UP to nearest previous incorrect/error
var $incorrectFields = $('.gfield:visible').filter(function () {
var $f = $(this);
return $f.hasClass('gfield_error') ||
$f.hasClass('gquiz-field-incorrect') ||
$f.find('.gquiz-incorrect-choice:visible').length > 0 ||
$f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
var srcTop = $sourceBlockEl.offset().top, $prevIncorrect = $();
$incorrectFields.each(function () {
var $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f;
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if ($prevIncorrect.outerHeight() > $(window).outerHeight()) {
var $choice = $prevIncorrect.find('.gquiz-incorrect-choice:visible, .choice_incorrect:visible').first();
if ($choice.length) scrollToEl = $choice;
headerHeight = $(window).outerHeight() / 4;
}
}
}
// 2) If no incorrect above, ALWAYS go to the next VISIBLE question
if (!scrollToEl) {
var $nextVisibleQuestion = $sourceBlockEl
.nextAll('.gfield:visible')
.filter(function () { return $(this).find('.ginput_container').length > 0; }) // skip sections/HTML blocks
.first();
if ($nextVisibleQuestion.length) {
scrollToEl = $nextVisibleQuestion;
} else {
// 3) Fallbacks unchanged: first visible unanswered anywhere, else center submit
var found = false;
$('.gfield:visible').each(function () {
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip non-question blocks
var answered = false;
if ($f.find('.ginput_container_choice').length) {
answered = $f.find('input:radio:checked, input:checkbox:checked').length > 0;
} else {
answered =
$f.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea')
.filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('select').filter(function () { var v = $(this).val(); return v !== '' && v !== null; }).length > 0
|| $f.find('input[type="date"], input[type="time"]').filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('input[type="file"]').filter(function () { return this.files && this.files.length; }).length > 0;
}
if (!answered) { scrollToEl = $f; found = true; return false; }
});
if (!found) {
scrollToEl = $('.gform_footer');
headerHeight += ($(window).outerHeight() / 4);
}
}
}
}
// No scroll on incorrect clicks
if (scrollToEl) {
var elOffset = $(scrollToEl).is(':visible')
? $(scrollToEl).offset().top
: $sourceBlockEl.offset().top + $sourceBlockEl.outerHeight();
$('html, body').animate({ scrollTop: elOffset – headerHeight }, 1000);
}
});
after adding above script the problem start
Drop-in replacement (same logic, safer binding):
(function ($) {
// Only bind if a Gravity Form exists on the page
var $formWrap = $('.gform_wrapper');
if (!$formWrap.length) return;
// Bind on the form container (not document) + namespace
$formWrap.off('click.gformAutoScroll', '.gfield_choice label')
.on('click.gformAutoScroll', '.gfield_choice label', function () {
// Let GF update conditional logic first
$(this).siblings('input').trigger('click');
var $sourceBlockEl = $(this).closest('.gfield');
var scrollToEl = '';
var headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : $('#et-main-area').offset().top;
// treat as "correct" only if not flagged incorrect AND gating allows
var isCorrectClick =
((($(this).attr('onclick') || '').indexOf('incorrect') === -1)) &&
((typeof isOverride !== 'undefined' && isOverride) ||
(typeof availableProducts !== 'undefined' && availableProducts.length > 0));
if (isCorrectClick) {
// 1) Up to nearest previous incorrect/error
var $incorrectFields = $('.gfield:visible').filter(function () {
var $f = $(this);
return $f.hasClass('gfield_error') ||
$f.hasClass('gquiz-field-incorrect') ||
$f.find('.gquiz-incorrect-choice:visible').length > 0 ||
$f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
var srcTop = $sourceBlockEl.offset().top, $prevIncorrect = $();
$incorrectFields.each(function () {
var $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f;
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if ($prevIncorrect.outerHeight() > $(window).outerHeight()) {
var $choice = $prevIncorrect.find('.gquiz-incorrect-choice:visible, .choice_incorrect:visible').first();
if ($choice.length) scrollToEl = $choice;
headerHeight = $(window).outerHeight() / 4;
}
}
}
// 2) Else always go to the next visible question (required or not)
if (!scrollToEl) {
var $nextVisibleQuestion = $sourceBlockEl
.nextAll('.gfield:visible')
.filter(function () { return $(this).find('.ginput_container').length > 0; })
.first();
if ($nextVisibleQuestion.length) {
scrollToEl = $nextVisibleQuestion;
} else {
// 3) Fallbacks unchanged
var found = false;
$('.gfield:visible').each(function () {
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip non-question blocks
var answered = false;
if ($f.find('.ginput_container_choice').length) {
answered = $f.find('input:radio:checked, input:checkbox:checked').length > 0;
} else {
answered =
$f.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea')
.filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('select').filter(function () { var v = $(this).val(); return v !== '' && v !== null; }).length > 0
|| $f.find('input[type="date"], input[type="time"]').filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('input[type="file"]').filter(function () { return this.files && this.files.length; }).length > 0;
}
if (!answered) { scrollToEl = $f; found = true; return false; }
});
if (!found) {
scrollToEl = $('.gform_footer');
headerHeight += ($(window).outerHeight() / 4);
}
}
}
}
// No scroll on incorrect clicks
if (scrollToEl) {
var elOffset = $(scrollToEl).is(':visible')
? $(scrollToEl).offset().top
: $sourceBlockEl.offset().top + $sourceBlockEl.outerHeight();
$('html, body').animate({ scrollTop: elOffset - headerHeight }, 1000);
}
});
})(jQuery);
Also, keep your upsell button bulletproof (in case other global handlers exist):
$(document).on('click', '.upsell-addtocart', function (e) {
e.preventDefault();
e.stopPropagation();
// add-to-cart logic...
});
Scoping the GF listener to `.gform_wrapper` removes any chance it interferes with other pages/components.
Main fixes:
– **Null-safe headerHeight** (don’t read `.offset().top` if `#et-main-area` isn’t there).
– **Scope to the specific form** that actually has choice labels (so other pages aren’t touched).
– **Limit all lookups** to that form scope.
Drop-in replacement:
(function ($) {
// Find only forms that actually have choice labels
var $scope = $('.gform_wrapper').filter(function () {
return $(this).find('.gfield_choice label').length > 0;
}).first();
if (!$scope.length) return; // no quiz/choice form on this page
// bind inside the form scope + namespace
$scope.off('click.gformAutoScroll', '.gfield_choice label')
.on('click.gformAutoScroll', '.gfield_choice label', function () {
// Let GF update conditional logic first
$(this).siblings('input').trigger('click');
var $sourceBlockEl = $(this).closest('.gfield');
var scrollToEl = '';
// NULL-SAFE header height
var $mainArea = $('#et-main-area');
var headerHeight = $('#et_mobile_nav_menu').is(':visible') ? 0 : ($mainArea.length ? $mainArea.offset().top : 0);
// Safe gating (vars may not exist on all pages)
var isCorrectClick =
((($(this).attr('onclick') || '').indexOf('incorrect') === -1)) &&
((typeof isOverride !== 'undefined' && isOverride) ||
(typeof availableProducts !== 'undefined' && availableProducts.length > 0));
if (isCorrectClick) {
// 1) Up to nearest previous incorrect/error (within this form only)
var $incorrectFields = $scope.find('.gfield:visible').filter(function () {
var $f = $(this);
return $f.hasClass('gfield_error') ||
$f.hasClass('gquiz-field-incorrect') ||
$f.find('.gquiz-incorrect-choice:visible').length > 0 ||
$f.find('.choice_incorrect:visible').length > 0;
});
if ($incorrectFields.length) {
var srcTop = $sourceBlockEl.offset().top, $prevIncorrect = $();
$incorrectFields.each(function () {
var $f = $(this);
if ($f.offset().top < srcTop) $prevIncorrect = $f;
});
if ($prevIncorrect.length) {
scrollToEl = $prevIncorrect;
// mobile centering tweak for tall fields
if ($prevIncorrect.outerHeight() > $(window).outerHeight()) {
var $choice = $prevIncorrect.find('.gquiz-incorrect-choice:visible, .choice_incorrect:visible').first();
if ($choice.length) scrollToEl = $choice;
headerHeight = $(window).outerHeight() / 4;
}
}
}
// 2) Else always go to the next visible question (required or not) within this form
if (!scrollToEl) {
var $nextVisibleQuestion = $sourceBlockEl
.nextAll('.gfield:visible')
.filter(function () { return $(this).find('.ginput_container').length > 0; })
.first();
if ($nextVisibleQuestion.length) {
scrollToEl = $nextVisibleQuestion;
} else {
// 3) Fallbacks unchanged but scoped
var found = false;
$scope.find('.gfield:visible').each(function () {
var $f = $(this);
if ($f.find('.ginput_container').length === 0) return; // skip non-question blocks
var answered = false;
if ($f.find('.ginput_container_choice').length) {
answered = $f.find('input:radio:checked, input:checkbox:checked').length > 0;
} else {
answered =
$f.find('input[type="text"], input[type="email"], input[type="number"], input[type="tel"], input[type="url"], textarea')
.filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('select').filter(function () { var v = $(this).val(); return v !== '' && v !== null; }).length > 0
|| $f.find('input[type="date"], input[type="time"]').filter(function () { return $.trim($(this).val()) !== ''; }).length > 0
|| $f.find('input[type="file"]').filter(function () { return this.files && this.files.length; }).length > 0;
}
if (!answered) { scrollToEl = $f; found = true; return false; }
});
if (!found) {
scrollToEl = $scope.find('.gform_footer');
headerHeight += ($(window).outerHeight() / 4);
}
}
}
}
// No scroll on incorrect clicks
if (scrollToEl && $(scrollToEl).length) {
var $target = $(scrollToEl);
var elOffset = $target.is(':visible')
? $target.offset().top
: $sourceBlockEl.offset().top + $sourceBlockEl.outerHeight();
$('html, body').animate({ scrollTop: elOffset - headerHeight }, 1000);
}
});
})(jQuery);
And keep your upsell click bullet-proof:
$(document).off('click.upsell', '.upsell-addtocart')
.on('click.upsell', '.upsell-addtocart', function (e) {
e.preventDefault();
e.stopPropagation();
const id = $(this).data('prodid');
// add-to-cart logic...
});
This prevents the GF script from running (or erroring) on pages without that quiz form and stops it from breaking your upsell button.