Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor content panels into an iframe #840

Merged
merged 111 commits into from
Sep 2, 2022
Merged

Refactor content panels into an iframe #840

merged 111 commits into from
Sep 2, 2022

Conversation

codemist
Copy link
Collaborator

@codemist codemist commented May 13, 2022

This PR refactors the content panels into an iframe, instead of injecting it directly into the DOM.

Preview:
image

image

UI is updated to reflect new Firefox prompt designs.

Post-review To-Dos:

  • Add checkbox 'do not show again' + escape key functionality
  • Change innerHTML to textContent
  • UI Redesign to follow Firefox popup design specs
  • Update cross-origin communication logic

Remaining To-Dos:

  • Position iframe window according to FBC icon position
  • Localize strings
  • Make iframe position responsive to screen resize/scroll
  • Close popup when selecting outside iframe window and when cancel + dismiss is selected
  • Add Facebook authentication backlink to Allow button
  • Add left/right chevron to iframe window
  • Restore allowClickSwitch boolean to login switch case
  • Mobile orientation

Testing

Case 1 (Login popup)

  1. Go to Imgur sign in page
  2. Select the FBC Icon and check that the prompt opens
  3. Close the popup by clicking Dismiss or selecting outside of the iframe window
  4. Open the popup again and select the Allow CTA
  5. Check that window is redirected to a Facebook authentication page

Case 2 (Login + Email popup) Note: Popups should contain different content

  1. Go to Etsy sign in page
  2. Select the FBC icon at the top over the email input field and check that the prompt opens + contains a checkbox and a Try Firefox Relay CTA
  3. Close the popup by clicking Dismiss or selecting outside of the iframe window
  4. Select FBC icon at the bottom over the disabled Continue with Facebook button and check that the prompt opens + contains an Allow CTA
  5. Close the popup by clicking Dismiss or selecting outside of the iframe window

@codemist codemist added the WIP Work in progress label May 13, 2022
@codemist codemist marked this pull request as draft May 13, 2022 17:34
@codemist codemist changed the title Refactor content panel to iframe ⚠️ Refactor content panel to iframe ⚠️ May 13, 2022
Comment on lines 77 to 79
window.addEventListener("message", (e) => {
if (e.data === "closeTheInjectedIframe") {
closeIframe();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue I had was figuring out how to enable cross-origin communication between the iframe embedded site and the parent page. I thought this was impossible according to my research until I found the Window.postMessage() method! Super neat and useful to know for add on development.

@codemist codemist marked this pull request as ready for review May 26, 2022 19:37
src/content_script.js Outdated Show resolved Hide resolved
window.addEventListener("message", (e) => {
if (
e.data === "allowTriggered"
&& iframeSrcVal.includes(e.origin)
Copy link
Collaborator Author

@codemist codemist Aug 31, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the postMessage method since specified the origin is the iframe's src value. I did more reading up on it on MDN and I saw this:

If you do expect to receive messages from other sites, always verify the sender's identity using the origin and possibly source properties.

Copy link
Member

@groovecoder groovecoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spot-checks look good. Most non-blocking comments but a couple things we should at least discuss & decide before merging, I think.

src/content_script.js Outdated Show resolved Hide resolved
src/content_script.js Outdated Show resolved Hide resolved
src/content_script.js Outdated Show resolved Hide resolved
button.appendChild(document.createTextNode( browser.i18n.getMessage(buttonString) ));
htmlBadgeFragmentPromptButtonDiv.appendChild(button);
// Mobile Orientation
else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (non-blocking): whenever possible I like to refactor if () { ... } else { ... } code into if () { func(); return;} func2(); So here it would be something like:

const OFFSET_X = 20;
const OFFSET_Y = 55;

function desktopOrientation(iframeBox, iframeChevron, fencePos, fencePosition, iframePaddingAllowance) {
  // Desktop Values
  const xLeft = fencePosition.x - iframePaddingAllowance;
  const xRight = fencePosition.x + OFFSET_X + fencePos.offsetWidth;
  const yPos = fencePosition.y - OFFSET_Y;

  // Position iframe relative to FBC Icon
  iframeBox.style.marginLeft = `${xRight}px`;
  iframeBox.style.marginTop = `${yPos}px`;

  // Add Chevron (Default left arrow)
  const xPosChevron = xRight - iframeChevron.offsetWidth;
  const yPosChevron = yPos + OFFSET_Y;

  iframeChevron.style.marginLeft = `${xPosChevron}px`;
  iframeChevron.style.marginTop = `${yPosChevron}px`;

  const calculateOffsetDiff = window.innerWidth - fencePosition.x;

  iframeChevron.classList.remove("fbc-chevron-arrow-top");

  // Flip the iframe to show on the left side when icon is too close to the edge
  if (iframePaddingAllowance > calculateOffsetDiff) {
    iframeBox.style.marginLeft = `${xLeft}px`;
    iframeChevron.classList.add("fbc-chevron-arrow-right");
    iframeChevron.style.marginLeft = `${xPosChevron - fencePos.offsetWidth - iframeChevron.offsetWidth - OFFSET_X}px`;
    return;
  }
  iframeChevron.classList.remove("fbc-chevron-arrow-right");
}

function mobileOrientation(iframeElement, iframeChevron, iframeBox, fencePosition){
  // Mobile Values
  const xPosMobile = fencePosition.x;
  const yPosMobile = fencePosition.y + OFFSET_Y;
  for (const panels of iframeElement) {
    panels.width = window.innerWidth;
    if (window.innerWidth > 480) {
      panels.width = 350;
    }
  }

  iframeChevron.classList.add("fbc-chevron-arrow-top");
  iframeBox.style.marginTop = `${yPosMobile}px`;

  const xPosChevronMobile = xPosMobile;
  const yPosChevronMobile = yPosMobile - iframeChevron.offsetWidth;

  iframeChevron.style.marginLeft = `${xPosChevronMobile}px`;
  iframeChevron.style.marginTop = `${yPosChevronMobile}px`;
}

function positionIframe(fencePos) {
  const fencePosition = fencePos.getBoundingClientRect();
  const iframeBox = document.querySelector(".fbc-content-box");
  const iframeWrapper = document.querySelector(".fbc-wrapper");
  const iframeElement = iframeWrapper.getElementsByTagName("iframe");
  const iframeChevron = document.querySelector(".fbc-iframe-chevron");

  const iframePaddingAllowance = iframeBox.offsetWidth + OFFSET_X;

  const iconRightAllowance = window.innerWidth - fencePosition.x + fencePos.offsetWidth;
  const iconLeftAllowance = window.innerWidth - iconRightAllowance;

  if (iconRightAllowance > iframePaddingAllowance || iconLeftAllowance > iframePaddingAllowance) {
    desktopOrientation(iframeBox, iframeChevron, fencePos, fencePosition, iframePaddingAllowance);
  }
  mobileOrientation(iframeElement, iframeChevron, iframeBox, fencePosition);
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function positionIframe(fencePos) {
  const fencePosition = fencePos.getBoundingClientRect();
  const iframeBox = document.querySelector(".fbc-content-box");
  const iframeWrapper = document.querySelector(".fbc-wrapper");
  const iframeElement = iframeWrapper.getElementsByTagName("iframe");
  const iframeChevron = document.querySelector(".fbc-iframe-chevron");

  const offsetX = 20;
  const offsetY = 55;

  const iframePaddingAllowance = iframeBox.offsetWidth + offsetX;

  const iconRightAllowance = window.innerWidth - fencePosition.x + fencePos.offsetWidth;
  const iconLeftAllowance = window.innerWidth - iconRightAllowance;

  if (iconRightAllowance > iframePaddingAllowance || iconLeftAllowance > iframePaddingAllowance) {
    return desktopOrientation(iframeBox, iframeChevron, offsetY, fencePosition, iframePaddingAllowance, fencePos, offsetX);
  }
  return mobileOrientation(iframeElement, iframeChevron, iframeBox, fencePosition, offsetY);
}

function mobileOrientation(iframeElement, iframeChevron, iframeBox, fencePosition, offsetY){
  // Mobile Values
  const xPosMobile = fencePosition.x;
  const yPosMobile = fencePosition.y + offsetY;

  for (const panels of iframeElement) {
    panels.width = window.innerWidth;
    if (window.innerWidth > 480) {
      panels.width = 350;
    }
  }

  iframeChevron.classList.add("fbc-chevron-arrow-top");
  iframeBox.style.marginTop = `${yPosMobile}px`;

  const xPosChevronMobile = xPosMobile;
  const yPosChevronMobile = yPosMobile - iframeChevron.offsetWidth;

  iframeChevron.style.marginLeft = `${xPosChevronMobile}px`;
  iframeChevron.style.marginTop = `${yPosChevronMobile}px`;

}

function desktopOrientation(iframeBox, iframeChevron, offsetY, fencePosition, iframePaddingAllowance, fencePos, offsetX) {
  // Desktop Values
  const xRight = fencePosition.x + offsetX + fencePos.offsetWidth;
  const xLeft = fencePosition.x - iframePaddingAllowance;
  const yPos = fencePosition.y - offsetY;

  // Position iframe relative to FBC Icon
  iframeBox.style.marginLeft = `${xRight}px`;
  iframeBox.style.marginTop = `${yPos}px`;

  // Add Chevron (Default left arrow)
  const xPosChevron = xRight - iframeChevron.offsetWidth;
  const yPosChevron = yPos + offsetY;

  iframeChevron.style.marginLeft = `${xPosChevron}px`;
  iframeChevron.style.marginTop = `${yPosChevron}px`;

  const calculateOffsetDiff = window.innerWidth - fencePosition.x;

  // Flip the iframe to show on the left side when icon is too close to the edge
  if (iframePaddingAllowance > calculateOffsetDiff) {
    iframeBox.style.marginLeft = `${xLeft}px`;
    iframeChevron.classList.add("fbc-chevron-arrow-right");
    iframeChevron.style.marginLeft = `${xPosChevron - fencePos.offsetWidth - iframeChevron.offsetWidth - offsetX}px`;
  }
  else {
    iframeChevron.classList.remove("fbc-chevron-arrow-right");
  }
  iframeChevron.classList.remove("fbc-chevron-arrow-top");
}

I refactored it again. How is this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. There's one more else {} in desktopOrientation there that could be turned into this?

  // Flip the iframe to show on the left side when icon is too close to the edge
  iframeChevron.classList.remove("fbc-chevron-arrow-top");
  if (iframePaddingAllowance > calculateOffsetDiff) {
    iframeBox.style.marginLeft = `${xLeft}px`;
    iframeChevron.classList.add("fbc-chevron-arrow-right");
    iframeChevron.style.marginLeft = `${xPosChevron - fencePos.offsetWidth - iframeChevron.offsetWidth - offsetX}px`;
    return;
  }
  iframeChevron.classList.remove("fbc-chevron-arrow-right");

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

src/content_script.js Outdated Show resolved Hide resolved
src/content_script.js Outdated Show resolved Hide resolved
src/content_script.js Outdated Show resolved Hide resolved
src/content_script.js Outdated Show resolved Hide resolved
src/inpage-content.js Outdated Show resolved Hide resolved
src/inpage-content.js Outdated Show resolved Hide resolved
@groovecoder
Copy link
Member

Code LGTM. Lemme spot-check real quick though ...

@groovecoder groovecoder merged commit c8c92e2 into main Sep 2, 2022
@groovecoder groovecoder deleted the iframe branch September 2, 2022 18:26
@multun
Copy link

multun commented Sep 8, 2022

@groovecoder this change caused #863, can it be reverted until things are sorted out?

@Vinnl
Copy link

Vinnl commented Sep 8, 2022

@multun (and @zelch @alecvn who 👍'd it): it's been reverted, you can check for updates for the extension to fix the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
WIP Work in progress
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants