Skip to content

Instantly share code, notes, and snippets.

@dummerbd
Created July 8, 2019 13:54
Show Gist options
  • Save dummerbd/078620b27a80c16c8e8f4496f816e709 to your computer and use it in GitHub Desktop.
Save dummerbd/078620b27a80c16c8e8f4496f816e709 to your computer and use it in GitHub Desktop.
import React from "react";
import { parse } from "url";
import PropTypes from "prop-types";
import Router from "next/router";
export default class LegacyPageWrapper extends React.Component {
static propTypes = {
backendHost: PropTypes.string,
pageContents: PropTypes.string,
allowFollowingLinkToLocation: PropTypes.func,
loadLegacyModules: PropTypes.func,
onNavigate: PropTypes.func
};
static defaultProps = {
backendHost: "https://api.nomadhealth.com",
allowFollowingLinkToLocation: () => true,
loadLegacyModules: () => {},
onNavigate: location => {
Router.push(String(location));
}
};
static async getInitialProps({ asPath }) {
const response = await fetch(this.props.backendHost + asPath);
const pageContents = await response.text();
return { pageContents };
}
pageRef = React.createRef();
shouldComponentUpdate() {
return false;
}
componentDidMount() {
if (this.pageRef.current && typeof window.addEventListener === "function") {
addEventListener("click", this.clickCaptured, true);
this.props.loadLegacyModules(this.pageRef.current);
}
}
componentWillUnmount() {
if (typeof window.removeEventListener === "function") {
removeEventListener("click", this.clickCaptured, true);
removeEventListener("click", this.clickBubbled, false);
}
}
clickCaptured = () => {
removeEventListener("click", this.clickBubbled, false);
addEventListener("click", this.clickBubbled, false);
};
clickBubbled = event => {
if (this.clickEventIsSignificant(event)) {
const link = this.getVisitableLinkForTarget(event.target);
if (link) {
const location = this.getVisitableLocationForLink(link);
if (
location &&
this.props.allowFollowingLinkToLocation(link, location)
) {
event.preventDefault();
this.props.onNavigate(location);
}
}
}
};
clickEventIsSignificant(event) {
return !(
(event.target && event.target.isContentEditable) ||
event.defaultPrevented ||
event.which > 1 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
);
}
getVisitableLinkForTarget(target) {
if (target instanceof Element) {
return closest(target, "a[href]:not([target]):not([download])");
}
}
getVisitableLocationForLink(link) {
const location = new Location(link.getAttribute("href") || "");
if (location.isLocal()) {
return location;
}
}
render() {
return (
<div
ref={this.pageRef}
dangerouslySetInnerHTML={{ __html: this.props.pageContents }}
/>
);
}
}
export class Location {
constructor(href) {
this.href = href;
this.url = parse(href, false, true);
}
static getOrigin() {
const { protocol, hostname, port } = window.location;
return `${protocol}//${hostname}${port ? ":" + port : ""}`;
}
isLocal() {
const origin = parse(Location.getOrigin(), false, true);
return (
!this.url.host ||
(this.url.protocol === origin.protocol && this.url.host === origin.host)
);
}
}
export const closest = (() => {
const html = document.documentElement;
const match =
html.matches ||
html.webkitMatchesSelector ||
html.msMatchesSelector ||
html.mozMatchesSelector;
const closest =
html.closest ||
function(selector) {
let element = this;
while (element) {
if (match.call(element, selector)) {
return element;
} else {
element = element.parentElement;
}
}
};
return function(element, selector) {
return closest.call(element, selector);
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment