Skip to content

Commit

Permalink
Fix linkContentMatchHref issues (#21)
Browse files Browse the repository at this point in the history
* Fix an issue that a protocol-less url is linkified as a relative URL

When a user enters `www.example.com` and hits the space key, the text
should be linkified as `<a
href="http://www.example.com">www.example.com</a>`. However the text
was linkified as `<a href="www.example.com">www.example.com</a>`.

This doesn't happen in Squire, however `syncLinkHrefWithContent` didn't
seem to take into account the case when the text content doesn't have a
protocol part.

Here's another somewhat related case.

When a user enters `http://www.example.com` and hits the space key, the
text is linkified as `<a
href="http://www.example.com">www.example.com</a>` which is good. Then
they place a cursor after `http://` and delete `://`, the href should be
updated with `href="http://httpwww.example.com"`.

However the actual behavior was that the href was updated with
`href="httpwww.example.com"`.

An expected behavior in this case may be controvertible, but generating
a relative link doesn't seem to make sense.

#15

* fix: improve syncLinkHrefWithContent

* chore: add some comments

Co-authored-by: Satoshi Tanimoto <[email protected]>
  • Loading branch information
cvle and stanimoto authored May 11, 2021
1 parent 7f811a8 commit a78f7b8
Showing 1 changed file with 26 additions and 5 deletions.
31 changes: 26 additions & 5 deletions src/lib/syncLinkHrefWithContent.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,36 @@
const MAILTO_PROTOCOL = "mailto:";
const EMAIL_REGEXP = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i;
const PROTOCOL_REGEXP = /^([a-zA-Z]+:\/\/)/;

/**
* Enforces contents of links to match their href.
* @param element HTMLAnchorElement or HTMLElement potentially container anchor elements
*/
export default function syncLinkHrefWithContent(element: HTMLElement) {
export default function syncLinkHrefWithContent(element: HTMLElement): void {
if (element.tagName === "A") {
const anchorElement = element as HTMLAnchorElement;
const url = new URL(anchorElement.href);
const prefix = url.protocol === MAILTO_PROTOCOL ? MAILTO_PROTOCOL : "";
anchorElement.href = prefix + anchorElement.textContent;
try {
const content = anchorElement.textContent || "";
const isEmail = EMAIL_REGEXP.test(content);

// Handle mailto case.
if (isEmail) {
anchorElement.href = `mailto:${content}`;
return;
}

// Handle rest.
let urlContent = content;
if (!PROTOCOL_REGEXP.test(urlContent)) {
// Add default protocol if none was set.
urlContent = "http://" + content;
}

const url = new URL(urlContent);
anchorElement.href = url.toString();
} catch (e) {
// URL was invalid, use a `href` that does nothing.
anchorElement.href = "javascript:;";
}
return;
}
const anchorElements = element.getElementsByTagName("a");
Expand Down

0 comments on commit a78f7b8

Please sign in to comment.