diff --git a/src/survey-element.ts b/src/survey-element.ts index 26fabafa7c..d0203c0460 100644 --- a/src/survey-element.ts +++ b/src/survey-element.ts @@ -165,12 +165,24 @@ export class SurveyElement extends SurveyElementCore implements ISurvey const { root } = settings.environment; if (!elementId || typeof root === "undefined") return false; const el = root.getElementById(elementId); + return SurveyElement.ScrollElementToViewCore(el, false, scrollIfVisible); + } + private static ScrollElementToViewCore(el: HTMLElement, checkLeft: boolean, scrollIfVisible?: boolean): boolean { if (!el || !el.scrollIntoView) return false; - const elemTop: number = scrollIfVisible ? -1 : el.getBoundingClientRect().top; - let needScroll = elemTop < 0; - if(!needScroll && !!window) { + const elTop: number = scrollIfVisible ? -1 : el.getBoundingClientRect().top; + let needScroll = elTop < 0; + let elLeft: number = -1; + if(!needScroll && checkLeft) { + elLeft = el.getBoundingClientRect().left; + needScroll = elLeft < 0; + } + if(!!window && !needScroll) { const height = window.innerHeight; - needScroll = height > 0 && height < elemTop; + needScroll = height > 0 && height < elTop; + if(!needScroll && checkLeft) { + const width = window.innerWidth; + needScroll = width > 0 && width < elLeft; + } } if (needScroll) { el.scrollIntoView(); @@ -207,6 +219,7 @@ export class SurveyElement extends SurveyElementCore implements ISurvey const el = root.getElementById(elementId); // https://stackoverflow.com/questions/19669786/check-if-element-is-visible-in-dom if (el && !(el)["disabled"] && el.style.display !== "none" && el.offsetParent !== null) { + SurveyElement.ScrollElementToViewCore(el, true, false); el.focus(); return true; } diff --git a/testCafe/questions/matrixdropdown.js b/testCafe/questions/matrixdropdown.js index 3edb42a2b7..7abab1ac85 100644 --- a/testCafe/questions/matrixdropdown.js +++ b/testCafe/questions/matrixdropdown.js @@ -153,3 +153,77 @@ frameworks.forEach(framework => { await t.expect(requiredSpan.exists).ok(); }); }); + +const json3 = { + "elements": [ + { + "type": "matrixdropdown", + "name": "question1", + "columns": [ + { + "name": "Column 1" + }, + { + "name": "Column 2" + }, + { + "name": "Column 3" + }, + { + "name": "Column 4" + }, + { + "name": "Column 5" + }, + { + "name": "Column 6" + }, + { + "name": "Column 7" + }, + { + "name": "Column 8" + }, + { + "name": "Column 9" + }, + { + "name": "Column 10", + "isRequired": true + } + ], + "choices": [ + 1, + 2, + 3, + 4, + 5 + ], + "rows": [ + "Row 1", + "Row 2" + ] + } + ] +}; +frameworks.forEach(framework => { + fixture`${framework} ${title}`.page`${url}${framework}`.beforeEach( + async t => { + await initSurvey(framework, json3); + } + ); + test("Make a horizontal scroll to show a column with an error", async t => { + function filterIsInViewport(node) { + const rect = node.getBoundingClientRect(); + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); + } + const requiredSpan = Selector("span").withExactText("Response required."); + await t.click("input[value=Complete]") + .expect(Selector(requiredSpan).filter(filterIsInViewport).exists).ok(); + }); +});