Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/app/social/social.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export class SocialService {
* Import the AddToAny JavaScript
*/
initializeAddToAnyScript(): any {
if (!this.enabled) {
return;
}
// Initializing the addToAny script
const script = this._document.createElement('script');
script.type = 'text/javascript';
Expand All @@ -96,10 +99,63 @@ export class SocialService {
} else {
this._document.head.appendChild(script);
clearInterval(bodyHeightInterval);
this.observeAddToAnyModal();
}
}, 200);
}

/**
* Observes DOM changes to detect when the AddToAny modal is opened or closed.
* Since AddToAny does not reliably expose lifecycle callbacks, a MutationObserver
* is used to monitor the presence and visibility of the modal element.
*
* When the modal is visible, background scrolling is disabled by setting
* `overflow: hidden` on the document body. When the modal is no longer visible,
* the original scrolling behavior is restored.
*/
private observeAddToAnyModal(): void {
if (!isPlatformBrowser(this.platformId)) {
return;
}

const body = this._document.body;
let isLocked = false;

const observer = new MutationObserver(() => {
const modal = this._document.querySelector('.a2a_full') as HTMLElement;
const isVisible = modal && this.isElementVisible(modal);

if (isVisible && !isLocked) {
body.style.overflow = 'hidden';
isLocked = true;
} else if (!isVisible && isLocked) {
body.style.overflow = '';
isLocked = false;
}
});

observer.observe(body, {
childList: true,
subtree: true,
attributes: true,
});
}

/**
* Determines whether a given HTML element is currently visible in the DOM.
* This is necessary because the AddToAny modal may remain in the DOM while hidden.
*
* @param element The element to check for visibility
* @returns true if the element is visible, false otherwise
*/
private isElementVisible(element: HTMLElement): boolean {
return !!(
element.offsetWidth ||
element.offsetHeight ||
element.getClientRects().length
);
}

/**
* Initialize the Social service. This method must be called only inside app component.
*/
Expand Down
16 changes: 13 additions & 3 deletions src/app/submission/submission.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,17 @@ describe('SubmissionService test suite', () => {

describe('redirectToEditItem', () => {
beforeEach(() => {
(itemService.findById as jasmine.Spy).calls.reset();
if ((itemService.findById as any).calls) {
(itemService.findById as jasmine.Spy).calls.reset();
} else {
spyOn(itemService as any, 'findById');
}

if ((requestServce.setStaleByHrefSubstring as any).calls) {
(requestServce.setStaleByHrefSubstring as jasmine.Spy).calls.reset();
} else {
spyOn(requestServce as any, 'setStaleByHrefSubstring');
}
});

it('should redirect to Item page', fakeAsync(() => {
Expand All @@ -1003,8 +1013,8 @@ describe('SubmissionService test suite', () => {
}),
});
let itemSubmissionId = itemUuid + ':FULL';
spyOn(itemService as any, 'findById').and.returnValue(cold('a', { a: createSuccessfulRemoteDataObject(mockItem) }));
spyOn(requestServce as any, 'setStaleByHrefSubstring').and.returnValue(cold('a', { a: true }));
(itemService.findById as jasmine.Spy).and.returnValue(cold('a', { a: createSuccessfulRemoteDataObject(mockItem) }));
(requestServce.setStaleByHrefSubstring as jasmine.Spy).and.returnValue(cold('a', { a: true }));

scheduler.schedule(() => service.invalidateCacheAndRedirectToItemPage(itemSubmissionId));
scheduler.flush();
Expand Down
Loading