Skip to content

Commit

Permalink
Fix closeMenu() when not yet fully upgraded (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
MattiasBuelens authored Feb 14, 2024
1 parent 2e69dad commit b874fe3
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 27 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
> - 🏠 Internal
> - 💅 Polish
## Unreleased

- 🐛 Fixed an issue where `<theoplayer-ui>` could throw an error when the player changes sources before all custom elements are properly registered. ([#49](https://github.com/THEOplayer/web-ui/pull/49))

## v1.6.0 (2024-02-08)

- 🚀 Introducing [Open Video UI for React](https://www.npmjs.com/package/@theoplayer/react-ui). ([#48](https://github.com/THEOplayer/web-ui/pull/48))
Expand Down
14 changes: 10 additions & 4 deletions src/UIContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ import { fullscreenAPI } from './util/FullscreenUtils';
import { Attribute } from './util/Attribute';
import { isMobile, isTv } from './util/Environment';
import { Rectangle } from './util/GeometryUtils';
import './components/GestureReceiver';
import { PREVIEW_TIME_CHANGE_EVENT, type PreviewTimeChangeEvent } from './events/PreviewTimeChangeEvent';
import type { StreamType } from './util/StreamType';
import type { StreamTypeChangeEvent } from './events/StreamTypeChangeEvent';
import { STREAM_TYPE_CHANGE_EVENT } from './events/StreamTypeChangeEvent';
import { createCustomEvent } from './util/EventUtils';
import { getTargetQualities } from './util/TrackUtils';
import type { MenuGroup } from './components';
import './components/MenuGroup';
import { MenuGroup } from './components/MenuGroup';
import { MENU_CHANGE_EVENT } from './events/MenuChangeEvent';
import type { DeviceType } from './util/DeviceType';
import { getFocusedChild, navigateByArrowKey } from './util/KeyboardNavigation';
import { isArrowKey, isBackKey, KeyCode } from './util/KeyCode';
import { READY_EVENT } from './events/ReadyEvent';

// Load components used in template
import './components/GestureReceiver';

const template = document.createElement('template');
template.innerHTML = `<style>${elementCss}</style>${elementHtml}`;
shadyCss.prepareTemplate(template, 'theoplayer-ui');
Expand Down Expand Up @@ -378,6 +379,10 @@ export class UIContainer extends HTMLElement {
connectedCallback(): void {
shadyCss.styleElement(this);

if (!(this._menuGroup instanceof MenuGroup)) {
customElements.upgrade(this._menuGroup);
}

if (!this.hasAttribute(Attribute.DEVICE_TYPE)) {
const deviceType: DeviceType = isMobile() ? 'mobile' : isTv() ? 'tv' : 'desktop';
this.setAttribute(Attribute.DEVICE_TYPE, deviceType);
Expand Down Expand Up @@ -661,7 +666,8 @@ export class UIContainer extends HTMLElement {
}

private closeMenu_(): void {
this._menuGroup.closeMenu();
// Menu group might not be upgraded yet
this._menuGroup.closeMenu?.();
this._menuOpener?.focus();
this._menuOpener = undefined;
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/LanguageMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import { StateReceiverMixin } from './StateReceiverMixin';
import type { ChromelessPlayer, MediaTrack, TextTrack } from 'theoplayer/chromeless';
import { isSubtitleTrack } from '../util/TrackUtils';
import { Attribute } from '../util/Attribute';
import { toggleAttribute } from '../util/CommonUtils';

// Load components used in template
import './TrackRadioGroup';
import './TextTrackStyleMenu';
import { toggleAttribute } from '../util/CommonUtils';

const template = document.createElement('template');
template.innerHTML = menuGroupTemplate(languageMenuHtml, languageMenuCss);
Expand Down
19 changes: 9 additions & 10 deletions src/components/MenuGroup.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as shadyCss from '@webcomponents/shadycss';
import menuGroupCss from './MenuGroup.css';
import { Attribute } from '../util/Attribute';
import { arrayFind, arrayFindIndex, fromArrayLike, isElement, isHTMLElement, noOp } from '../util/CommonUtils';
import { arrayFind, arrayFindIndex, fromArrayLike, isElement, isHTMLElement, noOp, upgradeCustomElementIfNeeded } from '../util/CommonUtils';
import { CLOSE_MENU_EVENT, type CloseMenuEvent } from '../events/CloseMenuEvent';
import { TOGGLE_MENU_EVENT, type ToggleMenuEvent } from '../events/ToggleMenuEvent';
import { isBackKey, KeyCode } from '../util/KeyCode';
import { isBackKey } from '../util/KeyCode';
import { createCustomEvent } from '../util/EventUtils';
import type { MenuChangeEvent } from '../events/MenuChangeEvent';
import { MENU_CHANGE_EVENT } from '../events/MenuChangeEvent';
Expand Down Expand Up @@ -260,19 +260,18 @@ export class MenuGroup extends HTMLElement {
...fromArrayLike(this.shadowRoot!.children),
...(this._menuSlot ? this._menuSlot.assignedNodes({ flatten: true }).filter(isElement) : [])
];
const upgradePromises: Array<Promise<unknown>> = [];
for (const child of children) {
if (!isMenuElement(child)) {
// Upgrade custom elements if needed
const childName = child.nodeName.toLowerCase();
if (childName.indexOf('-') >= 0) {
if (customElements.get(childName)) {
customElements.upgrade(child);
} else {
customElements.whenDefined(childName).then(this._onMenuListChange, noOp);
}
const promise = upgradeCustomElementIfNeeded(child);
if (promise) {
upgradePromises.push(promise);
}
}
}
if (upgradePromises.length > 0) {
Promise.all(upgradePromises).then(this._onMenuListChange, noOp);
}
const newMenus = children.filter(isMenuElement);
// Close all removed menus
for (const oldMenu of this._menus) {
Expand Down
2 changes: 2 additions & 0 deletions src/components/PlaybackRateMenu.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as shadyCss from '@webcomponents/shadycss';
import { Menu, menuTemplate } from './Menu';
import playbackRateMenuHtml from './PlaybackRateMenu.html';

// Load components used in template
import './PlaybackRateRadioGroup';

const template = document.createElement('template');
Expand Down
19 changes: 9 additions & 10 deletions src/components/RadioGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import * as shadyCss from '@webcomponents/shadycss';
import { isArrowKey, KeyCode } from '../util/KeyCode';
import { RadioButton } from './RadioButton';
import { createEvent } from '../util/EventUtils';
import { arrayFind, isElement, noOp } from '../util/CommonUtils';
import './RadioButton';
import { arrayFind, isElement, noOp, upgradeCustomElementIfNeeded } from '../util/CommonUtils';
import { StateReceiverMixin } from './StateReceiverMixin';
import { Attribute } from '../util/Attribute';
import type { DeviceType } from '../util/DeviceType';
Expand Down Expand Up @@ -78,19 +77,19 @@ export class RadioGroup extends StateReceiverMixin(HTMLElement, ['deviceType'])

private readonly _onSlotChange = () => {
const children = this._slot.assignedNodes({ flatten: true }).filter(isElement);
const upgradePromises: Array<Promise<unknown>> = [];
for (const child of children) {
if (!isRadioButton(child)) {
// Upgrade custom elements if needed
const childName = child.nodeName.toLowerCase();
if (childName.indexOf('-') >= 0) {
if (customElements.get(childName)) {
customElements.upgrade(child);
} else {
customElements.whenDefined(childName).then(this._onSlotChange, noOp);
}
const promise = upgradeCustomElementIfNeeded(child);
if (promise) {
upgradePromises.push(promise);
}
}
}
if (upgradePromises.length > 0) {
Promise.all(upgradePromises).then(this._onSlotChange, noOp);
}

this._radioButtons = children.filter(isRadioButton);

let firstFocusedButton = this.focusedRadioButton;
Expand Down
2 changes: 2 additions & 0 deletions src/components/SettingsMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as shadyCss from '@webcomponents/shadycss';
import { MenuGroup, menuGroupTemplate } from './MenuGroup';
import settingsMenuHtml from './SettingsMenu.html';
import menuTableCss from './MenuTable.css';

// Load components used in template
import './ActiveQualityDisplay';
import './PlaybackRateDisplay';
import './PlaybackRateMenu';
Expand Down
2 changes: 2 additions & 0 deletions src/components/TextTrackStyleMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { MenuGroup, menuGroupTemplate } from './MenuGroup';
import textTrackStyleMenuHtml from './TextTrackStyleMenu.html';
import textTrackStyleMenuCss from './TextTrackStyleMenu.css';
import menuTableCss from './MenuTable.css';

// Load components used in template
import './TextTrackStyleDisplay';
import './TextTrackStyleRadioGroup';

Expand Down
6 changes: 4 additions & 2 deletions src/components/TimeRange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ import type { PreviewTimeChangeEvent } from '../events/PreviewTimeChangeEvent';
import { PREVIEW_TIME_CHANGE_EVENT } from '../events/PreviewTimeChangeEvent';
import { Attribute } from '../util/Attribute';
import type { StreamType } from '../util/StreamType';
import './PreviewThumbnail';
import './PreviewTimeDisplay';
import { isLinearAd } from '../util/AdUtils';
import type { ColorStops } from '../util/ColorStops';
import { KeyCode } from '../util/KeyCode';

// Load components used in template
import './PreviewThumbnail';
import './PreviewTimeDisplay';

const template = document.createElement('template');
template.innerHTML = rangeTemplate(timeRangeHtml, timeRangeCss);
shadyCss.prepareTemplate(template, 'theoplayer-time-range');
Expand Down
12 changes: 12 additions & 0 deletions src/util/CommonUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,3 +231,15 @@ export function getActiveElement(): Element | null {
}
return activeElement;
}

export function upgradeCustomElementIfNeeded(element: Element): Promise<unknown> | undefined {
const elementName = element.nodeName.toLowerCase();
if (elementName.indexOf('-') >= 0) {
if (customElements.get(elementName)) {
customElements.upgrade(element);
} else {
return customElements.whenDefined(elementName);
}
}
return undefined;
}

0 comments on commit b874fe3

Please sign in to comment.