Compare commits
5 Commits
a928c180d7
...
f77eb9aeb1
| Author | SHA1 | Date | |
|---|---|---|---|
| f77eb9aeb1 | |||
| 52fc370b17 | |||
| 0fd0ee8929 | |||
| ec7a1af1d0 | |||
| 2205bc6a27 |
@ -86,82 +86,91 @@
|
||||
.dual-form-wrapper .form-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
/* Skala di atas slider */
|
||||
/* Skala di atas slider */
|
||||
.range-scale {
|
||||
position: relative;
|
||||
height: 40px;
|
||||
margin-bottom: 8px;
|
||||
height: 45px;
|
||||
margin-top: 0px;
|
||||
border-top: 2px solid #495057;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
.range-track-colored {
|
||||
position: relative;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.range-track-colored .range-colored {
|
||||
width: 100%;
|
||||
-webkit-appearance: none;
|
||||
background: #ffffff; /* default putih, nanti diwarnai JS */
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
background: #ffffff;
|
||||
height: 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
/* hilangkan track default browser */
|
||||
.range-colored::-webkit-slider-runnable-track {
|
||||
background: transparent;
|
||||
height: 8px;
|
||||
height: 10px;
|
||||
}
|
||||
.range-colored::-moz-range-track {
|
||||
background: transparent;
|
||||
height: 8px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
/* thumb */
|
||||
.range-colored::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: #000;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
.range-colored::-moz-range-thumb {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: #000;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
.range-scale-item {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
transform: translateX(-50%);
|
||||
text-align: center;
|
||||
font-size: 10px;
|
||||
color: #555;
|
||||
font-size: 11px;
|
||||
color: #495057;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.range-scale-label {
|
||||
display: block;
|
||||
margin-bottom: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.range-scale-mark {
|
||||
display: block;
|
||||
width: 1px;
|
||||
height: 8px;
|
||||
margin-top:-10px;
|
||||
background-color: #555;
|
||||
background-color: #495057;
|
||||
}
|
||||
|
||||
/* Tick besar tiap 10 */
|
||||
/* Tick besar untuk angka 1 dan kelipatan 10 */
|
||||
.range-scale-item-major .range-scale-mark {
|
||||
height: 12px;
|
||||
background-color: #000;
|
||||
width: 2px;
|
||||
background-color: #212529;
|
||||
}
|
||||
|
||||
.range-scale-item-major .range-scale-label {
|
||||
font-weight: 600;
|
||||
color: #212529;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Tick khusus angka 1 biar lebih pendek (opsional) */
|
||||
/* Tick khusus angka 1 */
|
||||
.range-scale-item-one .range-scale-mark {
|
||||
height: 10px;
|
||||
height: 12px;
|
||||
background-color: #212529;
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
.range-scale-item-one .range-scale-label {
|
||||
color: #212529;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@ -211,7 +220,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($hal === $halPertama)
|
||||
<div class="card border-0 shadow-sm mb-4" id="head_soal">
|
||||
<div class="card-body">
|
||||
@ -312,6 +320,8 @@
|
||||
$rangeStep = 1;
|
||||
$rangeDefault = null;
|
||||
$rangeTicks = [];
|
||||
$rangeSubTickCount = 4;
|
||||
$rangeMajorStep = 10;
|
||||
if ($useDualForm && $currentAnswer) {
|
||||
if (preg_match('/([0-9]+)\\s*\\(Tahun\\)/i', $currentAnswer, $matchYear)) {
|
||||
$dualYearOld = $matchYear[1];
|
||||
@ -344,18 +354,74 @@
|
||||
}
|
||||
$rangeSpan = max($rangeMax - $rangeMin, 1);
|
||||
|
||||
$startTick = (int) ceil($rangeMin);
|
||||
$endTick = (int) floor($rangeMax);
|
||||
|
||||
for ($v = $startTick; $v <= $endTick; $v++) {
|
||||
$position = (($v - $rangeMin) / $rangeSpan) * 100;
|
||||
|
||||
$rangeTicks[] = [
|
||||
'value' => $v, // nilai asli
|
||||
'label' => ($v === 1 || $v % 10 === 0) ? $v : null, // label hanya 1 & kelipatan 10
|
||||
'position' => max(0, min(100, $position)),
|
||||
];
|
||||
$majorAnchors = [$rangeMin, $rangeMax];
|
||||
if ($rangeMin <= 1 && $rangeMax >= 1) {
|
||||
$majorAnchors[] = 1;
|
||||
}
|
||||
$firstMajor = max($rangeMin, ($rangeMin <= 1 ? 10 : ceil($rangeMin / $rangeMajorStep) * $rangeMajorStep));
|
||||
for ($v = $firstMajor; $v <= $rangeMax; $v += $rangeMajorStep) {
|
||||
$majorAnchors[] = $v;
|
||||
}
|
||||
|
||||
sort($majorAnchors);
|
||||
$uniqueAnchors = [];
|
||||
foreach ($majorAnchors as $anchor) {
|
||||
if (empty($uniqueAnchors) || abs(end($uniqueAnchors) - $anchor) > 0.0001) {
|
||||
$uniqueAnchors[] = $anchor;
|
||||
}
|
||||
}
|
||||
$majorAnchors = array_values(array_filter($uniqueAnchors, function ($value) use ($rangeMin, $rangeMax) {
|
||||
return $value >= $rangeMin && $value <= $rangeMax;
|
||||
}));
|
||||
|
||||
$ticks = [];
|
||||
$addTick = function ($value, $isMajor = false) use (&$ticks, $rangeMin, $rangeSpan, $rangeMajorStep) {
|
||||
$position = $rangeSpan > 0 ? (($value - $rangeMin) / $rangeSpan) * 100 : 0;
|
||||
$isOne = abs($value - 1) < 0.0001;
|
||||
$isMultiple = $rangeMajorStep > 0 ? abs(fmod($value, $rangeMajorStep)) < 0.0001 : false;
|
||||
$ticks[] = [
|
||||
'value' => $value,
|
||||
'label' => ($isOne || $isMultiple) ? (int) round($value) : null,
|
||||
'position' => max(0, min(100, $position)),
|
||||
'is_major' => $isMajor,
|
||||
'is_one' => $isOne,
|
||||
];
|
||||
};
|
||||
|
||||
$countAnchors = count($majorAnchors);
|
||||
if ($countAnchors === 0) {
|
||||
$addTick($rangeMin, true);
|
||||
} else {
|
||||
for ($i = 0; $i < $countAnchors; $i++) {
|
||||
$currentAnchor = $majorAnchors[$i];
|
||||
$addTick($currentAnchor, true);
|
||||
|
||||
if ($i === $countAnchors - 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nextAnchor = $majorAnchors[$i + 1];
|
||||
$segmentLength = $nextAnchor - $currentAnchor;
|
||||
if ($segmentLength <= 0 || $rangeSubTickCount <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($sub = 1; $sub <= $rangeSubTickCount; $sub++) {
|
||||
$fraction = $sub / ($rangeSubTickCount + 1);
|
||||
$value = $currentAnchor + ($segmentLength * $fraction);
|
||||
$addTick($value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
usort($ticks, function ($a, $b) {
|
||||
if ($a['value'] == $b['value']) {
|
||||
return 0;
|
||||
}
|
||||
return ($a['value'] < $b['value']) ? -1 : 1;
|
||||
});
|
||||
|
||||
$rangeTicks = $ticks;
|
||||
}
|
||||
}
|
||||
$rangeMinDisplay = ($rangeMin !== null && floor($rangeMin) == $rangeMin) ? (int) $rangeMin : $rangeMin;
|
||||
@ -410,48 +476,26 @@
|
||||
value="{{ $currentAnswer }}"
|
||||
data-dual-hidden="{{ $detail->id }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" @endif
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif>
|
||||
</div>
|
||||
@elseif ($type === 'textarea')
|
||||
<textarea class="form-control @error('jawaban.' . $detail->id) is-invalid @enderror"
|
||||
name="jawaban[{{ $detail->id }}]" rows="4"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" @endif
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif
|
||||
placeholder="Tulis jawaban Anda di sini">{{ $currentAnswer }}</textarea>
|
||||
@elseif ($type === 'text')
|
||||
<input type="text" class="form-control @error('jawaban.' . $detail->id) is-invalid @enderror"
|
||||
name="jawaban[{{ $detail->id }}]" value="{{ $currentAnswer }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" @endif
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif
|
||||
placeholder="Masukkan jawaban Anda">
|
||||
@elseif ($type === 'option_with_range')
|
||||
@if ($rangeMin !== null && $rangeMax !== null)
|
||||
<div class="range-slider-wrapper" data-range-wrapper="{{ $detail->id }}">
|
||||
<div class="range-scale" aria-hidden="true">
|
||||
@foreach ($rangeTicks as $tick)
|
||||
@php
|
||||
$value = (int) $tick['value'];
|
||||
$label = $tick['label']; // bisa null
|
||||
$isMajor = ($value === 1) || ($value % 10 === 0);
|
||||
$isOneTick = ($value === 1);
|
||||
@endphp
|
||||
<div class="range-scale-item
|
||||
{{ $isMajor ? 'range-scale-item-major' : '' }}
|
||||
{{ $isOneTick ? 'range-scale-item-one' : '' }}"
|
||||
style="left: {{ $tick['position'] }}%;">
|
||||
<span class="range-scale-mark"></span>
|
||||
|
||||
@if(!is_null($label))
|
||||
<span class="range-scale-label">{{ $label }}</span>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
|
||||
{{-- Track warna + slider --}}
|
||||
<div class="range-track-colored">
|
||||
<input type="range"
|
||||
@ -465,9 +509,29 @@
|
||||
data-range-min-value="{{ $rangeMin }}"
|
||||
data-range-max-value="{{ $rangeMax }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif>
|
||||
</div>
|
||||
<div class="range-scale" aria-hidden="true">
|
||||
@foreach ($rangeTicks as $tick)
|
||||
@php
|
||||
$label = $tick['label'] ?? null;
|
||||
$isMajor = !empty($tick['is_major']);
|
||||
$isOneTick = !empty($tick['is_one']);
|
||||
@endphp
|
||||
|
||||
<div class="range-scale-item
|
||||
{{ $isMajor ? 'range-scale-item-major' : '' }}
|
||||
{{ $isOneTick ? 'range-scale-item-one' : '' }}"
|
||||
style="left: {{ $tick['position'] }}%;">
|
||||
<span class="range-scale-mark"></span>
|
||||
|
||||
@if(!is_null($label))
|
||||
<span class="range-scale-label">{{ $label }}</span>
|
||||
@endif
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
<div class="text-center mt-2 fw-semibold">
|
||||
Nilai saat ini:
|
||||
<span data-range-output="{{ $detail->id }}">{{ $rangeDefaultDisplay ?? $rangeMinDisplay }}</span>
|
||||
@ -490,7 +554,7 @@
|
||||
<input type="text" class="form-control @error('jawaban.' . $detail->id) is-invalid @enderror"
|
||||
name="jawaban[{{ $detail->id }}]" value="{{ $currentAnswer }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" @endif
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif
|
||||
placeholder="Masukkan jawaban Anda">
|
||||
@endif
|
||||
@ -526,7 +590,7 @@
|
||||
data-original-value="{{ $optionLabel }}"
|
||||
data-lainnya-radio="{{ $isLainnya ? $detail->id : '' }}"
|
||||
data-field-hal="{{ $detailHal }}"
|
||||
@if ($isConsentQuestion) data-consent-input="1" @endif
|
||||
@if ($isConsentQuestion) data-consent-input="1" required @endif
|
||||
@if($formLocked) disabled @endif
|
||||
{{ $shouldCheck || $autoSelect ? 'checked' : '' }}>
|
||||
<label class="form-check-label" for="{{ $optionId }}">
|
||||
@ -667,7 +731,7 @@
|
||||
const summaryHal = document.getElementById('summary-hal');
|
||||
const totalHal = halList.length || 1;
|
||||
const nonConsentFields = document.querySelectorAll('[data-field-hal]:not([data-consent-input="1"])');
|
||||
const consentFields = document.querySelectorAll('[data-consent-input="1"]');
|
||||
const consentFields = document.querySelectorAll('[data-consent-input="1"][name]');
|
||||
const headSoalCard = document.getElementById('head_soal');
|
||||
const consentNegativeKeywords = ['tidak', 'tidak setuju'];
|
||||
let immediateSubmitActive = false;
|
||||
@ -791,6 +855,7 @@
|
||||
}
|
||||
updateQuestionVisibility();
|
||||
updateNavigationUI();
|
||||
scrollPageToTop();
|
||||
}
|
||||
|
||||
function validateHal(halValue) {
|
||||
@ -829,11 +894,13 @@
|
||||
const isFirst = currentIndex <= 0;
|
||||
const isLast = currentIndex === halList.length - 1;
|
||||
|
||||
const consentBlocked = hasIncompleteConsentForHal(currentHal);
|
||||
|
||||
if (prevButton) {
|
||||
prevButton.disabled = immediateSubmitActive ? true : isFirst;
|
||||
}
|
||||
if (nextButton) {
|
||||
if (immediateSubmitActive) {
|
||||
if (immediateSubmitActive || consentBlocked) {
|
||||
nextButton.style.display = 'none';
|
||||
} else {
|
||||
nextButton.style.display = '';
|
||||
@ -842,10 +909,12 @@
|
||||
}
|
||||
|
||||
navHalButtons.forEach(function (button) {
|
||||
const isActive = parseInt(button.dataset.navHal, 10) === currentHal;
|
||||
const targetHal = parseInt(button.dataset.navHal, 10);
|
||||
const isActive = targetHal === currentHal;
|
||||
const movingForward = targetHal > currentHal;
|
||||
button.classList.toggle('btn-primary', isActive);
|
||||
button.classList.toggle('btn-outline-primary', !isActive);
|
||||
button.disabled = immediateSubmitActive;
|
||||
button.disabled = immediateSubmitActive || (consentBlocked && movingForward);
|
||||
});
|
||||
|
||||
const progress = totalHal > 0 ? Math.round(((currentIndex + 1) / totalHal) * 100) : 100;
|
||||
@ -984,57 +1053,57 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setupRangeInputs() {
|
||||
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
||||
function setupRangeInputs() {
|
||||
const rangeInputs = form.querySelectorAll('[data-range-input]');
|
||||
|
||||
rangeInputs.forEach(function (input) {
|
||||
const detailId = input.getAttribute('data-range-input');
|
||||
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
||||
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
||||
rangeInputs.forEach(function (input) {
|
||||
const detailId = input.getAttribute('data-range-input');
|
||||
const output = detailId ? form.querySelector('[data-range-output="' + detailId + '"]') : null;
|
||||
const manualInput = detailId ? form.querySelector('[data-range-manual="' + detailId + '"]') : null;
|
||||
|
||||
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
||||
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
||||
const stepValue = parseFloat(input.step || '1') || 1;
|
||||
const minValue = parseFloat(input.dataset.rangeMinValue || input.min || '0');
|
||||
const maxValue = parseFloat(input.dataset.rangeMaxValue || input.max || '100');
|
||||
const stepValue = parseFloat(input.step || '1') || 1;
|
||||
|
||||
function clampAndSnap(rawVal) {
|
||||
let v = parseFloat(rawVal);
|
||||
if (isNaN(v)) v = minValue;
|
||||
if (v < minValue) v = minValue;
|
||||
if (v > maxValue) v = maxValue;
|
||||
return snapToStep(v, minValue, stepValue);
|
||||
}
|
||||
function clampAndSnap(rawVal) {
|
||||
let v = parseFloat(rawVal);
|
||||
if (isNaN(v)) v = minValue;
|
||||
if (v < minValue) v = minValue;
|
||||
if (v > maxValue) v = maxValue;
|
||||
return snapToStep(v, minValue, stepValue);
|
||||
}
|
||||
|
||||
function updateBoth(fromManual) {
|
||||
const current = fromManual && manualInput ? manualInput.value : input.value;
|
||||
const value = clampAndSnap(current);
|
||||
function updateBoth(fromManual) {
|
||||
const current = fromManual && manualInput ? manualInput.value : input.value;
|
||||
const value = clampAndSnap(current);
|
||||
|
||||
input.value = value;
|
||||
input.value = value;
|
||||
|
||||
if (output) {
|
||||
output.textContent = formatRangeDisplay(value);
|
||||
}
|
||||
if (manualInput && !fromManual) {
|
||||
manualInput.value = value;
|
||||
}
|
||||
if (output) {
|
||||
output.textContent = formatRangeDisplay(value);
|
||||
}
|
||||
if (manualInput && !fromManual) {
|
||||
manualInput.value = value;
|
||||
}
|
||||
|
||||
updateRangeFill(input, minValue, maxValue);
|
||||
}
|
||||
updateRangeFill(input, minValue, maxValue);
|
||||
}
|
||||
|
||||
input.addEventListener('input', function () {
|
||||
updateBoth(false);
|
||||
input.addEventListener('input', function () {
|
||||
updateBoth(false);
|
||||
});
|
||||
|
||||
if (manualInput) {
|
||||
manualInput.addEventListener('input', function () {
|
||||
updateBoth(true);
|
||||
});
|
||||
}
|
||||
|
||||
// initial
|
||||
updateBoth(false);
|
||||
});
|
||||
|
||||
if (manualInput) {
|
||||
manualInput.addEventListener('input', function () {
|
||||
updateBoth(true);
|
||||
});
|
||||
}
|
||||
|
||||
// initial
|
||||
updateBoth(false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function formatRangeDisplay(value) {
|
||||
@ -1099,6 +1168,58 @@ function setupRangeInputs() {
|
||||
return value === '';
|
||||
}
|
||||
|
||||
function hasIncompleteConsentForHal(halValue) {
|
||||
if (!halValue || formLocked) {
|
||||
return false;
|
||||
}
|
||||
const fields = form.querySelectorAll('[data-consent-input="1"][name][data-field-hal="' + halValue + '"]');
|
||||
if (!fields.length) {
|
||||
return false;
|
||||
}
|
||||
const groupMap = {};
|
||||
let needsValue = false;
|
||||
|
||||
fields.forEach(function (field) {
|
||||
if (!field || field.disabled) {
|
||||
return;
|
||||
}
|
||||
const type = (field.type || '').toLowerCase();
|
||||
const tagName = (field.tagName || '').toLowerCase();
|
||||
|
||||
if (type === 'radio' || type === 'checkbox') {
|
||||
const groupName = field.name || field.id || ('consent-' + halValue);
|
||||
if (!groupMap[groupName]) {
|
||||
groupMap[groupName] = [];
|
||||
}
|
||||
groupMap[groupName].push(field);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tagName === 'select') {
|
||||
if (field.value === null || field.value === '') {
|
||||
needsValue = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const value = (field.value || '').toString().trim();
|
||||
if (!value) {
|
||||
needsValue = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (needsValue) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Object.keys(groupMap).some(function (groupName) {
|
||||
const fieldsInGroup = groupMap[groupName] || [];
|
||||
return !fieldsInGroup.some(function (input) {
|
||||
return input.checked;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setupDualFormInputs() {
|
||||
document.querySelectorAll('[data-dual-wrapper]').forEach(function (wrapper) {
|
||||
const detailId = wrapper.getAttribute('data-dual-wrapper');
|
||||
@ -1150,12 +1271,18 @@ function setupRangeInputs() {
|
||||
return;
|
||||
}
|
||||
consentFields.forEach(function (field) {
|
||||
field.addEventListener('change', function (event) {
|
||||
if (field.type === 'radio' && !field.checked) {
|
||||
const handleChange = function () {
|
||||
const type = (field.type || '').toLowerCase();
|
||||
if ((type === 'radio' || type === 'checkbox') && !field.checked) {
|
||||
return;
|
||||
}
|
||||
evaluateConsentValue(event.target.value);
|
||||
});
|
||||
evaluateConsentValue(field.value);
|
||||
};
|
||||
|
||||
field.addEventListener('change', handleChange);
|
||||
if (shouldUseInputEvent(field)) {
|
||||
field.addEventListener('input', handleChange);
|
||||
}
|
||||
|
||||
if (
|
||||
(field.type === 'radio' && field.checked) ||
|
||||
@ -1167,6 +1294,15 @@ function setupRangeInputs() {
|
||||
});
|
||||
}
|
||||
|
||||
function shouldUseInputEvent(field) {
|
||||
const tagName = (field.tagName || '').toLowerCase();
|
||||
const type = (field.type || '').toLowerCase();
|
||||
if (tagName === 'textarea') {
|
||||
return true;
|
||||
}
|
||||
return type === 'text' || type === 'number' || type === 'range';
|
||||
}
|
||||
|
||||
function evaluateConsentValue(value) {
|
||||
const normalized = (value || '').toString().trim().toLowerCase();
|
||||
const shouldStop = consentNegativeKeywords.some(function (keyword) {
|
||||
@ -1191,6 +1327,17 @@ function setupRangeInputs() {
|
||||
});
|
||||
updateNavigationUI();
|
||||
}
|
||||
|
||||
function scrollPageToTop() {
|
||||
if (typeof window === 'undefined' || typeof window.scrollTo !== 'function') {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
} catch (error) {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user