Skip to content

Commit

Permalink
Merge pull request #528 from ipfs-shipyard/fix/linkify-tree-check
Browse files Browse the repository at this point in the history
Linkify fix to run safety checks on entire parent tree

## Background

Linkify is an opt-in experiment on _Preferences_ screen:
https://ipfs.io/ipfs/QmY1D42peN9oPCoEeFezKR2jWKReDnJek52zcj7pcXXaaH

## In This PR

A lot of web-based text editors create elaborate DOM trees and together with @lgierth  we've experienced it first hand that  it is not enough to check if parent is safe for linkification. 

This change walks back over entire parent tree to ensure none of parents
has a no-go flag for linkification (eg. HTMLElement.contentEditable property)

Test pages:
- https://ipfs.io/ipfs/bafybeidvtwx54qr44kidymvhfzefzxhgkieigwth6oswk75zhlzjdmunoy/linkify-demo.html
- https://hackmd.io/kMlFFc_bQoiabAul5RjYag?both#
  - Left pane (editor) will be ignored after this PR is merged. Right now, if multiple people edit the same line, content gets destroyed.
  • Loading branch information
lidel authored Jul 16, 2018
2 parents 76a7bd5 + a5b047d commit ed4c189
Showing 1 changed file with 21 additions and 9 deletions.
30 changes: 21 additions & 9 deletions add-on/src/contentScripts/linkifyDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,16 +139,28 @@ const PQueue = require('p-queue')
return window.ipfsCompanionLinkifyValidationCache.get(path)
}

async function linkifyTextNode (node) {
const parent = node.parentNode
function isParentTreeSafe (node) {
let parent = node.parentNode
// Skip if no longer in visible DOM
if (!parent) return
// Skip already linkified nodes
if (parent.className && parent.className.match(/\blinkifiedIpfsAddress\b/)) return
// Skip styled <pre> -- often highlighted by script.
if (parent.tagName === 'PRE' && parent.className) return
// Skip forms, textareas
if (parent.isContentEditable) return
if (!parent) return false
// Walk back over parent tree and check each of them
while (parent) {
// Skip forms, textareas
if (parent.isContentEditable) return false
// Skip already linkified nodes
if (parent.className && parent.className.match(/\blinkifiedIpfsAddress\b/)) return false
// Skip styled <pre> -- often highlighted by scripts
if (parent.tagName === 'PRE' && parent.className) return false
// Skip if no longer in visible DOM
if (!(parent instanceof HTMLDocument) && !parent.parentNode) return false
parent = parent.parentNode
}
return true
}

async function linkifyTextNode (node) {
// Skip if node belongs to a parent from unsafe tree
if (!isParentTreeSafe(node)) return

let link
let match
Expand Down

0 comments on commit ed4c189

Please sign in to comment.