Skip to content

Commit

Permalink
Remove fallback for browsers not supporting ResizeObserver
Browse files Browse the repository at this point in the history
  • Loading branch information
acelaya committed Jan 20, 2025
1 parent dc00cad commit f2f720d
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 124 deletions.
53 changes: 5 additions & 48 deletions src/sidebar/util/observe-element-size.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { ListenerCollection } from '@hypothesis/frontend-shared';

/**
* Watch for changes in the size (`clientWidth` and `clientHeight`) of
* an element.
Expand All @@ -15,50 +13,9 @@ export function observeElementSize(
element: Element,
onSizeChanged: (width: number, height: number) => void,
): () => void {
if (typeof ResizeObserver !== 'undefined') {
const observer = new ResizeObserver(() =>
onSizeChanged(element.clientWidth, element.clientHeight),
);
observer.observe(element);
return () => observer.disconnect();
}
const listeners = new ListenerCollection();

// Fallback method which listens for the most common events that result in
// element size changes:
//
// - Window size change
// - Media loading and adjusting size to content
// - DOM changes
//
// This is not comprehensive but it is simple to implement and good-enough for
// our current use cases.

let prevWidth = element.clientWidth;
let prevHeight = element.clientHeight;

const check = () => {
if (
prevWidth !== element.clientWidth ||
prevHeight !== element.clientHeight
) {
prevWidth = element.clientWidth;
prevHeight = element.clientHeight;
onSizeChanged(prevWidth, prevHeight);
}
};

listeners.add(element, 'load', check);
listeners.add(window, 'resize', check);
const observer = new MutationObserver(check);
observer.observe(element, {
characterData: true,
childList: true,
subtree: true,
});

return () => {
listeners.removeAll();
observer.disconnect();
};
const observer = new ResizeObserver(() =>
onSizeChanged(element.clientWidth, element.clientHeight),
);
observer.observe(element);
return () => observer.disconnect();
}
87 changes: 11 additions & 76 deletions src/sidebar/util/test/observe-element-size-test.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,6 @@
import { observeElementSize } from '../observe-element-size';
import { waitFor } from '@hypothesis/frontend-testing';

/**
* Wait for a condition to become true.
*
* @param {() => boolean} callback
*/
function waitFor(callback) {
return new Promise(resolve => {
const timer = setInterval(() => {
if (callback()) {
clearInterval(timer);
resolve();
}
}, 0);
});
}
import { observeElementSize } from '../observe-element-size';

/**
* Give MutationObserver, ResizeObserver etc. a chance to deliver their
Expand Down Expand Up @@ -48,68 +34,17 @@ describe('observeElementSize', () => {
stopObserving = observeElementSize(content, sizeChanged);
}

context('when `ResizeObserver` is available', function () {
if (typeof ResizeObserver === 'undefined') {
this.skip();
}

it('notifies when the element size changes', async () => {
startObserving();
it('notifies when the element size changes', async () => {
startObserving();

content.innerHTML = '<p>different content</p>';
await waitFor(() => sizeChanged.called);
content.innerHTML = '<p>different content</p>';
await waitFor(() => sizeChanged.called);

stopObserving();
sizeChanged.reset();

content.innerHTML = '<p>other content</p>';
await waitForObservations();
assert.notCalled(sizeChanged);
});
});

context('when `ResizeObserver` is not available', () => {
let origResizeObserver;
beforeEach(() => {
origResizeObserver = window.ResizeObserver;
window.ResizeObserver = undefined;
});

afterEach(() => {
window.ResizeObserver = origResizeObserver;
});

[
{
description: 'media loads inside the element',
triggerCheck: () =>
content.dispatchEvent(new Event('load', { bubbles: true })),
},
{
description: 'the window is resized',
triggerCheck: () => window.dispatchEvent(new Event('resize')),
},
{
description: "the element's DOM structure changes",
triggerCheck: () => (content.innerHTML += '<p>more content</p>'),
},
].forEach(({ description, triggerCheck }) => {
it(`checks for changes when ${description}`, async () => {
startObserving();

// Change the content height, which is not directly observed.
content.style.minHeight = '500px';
triggerCheck();
await waitFor(() => sizeChanged.called);

sizeChanged.reset();
stopObserving();
stopObserving();
sizeChanged.reset();

content.style.minHeight = '200px';
triggerCheck();
await waitForObservations();
assert.notCalled(sizeChanged);
});
});
content.innerHTML = '<p>other content</p>';
await waitForObservations();
assert.notCalled(sizeChanged);
});
});

0 comments on commit f2f720d

Please sign in to comment.