Skip to content

Commit

Permalink
Merge pull request #1249 from nrkno/fix/ho-prompter/sofie-3082
Browse files Browse the repository at this point in the history
fix: resolve an issue with prompter jumping when Parts become PartInstances
  • Loading branch information
jstarpl authored Sep 19, 2024
2 parents ad9dfce + a670a73 commit 7f7e23e
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 74 deletions.
151 changes: 79 additions & 72 deletions meteor/client/ui/Prompter/PrompterView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export class PrompterViewInner extends MeteorReactComponent<Translated<IProps &
}
scrollToPartInstance(partInstanceId: PartInstanceId): void {
const scrollMargin = this.calculateScrollPosition()
const target = document.querySelector(`#partInstance_${partInstanceId}`)
const target = document.querySelector(`[data-part-instance-id="${partInstanceId}"]`)

if (target) {
Velocity(document.body, 'finish')
Expand Down Expand Up @@ -408,63 +408,60 @@ export class PrompterViewInner extends MeteorReactComponent<Translated<IProps &
private checkCurrentTakeMarkers = () => {
const playlist = this.props.rundownPlaylist

if (playlist !== undefined) {
const positionTop = window.scrollY
const positionBottom = positionTop + window.innerHeight
if (playlist === undefined) return
const positionTop = window.scrollY
const positionBottom = positionTop + window.innerHeight

let currentPartElement: Element | null = null
let currentPartElementAfter: Element | null = null
let nextPartElementAfter: Element | null = null
let currentPartElement: Element | null = null
let currentPartElementAfter: Element | null = null
let nextPartElementAfter: Element | null = null

const anchors: Array<Element> = Array.from(document.querySelectorAll('.scroll-anchor'))
const anchors: Array<Element> = Array.from(document.querySelectorAll('.scroll-anchor'))

for (let index = 0; index < anchors.length; index++) {
const current = anchors[index]
const next = index + 1 < anchors.length ? anchors[index + 1] : null
for (let index = 0; index < anchors.length; index++) {
const current = anchors[index]
const next = index + 1 < anchors.length ? anchors[index + 1] : null

if (playlist.currentPartInfo && current.classList.contains(`live`)) {
currentPartElement = current
currentPartElementAfter = next
}
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
nextPartElementAfter = next
}
if (playlist.currentPartInfo && current.classList.contains(`live`)) {
currentPartElement = current
currentPartElementAfter = next
}
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
nextPartElementAfter = next
}
}

const currentPositionStart = currentPartElement
? currentPartElement.getBoundingClientRect().top + positionTop
: null
const currentPositionEnd = currentPartElementAfter
? currentPartElementAfter.getBoundingClientRect().top + positionTop
: null

const nextPositionEnd = nextPartElementAfter
? nextPartElementAfter.getBoundingClientRect().top + positionTop
: null

const takeIndicator = document.querySelector('.take-indicator')
if (takeIndicator) {
if (currentPositionEnd && currentPositionEnd < positionTop) {
// Display take "^" indicator
takeIndicator.classList.remove('hidden')
takeIndicator.classList.add('top')
} else if (currentPositionStart && currentPositionStart > positionBottom) {
// Display take "v" indicator
takeIndicator.classList.remove('hidden', 'top')
} else {
takeIndicator.classList.add('hidden')
}
const currentPositionStart = currentPartElement
? currentPartElement.getBoundingClientRect().top + positionTop
: null
const currentPositionEnd = currentPartElementAfter
? currentPartElementAfter.getBoundingClientRect().top + positionTop
: null

const nextPositionEnd = nextPartElementAfter ? nextPartElementAfter.getBoundingClientRect().top + positionTop : null

const takeIndicator = document.querySelector('.take-indicator')
if (takeIndicator) {
if (currentPositionEnd && currentPositionEnd < positionTop) {
// Display take "^" indicator
takeIndicator.classList.remove('hidden')
takeIndicator.classList.add('top')
} else if (currentPositionStart && currentPositionStart > positionBottom) {
// Display take "v" indicator
takeIndicator.classList.remove('hidden', 'top')
} else {
takeIndicator.classList.add('hidden')
}
}

const nextIndicator = document.querySelector('.next-indicator')
if (nextIndicator) {
if (nextPositionEnd && nextPositionEnd < positionTop) {
// Display next "^" indicator
nextIndicator.classList.remove('hidden')
nextIndicator.classList.add('top')
} else {
nextIndicator.classList.add('hidden')
}
const nextIndicator = document.querySelector('.next-indicator')
if (nextIndicator) {
if (nextPositionEnd && nextPositionEnd < positionTop) {
// Display next "^" indicator
nextIndicator.classList.remove('hidden')
nextIndicator.classList.add('top')
} else {
nextIndicator.classList.add('hidden')
}
}
}
Expand Down Expand Up @@ -737,24 +734,32 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
// Go through the anchors and use the first one that we find:
for (const scrollAnchor of scrollAnchors) {
const anchor = document.getElementById(scrollAnchor.anchorId)
if (anchor) {
const { top } = anchor.getBoundingClientRect()

if (scrollAnchor.offset !== null) {
window.scrollBy({
top: top - scrollAnchor.offset,
})
// We've scrolled, exit the function!
return
} else {
// Note: config.margin does not have to be taken into account here,
// the css margins magically does it for us.
window.scrollBy({
top: top - readPosition,
})
// We've scrolled, exit the function!
return
}
if (!anchor) continue

const { top } = anchor.getBoundingClientRect()

if (scrollAnchor.offset !== null) {
this.props.config.debug &&
logger.debug(
`Selected anchor ${scrollAnchor.anchorId} as anchor element in view, restoring position ${scrollAnchor.offset}`
)

window.scrollBy({
top: top - scrollAnchor.offset,
})
// We've scrolled, exit the function!
return
} else {
this.props.config.debug &&
logger.debug(`Selected anchor ${scrollAnchor.anchorId} as anchor element outside of view, jumping to it`)

// Note: config.margin does not have to be taken into account here,
// the css margins magically does it for us.
window.scrollBy({
top: top - readPosition,
})
// We've scrolled, exit the function!
return
}
}
// None of the anchors where found at this point.
Expand All @@ -766,6 +771,7 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
.join(', ')}`
)

// TODO: In the past 4 months this has been here, this hasn't logged a single line, should we keep it?
// Below is for troubleshooting, see if the anchor is in prompterData:
if (!this.props.prompterData) {
logger.error(`Read anchor troubleshooting: no prompterData`)
Expand Down Expand Up @@ -847,9 +853,9 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
}

private getPartStatus(prompterData: PrompterData, part: PrompterDataPart) {
if (prompterData.currentPartInstanceId === part.id) {
if (prompterData.currentPartInstanceId === part.partInstanceId) {
return 'live'
} else if (prompterData.nextPartInstanceId === part.id) {
} else if (prompterData.nextPartInstanceId === part.partInstanceId) {
return 'next'
} else {
return null
Expand Down Expand Up @@ -881,9 +887,10 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
segment.parts.forEach((part) => {
lines.push(
<div
id={`partInstance_${part.id}`}
id={`part_${part.id}`}
data-obj-id={segment.id + '_' + part.id}
key={'partInstance_' + part.id}
data-part-instance-id={part.partInstanceId}
key={'part_' + part.id}
className={ClassNames('prompter-part', 'scroll-anchor', this.getPartStatus(prompterData, part))}
>
{part.title || 'N/A'}
Expand Down
6 changes: 4 additions & 2 deletions meteor/client/ui/Prompter/prompter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ export interface PrompterDataSegment {
parts: PrompterDataPart[]
}
export interface PrompterDataPart {
id: PartInstanceId
id: PartId
partInstanceId: PartInstanceId
title: string | undefined
pieces: PrompterDataPiece[]
}
Expand Down Expand Up @@ -183,7 +184,8 @@ export namespace PrompterAPI {
for (let partIndex = 0; partIndex < partInstances.length; partIndex++) {
const partInstance = partInstances[partIndex]
const partData: PrompterDataPart = {
id: partInstance._id,
id: partInstance.part._id,
partInstanceId: partInstance._id,
title: partInstance.part.prompterTitle || partInstance.part.title,
pieces: [],
}
Expand Down

0 comments on commit 7f7e23e

Please sign in to comment.