mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-21 15:09:10 +00:00
Feat: reorder events with alt+ctrl + arrow up/down (#645)
* fix: key guard * feat: reorder events * refactor: return index from the getEvent functions
This commit is contained in:
committed by
GitHub
parent
b2c01a141a
commit
96280e5932
@@ -136,8 +136,8 @@ export default function Operator() {
|
|||||||
let isPast = Boolean(featureData.selectedEventId);
|
let isPast = Boolean(featureData.selectedEventId);
|
||||||
const hidePast = isStringBoolean(searchParams.get('hidepast'));
|
const hidePast = isStringBoolean(searchParams.get('hidepast'));
|
||||||
|
|
||||||
const firstEvent = getFirstEvent(data);
|
const { firstEvent } = getFirstEvent(data);
|
||||||
const lastEvent = getLastEvent(data);
|
const { lastEvent } = getLastEvent(data);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.operatorContainer}>
|
<div className={style.operatorContainer}>
|
||||||
|
|||||||
@@ -88,14 +88,16 @@ export default function Rundown(props: RundownProps) {
|
|||||||
(event: KeyboardEvent) => {
|
(event: KeyboardEvent) => {
|
||||||
// handle held key
|
// handle held key
|
||||||
if (event.repeat) return;
|
if (event.repeat) return;
|
||||||
// Check if the alt key is pressed
|
// Check if the modifier combination
|
||||||
if (event.altKey && (!event.ctrlKey || !event.shiftKey)) {
|
const modKeysAlt = event.altKey && !event.ctrlKey && !event.shiftKey;
|
||||||
|
const modKeysCtrlAlt = event.altKey && event.ctrlKey && !event.shiftKey;
|
||||||
|
if (modKeysAlt) {
|
||||||
switch (event.code) {
|
switch (event.code) {
|
||||||
case 'ArrowDown': {
|
case 'ArrowDown': {
|
||||||
if (entries.length < 1) {
|
if (entries.length < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const nextEvent = cursor == null ? getFirst(entries) : getNext(entries, cursor);
|
const nextEvent = cursor == null ? getFirst(entries) : getNext(entries, cursor)?.nextEvent;
|
||||||
if (nextEvent) {
|
if (nextEvent) {
|
||||||
moveCursorTo(nextEvent.id, nextEvent.type === SupportedEvent.Event);
|
moveCursorTo(nextEvent.id, nextEvent.type === SupportedEvent.Event);
|
||||||
}
|
}
|
||||||
@@ -106,7 +108,7 @@ export default function Rundown(props: RundownProps) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we check for this before
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- we check for this before
|
||||||
const previousEvent = cursor == null ? getFirst(entries) : getPrevious(entries, cursor);
|
const previousEvent = cursor == null ? getFirst(entries) : getPrevious(entries, cursor).previousEvent;
|
||||||
if (previousEvent) {
|
if (previousEvent) {
|
||||||
moveCursorTo(previousEvent.id, previousEvent.type === SupportedEvent.Event);
|
moveCursorTo(previousEvent.id, previousEvent.type === SupportedEvent.Event);
|
||||||
}
|
}
|
||||||
@@ -133,9 +135,24 @@ export default function Rundown(props: RundownProps) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (modKeysCtrlAlt) {
|
||||||
|
if (entries.length < 2 || cursor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.code == 'ArrowDown') {
|
||||||
|
const { nextEvent, nextIndex } = getNext(entries, cursor);
|
||||||
|
if (nextEvent && nextIndex !== null) {
|
||||||
|
reorderEvent(cursor, nextIndex - 1, nextIndex);
|
||||||
|
}
|
||||||
|
} else if (event.code == 'ArrowUp') {
|
||||||
|
const { previousEvent, previousIndex } = getPrevious(entries, cursor);
|
||||||
|
if (previousEvent && previousIndex !== null) {
|
||||||
|
reorderEvent(cursor, previousIndex + 1, previousIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[cursor, entries, insertAtCursor, moveCursorTo],
|
[cursor, entries, insertAtCursor, moveCursorTo, reorderEvent],
|
||||||
);
|
);
|
||||||
|
|
||||||
// we copy the state from the store here
|
// we copy the state from the store here
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function getIncrement(input: string): string {
|
|||||||
*/
|
*/
|
||||||
export function getCueCandidate(rundown: OntimeRundown, insertAfterId?: string): string {
|
export function getCueCandidate(rundown: OntimeRundown, insertAfterId?: string): string {
|
||||||
function addAtTop() {
|
function addAtTop() {
|
||||||
const firstEventCue = getFirstEvent(rundown)?.cue;
|
const firstEventCue = getFirstEvent(rundown).firstEvent?.cue;
|
||||||
|
|
||||||
if (isNumeric(firstEventCue)) {
|
if (isNumeric(firstEventCue)) {
|
||||||
return (Number(firstEventCue) / 10).toString();
|
return (Number(firstEventCue) / 10).toString();
|
||||||
@@ -68,11 +68,11 @@ export function getCueCandidate(rundown: OntimeRundown, insertAfterId?: string):
|
|||||||
// get elements around
|
// get elements around
|
||||||
let previousEvent: OntimeRundownEntry | undefined | null | OntimeEvent = rundown.at(afterIndex);
|
let previousEvent: OntimeRundownEntry | undefined | null | OntimeEvent = rundown.at(afterIndex);
|
||||||
if (!isOntimeEvent(previousEvent)) {
|
if (!isOntimeEvent(previousEvent)) {
|
||||||
previousEvent = getPreviousEvent(rundown, insertAfterId) as null | OntimeEvent;
|
previousEvent = getPreviousEvent(rundown, insertAfterId).previousEvent as null | OntimeEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cue = '1';
|
let cue = '1';
|
||||||
const nextEvent = getNextEvent(rundown, insertAfterId);
|
const { nextEvent } = getNextEvent(rundown, insertAfterId);
|
||||||
|
|
||||||
// try and increment the cue
|
// try and increment the cue
|
||||||
if (isOntimeEvent(previousEvent)) {
|
if (isOntimeEvent(previousEvent)) {
|
||||||
|
|||||||
@@ -1,6 +1,43 @@
|
|||||||
import { OntimeRundown, SupportedEvent } from 'ontime-types';
|
import { OntimeRundown, SupportedEvent } from 'ontime-types';
|
||||||
|
|
||||||
import { getNextEvent, getPreviousEvent } from './rundownUtils';
|
import { getNext, getNextEvent, getPrevious, getPreviousEvent } from './rundownUtils';
|
||||||
|
|
||||||
|
describe('getNext()', () => {
|
||||||
|
it('returns the next event of type event', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '1', type: SupportedEvent.Event },
|
||||||
|
{ id: '2', type: SupportedEvent.Event },
|
||||||
|
{ id: '3', type: SupportedEvent.Event },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { nextEvent, nextIndex } = getNext(testRundown as OntimeRundown, '1');
|
||||||
|
expect(nextEvent?.id).toBe('2');
|
||||||
|
expect(nextIndex).toBe(1);
|
||||||
|
});
|
||||||
|
it('alows other event types', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '1', type: SupportedEvent.Event },
|
||||||
|
{ id: '2', type: SupportedEvent.Delay },
|
||||||
|
{ id: '3', type: SupportedEvent.Block },
|
||||||
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { nextEvent, nextIndex } = getNext(testRundown as OntimeRundown, '1');
|
||||||
|
expect(nextEvent?.id).toBe('2');
|
||||||
|
expect(nextIndex).toBe(1);
|
||||||
|
});
|
||||||
|
it('returns null if none found', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '1', type: SupportedEvent.Event },
|
||||||
|
{ id: '2', type: SupportedEvent.Delay },
|
||||||
|
{ id: '3', type: SupportedEvent.Block },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { nextEvent, nextIndex } = getNext(testRundown as OntimeRundown, '3');
|
||||||
|
expect(nextEvent).toBe(null);
|
||||||
|
expect(nextIndex).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getNextEvent()', () => {
|
describe('getNextEvent()', () => {
|
||||||
it('returns the next event of type event', () => {
|
it('returns the next event of type event', () => {
|
||||||
@@ -10,8 +47,9 @@ describe('getNextEvent()', () => {
|
|||||||
{ id: '3', type: SupportedEvent.Event },
|
{ id: '3', type: SupportedEvent.Event },
|
||||||
];
|
];
|
||||||
|
|
||||||
const next = getNextEvent(testRundown as OntimeRundown, '1');
|
const { nextEvent, nextIndex } = getNextEvent(testRundown as OntimeRundown, '1');
|
||||||
expect(next?.id).toBe('2');
|
expect(nextEvent?.id).toBe('2');
|
||||||
|
expect(nextIndex).toBe(1);
|
||||||
});
|
});
|
||||||
it('ignores other event types', () => {
|
it('ignores other event types', () => {
|
||||||
const testRundown = [
|
const testRundown = [
|
||||||
@@ -21,8 +59,9 @@ describe('getNextEvent()', () => {
|
|||||||
{ id: '4', type: SupportedEvent.Event },
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
];
|
];
|
||||||
|
|
||||||
const next = getNextEvent(testRundown as OntimeRundown, '1');
|
const { nextEvent, nextIndex } = getNextEvent(testRundown as OntimeRundown, '1');
|
||||||
expect(next?.id).toBe('4');
|
expect(nextEvent?.id).toBe('4');
|
||||||
|
expect(nextIndex).toBe(3);
|
||||||
});
|
});
|
||||||
it('returns null if none found', () => {
|
it('returns null if none found', () => {
|
||||||
const testRundown = [
|
const testRundown = [
|
||||||
@@ -31,8 +70,46 @@ describe('getNextEvent()', () => {
|
|||||||
{ id: '3', type: SupportedEvent.Block },
|
{ id: '3', type: SupportedEvent.Block },
|
||||||
];
|
];
|
||||||
|
|
||||||
const next = getNextEvent(testRundown as OntimeRundown, '1');
|
const { nextEvent, nextIndex } = getNextEvent(testRundown as OntimeRundown, '1');
|
||||||
expect(next).toBe(null);
|
expect(nextEvent).toBe(null);
|
||||||
|
expect(nextIndex).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getPrevious()', () => {
|
||||||
|
it('returns the previous event of type event', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '1', type: SupportedEvent.Event },
|
||||||
|
{ id: '2', type: SupportedEvent.Event },
|
||||||
|
{ id: '3', type: SupportedEvent.Event },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { previousEvent, previousIndex } = getPrevious(testRundown as OntimeRundown, '3');
|
||||||
|
expect(previousEvent?.id).toBe('2');
|
||||||
|
expect(previousIndex).toBe(1);
|
||||||
|
});
|
||||||
|
it('allow other event types', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '1', type: SupportedEvent.Event },
|
||||||
|
{ id: '2', type: SupportedEvent.Delay },
|
||||||
|
{ id: '3', type: SupportedEvent.Block },
|
||||||
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { previousEvent, previousIndex } = getPrevious(testRundown as OntimeRundown, '3');
|
||||||
|
expect(previousEvent?.id).toBe('2');
|
||||||
|
expect(previousIndex).toBe(1);
|
||||||
|
});
|
||||||
|
it('returns null if none found', () => {
|
||||||
|
const testRundown = [
|
||||||
|
{ id: '2', type: SupportedEvent.Delay },
|
||||||
|
{ id: '3', type: SupportedEvent.Block },
|
||||||
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
|
];
|
||||||
|
|
||||||
|
const { previousEvent, previousIndex } = getPrevious(testRundown as OntimeRundown, '2');
|
||||||
|
expect(previousEvent).toBe(null);
|
||||||
|
expect(previousIndex).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -44,8 +121,9 @@ describe('getPreviousEvent()', () => {
|
|||||||
{ id: '3', type: SupportedEvent.Event },
|
{ id: '3', type: SupportedEvent.Event },
|
||||||
];
|
];
|
||||||
|
|
||||||
const previous = getPreviousEvent(testRundown as OntimeRundown, '3');
|
const { previousEvent, previousIndex } = getPreviousEvent(testRundown as OntimeRundown, '3');
|
||||||
expect(previous?.id).toBe('2');
|
expect(previousEvent?.id).toBe('2');
|
||||||
|
expect(previousIndex).toBe(1);
|
||||||
});
|
});
|
||||||
it('ignores other event types', () => {
|
it('ignores other event types', () => {
|
||||||
const testRundown = [
|
const testRundown = [
|
||||||
@@ -55,8 +133,9 @@ describe('getPreviousEvent()', () => {
|
|||||||
{ id: '4', type: SupportedEvent.Event },
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
];
|
];
|
||||||
|
|
||||||
const previous = getPreviousEvent(testRundown as OntimeRundown, '4');
|
const { previousEvent, previousIndex } = getPreviousEvent(testRundown as OntimeRundown, '4');
|
||||||
expect(previous?.id).toBe('1');
|
expect(previousEvent?.id).toBe('1');
|
||||||
|
expect(previousIndex).toBe(0);
|
||||||
});
|
});
|
||||||
it('returns null if none found', () => {
|
it('returns null if none found', () => {
|
||||||
const testRundown = [
|
const testRundown = [
|
||||||
@@ -65,7 +144,8 @@ describe('getPreviousEvent()', () => {
|
|||||||
{ id: '4', type: SupportedEvent.Event },
|
{ id: '4', type: SupportedEvent.Event },
|
||||||
];
|
];
|
||||||
|
|
||||||
const previous = getNextEvent(testRundown as OntimeRundown, '1');
|
const { previousEvent, previousIndex } = getPreviousEvent(testRundown as OntimeRundown, '2');
|
||||||
expect(previous).toBe(null);
|
expect(previousEvent).toBe(null);
|
||||||
|
expect(previousIndex).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,45 +12,55 @@ export function getFirst(rundown: OntimeRundownEntry[]) {
|
|||||||
/**
|
/**
|
||||||
* Gets first scheduled event in rundown, if it exists
|
* Gets first scheduled event in rundown, if it exists
|
||||||
* @param {OntimeRundownEntry[]} rundown
|
* @param {OntimeRundownEntry[]} rundown
|
||||||
* @return {OntimeEvent | null}
|
* @return {{ firstEvent: OntimeEvent | null; firstIndex: number | null } }
|
||||||
*/
|
*/
|
||||||
export function getFirstEvent(rundown: OntimeRundownEntry[]) {
|
export function getFirstEvent(rundown: OntimeRundownEntry[]): {
|
||||||
|
firstEvent: OntimeEvent | null;
|
||||||
|
firstIndex: number | null;
|
||||||
|
} {
|
||||||
for (let i = 0; i < rundown.length; i++) {
|
for (let i = 0; i < rundown.length; i++) {
|
||||||
const event = rundown[i];
|
const firstEvent = rundown[i];
|
||||||
if (isOntimeEvent(event)) {
|
if (isOntimeEvent(firstEvent)) {
|
||||||
return event;
|
return { firstEvent, firstIndex: i };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return { firstEvent: null, firstIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLastEvent(rundown: OntimeRundown): OntimeEvent | null {
|
export function getLastEvent(rundown: OntimeRundown): {
|
||||||
|
lastEvent: OntimeEvent | null;
|
||||||
|
lastIndex: number | null;
|
||||||
|
} {
|
||||||
if (rundown.length < 1) {
|
if (rundown.length < 1) {
|
||||||
return null;
|
return { lastEvent: null, lastIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = rundown.length - 1; i > 0; i--) {
|
for (let i = rundown.length - 1; i > 0; i--) {
|
||||||
const event = rundown.at(i);
|
const lastEvent = rundown.at(i);
|
||||||
if (isOntimeEvent(event)) {
|
if (isOntimeEvent(lastEvent)) {
|
||||||
return event;
|
return { lastEvent, lastIndex: i };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return { lastEvent: null, lastIndex: null };
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets next event in rundown, if it exists
|
* Gets next event in rundown, if it exists
|
||||||
* @param {OntimeRundownEntry[]} rundown
|
* @param {OntimeRundownEntry[]} rundown
|
||||||
* @param {string} currentId
|
* @param {string} currentId
|
||||||
* @return {OntimeRundownEntry | null}
|
* @return {{ nextEvent: OntimeRundownEntry | null; nextIndex: number | null } }
|
||||||
*/
|
*/
|
||||||
export function getNext(rundown: OntimeRundownEntry[], currentId: string): OntimeRundownEntry | null {
|
export function getNext(
|
||||||
|
rundown: OntimeRundownEntry[],
|
||||||
|
currentId: string,
|
||||||
|
): { nextEvent: OntimeRundownEntry | null; nextIndex: number | null } {
|
||||||
const index = rundown.findIndex((event) => event.id === currentId);
|
const index = rundown.findIndex((event) => event.id === currentId);
|
||||||
if (index !== -1 && index + 1 < rundown.length) {
|
if (index !== -1 && index + 1 < rundown.length) {
|
||||||
return rundown[index + 1];
|
const nextIndex = index + 1;
|
||||||
|
const nextEvent = rundown[nextIndex];
|
||||||
|
return { nextEvent, nextIndex };
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return { nextEvent: null, nextIndex: null };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,35 +68,43 @@ export function getNext(rundown: OntimeRundownEntry[], currentId: string): Ontim
|
|||||||
* Gets next scheduled event in rundown, if it exists
|
* Gets next scheduled event in rundown, if it exists
|
||||||
* @param {OntimeRundownEntry[]} rundown
|
* @param {OntimeRundownEntry[]} rundown
|
||||||
* @param {string} currentId
|
* @param {string} currentId
|
||||||
* @return {OntimeEvent | null}
|
* @return {{ nextEvent: OntimeEvent | null; nextIndex: number | null } }
|
||||||
*/
|
*/
|
||||||
export function getNextEvent(rundown: OntimeRundownEntry[], currentId: string): OntimeEvent | null {
|
export function getNextEvent(
|
||||||
|
rundown: OntimeRundownEntry[],
|
||||||
|
currentId: string,
|
||||||
|
): { nextEvent: OntimeEvent | null; nextIndex: number | null } {
|
||||||
const index = rundown.findIndex((event) => event.id === currentId);
|
const index = rundown.findIndex((event) => event.id === currentId);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return null;
|
return { nextEvent: null, nextIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = index + 1; i < rundown.length; i++) {
|
for (let i = index + 1; i < rundown.length; i++) {
|
||||||
const event = rundown[i];
|
const nextEvent = rundown[i];
|
||||||
if (isOntimeEvent(event)) {
|
if (isOntimeEvent(nextEvent)) {
|
||||||
return event;
|
return { nextEvent, nextIndex: i };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return { nextEvent: null, nextIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets previous event in rundown, if it exists
|
* Gets previous event in rundown, if it exists
|
||||||
* @param {OntimeRundownEntry[]} rundown
|
* @param {OntimeRundownEntry[]} rundown
|
||||||
* @param {string} currentId
|
* @param {string} currentId
|
||||||
* @return {OntimeRundownEntry | null}
|
* @return {{ previousEvent: OntimeRundownEntry | null; previousIndex: number | null } }
|
||||||
*/
|
*/
|
||||||
export function getPrevious(rundown: OntimeRundownEntry[], currentId: string) {
|
export function getPrevious(
|
||||||
|
rundown: OntimeRundownEntry[],
|
||||||
|
currentId: string,
|
||||||
|
): { previousEvent: OntimeRundownEntry | null; previousIndex: number | null } {
|
||||||
const index = rundown.findIndex((event) => event.id === currentId);
|
const index = rundown.findIndex((event) => event.id === currentId);
|
||||||
if (index !== -1 && index - 1 >= 0) {
|
if (index !== -1 && index - 1 >= 0) {
|
||||||
return rundown[index - 1];
|
const previousIndex = index - 1;
|
||||||
|
const previousEvent = rundown[previousIndex];
|
||||||
|
return { previousEvent, previousIndex };
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return { previousEvent: null, previousIndex: null };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,21 +112,23 @@ export function getPrevious(rundown: OntimeRundownEntry[], currentId: string) {
|
|||||||
* Gets previous scheduled event in rundown, if it exists
|
* Gets previous scheduled event in rundown, if it exists
|
||||||
* @param {OntimeRundownEntry[]} rundown
|
* @param {OntimeRundownEntry[]} rundown
|
||||||
* @param {string} currentId
|
* @param {string} currentId
|
||||||
* @return {OntimeEvent | null}
|
* @return {{ previousEvent: OntimeRundownEntry | null; previousIndex: number | null } }
|
||||||
*/
|
*/
|
||||||
export function getPreviousEvent(rundown: OntimeRundownEntry[], currentId: string): OntimeEvent | null {
|
export function getPreviousEvent(
|
||||||
|
rundown: OntimeRundownEntry[],
|
||||||
|
currentId: string,
|
||||||
|
): { previousEvent: OntimeEvent | null; previousIndex: number | null } {
|
||||||
const index = rundown.findIndex((event) => event.id === currentId);
|
const index = rundown.findIndex((event) => event.id === currentId);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return null;
|
return { previousEvent: null, previousIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = index - 1; i >= 0; i--) {
|
for (let i = index - 1; i >= 0; i--) {
|
||||||
const event = rundown[i];
|
const previousEvent = rundown[i];
|
||||||
if (isOntimeEvent(event)) {
|
if (isOntimeEvent(previousEvent)) {
|
||||||
return event;
|
return { previousEvent, previousIndex: i };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return { previousEvent: null, previousIndex: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user