Add 'scrollIntoView' to baseUIElement, autoscroll questions into view when appropriate
This commit is contained in:
parent
aec5ffba79
commit
9e97eba519
4 changed files with 78 additions and 13 deletions
|
@ -3,6 +3,8 @@
|
|||
*
|
||||
* Assumes a read-only configuration, so it has no 'ListenTo'
|
||||
*/
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
export default abstract class BaseUIElement {
|
||||
protected _constructedHtmlElement: HTMLElement
|
||||
protected isDestroyed = false
|
||||
|
@ -41,6 +43,34 @@ export default abstract class BaseUIElement {
|
|||
this._constructedHtmlElement?.scrollTo(0, 0)
|
||||
}
|
||||
|
||||
public ScrollIntoView(options?: {
|
||||
onlyIfPartiallyHidden?: boolean
|
||||
}) {
|
||||
if(this._constructedHtmlElement === undefined){
|
||||
return
|
||||
}
|
||||
let alignToTop = true;
|
||||
if(options?.onlyIfPartiallyHidden){
|
||||
// Is the element completely in the view?
|
||||
const parentRect = Utils.findParentWithScrolling(this._constructedHtmlElement.parentElement).getBoundingClientRect();
|
||||
const elementRect = this._constructedHtmlElement.getBoundingClientRect();
|
||||
|
||||
// Check if the element is within the vertical bounds of the parent element
|
||||
const topIsVisible = elementRect.top >= parentRect.top
|
||||
const bottomIsVisible = elementRect.bottom <= parentRect.bottom
|
||||
const inView = topIsVisible && bottomIsVisible ;
|
||||
if(inView){
|
||||
return
|
||||
}
|
||||
if(topIsVisible){
|
||||
alignToTop = false
|
||||
}
|
||||
}
|
||||
this._constructedHtmlElement?.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "start"
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Adds all the relevant classes, space separated
|
||||
*/
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import {UIEventSource} from "../../Logic/UIEventSource"
|
||||
import TagRenderingQuestion from "./TagRenderingQuestion"
|
||||
import Translations from "../i18n/Translations"
|
||||
import Combine from "../Base/Combine"
|
||||
import TagRenderingAnswer from "./TagRenderingAnswer"
|
||||
import Svg from "../../Svg"
|
||||
import Toggle from "../Input/Toggle"
|
||||
import BaseUIElement from "../BaseUIElement"
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
||||
import { Unit } from "../../Models/Unit"
|
||||
import {Unit} from "../../Models/Unit"
|
||||
import Lazy from "../Base/Lazy"
|
||||
import { FixedUiElement } from "../Base/FixedUiElement"
|
||||
import { EditButton } from "./SaveButton"
|
||||
import {FixedUiElement} from "../Base/FixedUiElement"
|
||||
import {EditButton} from "./SaveButton"
|
||||
|
||||
export default class EditableTagRendering extends Toggle {
|
||||
constructor(
|
||||
|
@ -31,10 +30,9 @@ export default class EditableTagRendering extends Toggle {
|
|||
configuration.IsKnown(tags) &&
|
||||
(configuration?.condition?.matchesProperties(tags) ?? true)
|
||||
)
|
||||
|
||||
const editMode = options.editMode ?? new UIEventSource<boolean>(false)
|
||||
super(
|
||||
new Lazy(() => {
|
||||
const editMode = options.editMode ?? new UIEventSource<boolean>(false)
|
||||
let rendering = EditableTagRendering.CreateRendering(
|
||||
state,
|
||||
tags,
|
||||
|
@ -54,6 +52,13 @@ export default class EditableTagRendering extends Toggle {
|
|||
undefined,
|
||||
renderingIsShown
|
||||
)
|
||||
const self = this;
|
||||
editMode.addCallback(editing => {
|
||||
if(editing){
|
||||
console.log("Scrolling etr into view")
|
||||
self.ScrollIntoView()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private static CreateRendering(
|
||||
|
@ -69,12 +74,6 @@ export default class EditableTagRendering extends Toggle {
|
|||
|
||||
if (configuration.question !== undefined && state?.featureSwitchUserbadge?.data) {
|
||||
// We have a question and editing is enabled
|
||||
const answerWithEditButton = new Combine([
|
||||
answer,
|
||||
new EditButton(state.osmConnection, () => {
|
||||
editMode.setData(true)
|
||||
}),
|
||||
]).SetClass("flex justify-between w-full")
|
||||
|
||||
const question = new Lazy(
|
||||
() =>
|
||||
|
@ -92,7 +91,18 @@ export default class EditableTagRendering extends Toggle {
|
|||
})
|
||||
)
|
||||
|
||||
const answerWithEditButton = new Combine([
|
||||
answer,
|
||||
new EditButton(state.osmConnection, () => {
|
||||
editMode.setData(true)
|
||||
question.ScrollIntoView({
|
||||
onlyIfPartiallyHidden:true
|
||||
})
|
||||
|
||||
}),
|
||||
]).SetClass("flex justify-between w-full")
|
||||
rendering = new Toggle(question, answerWithEditButton, editMode)
|
||||
|
||||
}
|
||||
return rendering
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ export default class QuestionBox extends VariableUiElement {
|
|||
.filter((tr) => tr.question !== undefined)
|
||||
.filter((tr) => tr.question !== null)
|
||||
|
||||
let focus: () => void = () => {};
|
||||
|
||||
const tagRenderingQuestions = tagRenderings.map(
|
||||
(tagRendering, i) =>
|
||||
new Lazy(
|
||||
|
@ -42,6 +44,7 @@ export default class QuestionBox extends VariableUiElement {
|
|||
afterSave: () => {
|
||||
// We save and indicate progress by pinging and recalculating
|
||||
skippedQuestions.ping()
|
||||
focus()
|
||||
},
|
||||
cancelButton: Translations.t.general.skip
|
||||
.Clone()
|
||||
|
@ -49,6 +52,8 @@ export default class QuestionBox extends VariableUiElement {
|
|||
.onClick(() => {
|
||||
skippedQuestions.data.push(i)
|
||||
skippedQuestions.ping()
|
||||
focus()
|
||||
|
||||
}),
|
||||
})
|
||||
)
|
||||
|
@ -136,5 +141,8 @@ export default class QuestionBox extends VariableUiElement {
|
|||
|
||||
this.skippedQuestions = skippedQuestions
|
||||
this.restingQuestions = questionsToAsk
|
||||
focus = () => this.ScrollIntoView({
|
||||
onlyIfPartiallyHidden: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
17
Utils.ts
17
Utils.ts
|
@ -1,4 +1,5 @@
|
|||
import * as colors from "./assets/colors.json"
|
||||
import HTML = Mocha.reporters.HTML;
|
||||
|
||||
export class Utils {
|
||||
/**
|
||||
|
@ -1221,4 +1222,20 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
|||
d.setUTCMilliseconds(0)
|
||||
d.setUTCMinutes(0)
|
||||
}
|
||||
|
||||
public static findParentWithScrolling(element: HTMLElement): HTMLElement {
|
||||
// Check if the element itself has scrolling
|
||||
if (element.scrollHeight > element.clientHeight) {
|
||||
return element;
|
||||
}
|
||||
|
||||
// If the element does not have scrolling, check if it has a parent element
|
||||
if (!element.parentElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If the element has a parent, repeat the process for the parent element
|
||||
return Utils.findParentWithScrolling(element.parentElement);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue