Skip to content

Commit 7f7e23e

Browse files
authored
Merge pull request #1249 from nrkno/fix/ho-prompter/sofie-3082
fix: resolve an issue with prompter jumping when Parts become PartInstances
2 parents ad9dfce + a670a73 commit 7f7e23e

File tree

2 files changed

+83
-74
lines changed

2 files changed

+83
-74
lines changed

meteor/client/ui/Prompter/PrompterView.tsx

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ export class PrompterViewInner extends MeteorReactComponent<Translated<IProps &
321321
}
322322
scrollToPartInstance(partInstanceId: PartInstanceId): void {
323323
const scrollMargin = this.calculateScrollPosition()
324-
const target = document.querySelector(`#partInstance_${partInstanceId}`)
324+
const target = document.querySelector(`[data-part-instance-id="${partInstanceId}"]`)
325325

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

411-
if (playlist !== undefined) {
412-
const positionTop = window.scrollY
413-
const positionBottom = positionTop + window.innerHeight
411+
if (playlist === undefined) return
412+
const positionTop = window.scrollY
413+
const positionBottom = positionTop + window.innerHeight
414414

415-
let currentPartElement: Element | null = null
416-
let currentPartElementAfter: Element | null = null
417-
let nextPartElementAfter: Element | null = null
415+
let currentPartElement: Element | null = null
416+
let currentPartElementAfter: Element | null = null
417+
let nextPartElementAfter: Element | null = null
418418

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

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

425-
if (playlist.currentPartInfo && current.classList.contains(`live`)) {
426-
currentPartElement = current
427-
currentPartElementAfter = next
428-
}
429-
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
430-
nextPartElementAfter = next
431-
}
425+
if (playlist.currentPartInfo && current.classList.contains(`live`)) {
426+
currentPartElement = current
427+
currentPartElementAfter = next
428+
}
429+
if (playlist.nextPartInfo && current.classList.contains(`next`)) {
430+
nextPartElementAfter = next
432431
}
432+
}
433433

434-
const currentPositionStart = currentPartElement
435-
? currentPartElement.getBoundingClientRect().top + positionTop
436-
: null
437-
const currentPositionEnd = currentPartElementAfter
438-
? currentPartElementAfter.getBoundingClientRect().top + positionTop
439-
: null
440-
441-
const nextPositionEnd = nextPartElementAfter
442-
? nextPartElementAfter.getBoundingClientRect().top + positionTop
443-
: null
444-
445-
const takeIndicator = document.querySelector('.take-indicator')
446-
if (takeIndicator) {
447-
if (currentPositionEnd && currentPositionEnd < positionTop) {
448-
// Display take "^" indicator
449-
takeIndicator.classList.remove('hidden')
450-
takeIndicator.classList.add('top')
451-
} else if (currentPositionStart && currentPositionStart > positionBottom) {
452-
// Display take "v" indicator
453-
takeIndicator.classList.remove('hidden', 'top')
454-
} else {
455-
takeIndicator.classList.add('hidden')
456-
}
434+
const currentPositionStart = currentPartElement
435+
? currentPartElement.getBoundingClientRect().top + positionTop
436+
: null
437+
const currentPositionEnd = currentPartElementAfter
438+
? currentPartElementAfter.getBoundingClientRect().top + positionTop
439+
: null
440+
441+
const nextPositionEnd = nextPartElementAfter ? nextPartElementAfter.getBoundingClientRect().top + positionTop : null
442+
443+
const takeIndicator = document.querySelector('.take-indicator')
444+
if (takeIndicator) {
445+
if (currentPositionEnd && currentPositionEnd < positionTop) {
446+
// Display take "^" indicator
447+
takeIndicator.classList.remove('hidden')
448+
takeIndicator.classList.add('top')
449+
} else if (currentPositionStart && currentPositionStart > positionBottom) {
450+
// Display take "v" indicator
451+
takeIndicator.classList.remove('hidden', 'top')
452+
} else {
453+
takeIndicator.classList.add('hidden')
457454
}
455+
}
458456

459-
const nextIndicator = document.querySelector('.next-indicator')
460-
if (nextIndicator) {
461-
if (nextPositionEnd && nextPositionEnd < positionTop) {
462-
// Display next "^" indicator
463-
nextIndicator.classList.remove('hidden')
464-
nextIndicator.classList.add('top')
465-
} else {
466-
nextIndicator.classList.add('hidden')
467-
}
457+
const nextIndicator = document.querySelector('.next-indicator')
458+
if (nextIndicator) {
459+
if (nextPositionEnd && nextPositionEnd < positionTop) {
460+
// Display next "^" indicator
461+
nextIndicator.classList.remove('hidden')
462+
nextIndicator.classList.add('top')
463+
} else {
464+
nextIndicator.classList.add('hidden')
468465
}
469466
}
470467
}
@@ -737,24 +734,32 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
737734
// Go through the anchors and use the first one that we find:
738735
for (const scrollAnchor of scrollAnchors) {
739736
const anchor = document.getElementById(scrollAnchor.anchorId)
740-
if (anchor) {
741-
const { top } = anchor.getBoundingClientRect()
742-
743-
if (scrollAnchor.offset !== null) {
744-
window.scrollBy({
745-
top: top - scrollAnchor.offset,
746-
})
747-
// We've scrolled, exit the function!
748-
return
749-
} else {
750-
// Note: config.margin does not have to be taken into account here,
751-
// the css margins magically does it for us.
752-
window.scrollBy({
753-
top: top - readPosition,
754-
})
755-
// We've scrolled, exit the function!
756-
return
757-
}
737+
if (!anchor) continue
738+
739+
const { top } = anchor.getBoundingClientRect()
740+
741+
if (scrollAnchor.offset !== null) {
742+
this.props.config.debug &&
743+
logger.debug(
744+
`Selected anchor ${scrollAnchor.anchorId} as anchor element in view, restoring position ${scrollAnchor.offset}`
745+
)
746+
747+
window.scrollBy({
748+
top: top - scrollAnchor.offset,
749+
})
750+
// We've scrolled, exit the function!
751+
return
752+
} else {
753+
this.props.config.debug &&
754+
logger.debug(`Selected anchor ${scrollAnchor.anchorId} as anchor element outside of view, jumping to it`)
755+
756+
// Note: config.margin does not have to be taken into account here,
757+
// the css margins magically does it for us.
758+
window.scrollBy({
759+
top: top - readPosition,
760+
})
761+
// We've scrolled, exit the function!
762+
return
758763
}
759764
}
760765
// None of the anchors where found at this point.
@@ -766,6 +771,7 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
766771
.join(', ')}`
767772
)
768773

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

849855
private getPartStatus(prompterData: PrompterData, part: PrompterDataPart) {
850-
if (prompterData.currentPartInstanceId === part.id) {
856+
if (prompterData.currentPartInstanceId === part.partInstanceId) {
851857
return 'live'
852-
} else if (prompterData.nextPartInstanceId === part.id) {
858+
} else if (prompterData.nextPartInstanceId === part.partInstanceId) {
853859
return 'next'
854860
} else {
855861
return null
@@ -881,9 +887,10 @@ export const Prompter = translateWithTracker<PropsWithChildren<IPrompterProps>,
881887
segment.parts.forEach((part) => {
882888
lines.push(
883889
<div
884-
id={`partInstance_${part.id}`}
890+
id={`part_${part.id}`}
885891
data-obj-id={segment.id + '_' + part.id}
886-
key={'partInstance_' + part.id}
892+
data-part-instance-id={part.partInstanceId}
893+
key={'part_' + part.id}
887894
className={ClassNames('prompter-part', 'scroll-anchor', this.getPartStatus(prompterData, part))}
888895
>
889896
{part.title || 'N/A'}

meteor/client/ui/Prompter/prompter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ export interface PrompterDataSegment {
3535
parts: PrompterDataPart[]
3636
}
3737
export interface PrompterDataPart {
38-
id: PartInstanceId
38+
id: PartId
39+
partInstanceId: PartInstanceId
3940
title: string | undefined
4041
pieces: PrompterDataPiece[]
4142
}
@@ -183,7 +184,8 @@ export namespace PrompterAPI {
183184
for (let partIndex = 0; partIndex < partInstances.length; partIndex++) {
184185
const partInstance = partInstances[partIndex]
185186
const partData: PrompterDataPart = {
186-
id: partInstance._id,
187+
id: partInstance.part._id,
188+
partInstanceId: partInstance._id,
187189
title: partInstance.part.prompterTitle || partInstance.part.title,
188190
pieces: [],
189191
}

0 commit comments

Comments
 (0)