-
Notifications
You must be signed in to change notification settings - Fork 277
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
Issue #139 - Convert ENS Address To Link functionality #140
Changes from 4 commits
a699c31
55e3fef
b5b1b87
2d758d3
ff98107
70904f6
311f014
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
.idea/ | ||
*.iml |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,14 +18,17 @@ class EtherAddressLookup { | |
this.intSettingsTotalCount = 2; | ||
} | ||
|
||
//Gets extension settings and then converts addresses to links | ||
/** | ||
* @name init | ||
* @desc Gets extension settings and applies DOM manipulation | ||
*/ | ||
init() | ||
{ | ||
let objBrowser = chrome ? chrome : browser; | ||
//Get the highlight option for the user | ||
objBrowser.runtime.sendMessage({func: "highlight_option"}, function(objResponse) { | ||
if(objResponse && objResponse.hasOwnProperty("resp")) { | ||
this.blHighlight = (objResponse.resp == 1 ? true : false); | ||
this.blHighlight = (objResponse.resp == 1); | ||
} | ||
++this.intSettingsCount; | ||
}.bind(this)); | ||
|
@@ -38,49 +41,205 @@ class EtherAddressLookup { | |
|
||
//Update the DOM once all settings have been received... | ||
setTimeout(function() { | ||
if(true || this.intSettingsCount === this.intSettingsTotalCount) { | ||
if(this.blBlacklistDomains) { | ||
this.blacklistedDomainCheck(); | ||
} | ||
this.convertAddressToLink(); | ||
// Needs to happen after user settings have been collected | ||
// and in the context of init(); | ||
this.setSearchAndReplaceSettings(); | ||
this.setWarningSettings(); | ||
this.manipulateDOM(); | ||
}.bind(this), 10); | ||
} | ||
|
||
/** | ||
* @name Set Search And Replace Settings | ||
* @desc | ||
*/ | ||
setSearchAndReplaceSettings() | ||
{ | ||
// Check user is on their favourite block explorer, on fail target blank. | ||
this.target = (this.isBlockchainExplorerSite() ? '_self' : '_blank'); | ||
|
||
// Register RegEx Patterns | ||
this.regExPatterns = [ | ||
// Ethereum Address Regex | ||
/(^|\s|:|-)((?:0x)[0-9a-fA-F]{40})(\s|$)/gi, | ||
|
||
// ENS Address Regex | ||
/([a-z0-9][a-z0-9-\.]+[a-z0-9](?:\.eth))(\s|$)/gi | ||
]; | ||
|
||
// Register RegEx Matching Patterns | ||
this.matchPatterns = [ | ||
// Ethereum Match Pattern | ||
/((?:0x)[0-9a-fA-F]{40})/gi, | ||
|
||
// ENS Match Pattern | ||
this.regExPatterns[1] | ||
]; | ||
|
||
// Register Replace Patterns | ||
this.replacePatterns = [ | ||
// Ethereum Address Replace | ||
'$1<a title="See this address on the blockchain explorer" ' + | ||
'href="' + this.strBlockchainExplorer + '/$2" ' + | ||
'class="ext-etheraddresslookup-link" ' + | ||
'target="'+ this.target +'">$2</a>$3', | ||
|
||
// ENS Address Replace | ||
'<a title="See this address on the blockchain explorer" ' + | ||
'href="' + this.strBlockchainExplorer + '/$1" ' + | ||
'class="ext-etheraddresslookup-link" ' + | ||
'target="'+ this.target +'">$1</a>$2' | ||
]; | ||
} | ||
|
||
/** | ||
* @name Set Warning Settings | ||
* @desc | ||
*/ | ||
setWarningSettings() | ||
{ | ||
// The block explorers that can handle ENS addresses | ||
this.ENSCompatiableExplorers = [ | ||
"https://etherscan.io/address", | ||
"https://etherchain.org/account" | ||
]; | ||
|
||
// Does the user's favorite explorer support an ENS address | ||
for(var i=0; i<this.ENSCompatiableExplorers.length; i++){ | ||
if(this.strBlockchainExplorer == this.ENSCompatiableExplorers[i]){ | ||
this.ENSCompatiable = true; | ||
break; | ||
} | ||
}.bind(this), 10) | ||
this.ENSCompatiable = false; | ||
} | ||
|
||
// On failure give the user a warning. | ||
if(!this.ENSCompatiable){ | ||
this.replacePatterns[1] = '<a title="Notification! We have spotted an ENS address, your current block explorer can\'t parse this address. Please choose a compatible block explorer." ' + | ||
'class="ext-etheraddresslookup-link ext-etheraddresslookup-warning" href="#">$1</a>'; | ||
} | ||
} | ||
|
||
//Finds Ethereum addresses and converts to a link to a block explorer | ||
convertAddressToLink() | ||
manipulateDOM() | ||
{ | ||
//Put the blockchain explorer into a so we can parse it. | ||
var objBlockchainExplorer = document.createElement("a"); | ||
objBlockchainExplorer.href = this.strBlockchainExplorer; | ||
if(true || this.intSettingsCount === this.intSettingsTotalCount) { | ||
if(this.blBlacklistDomains) { | ||
this.blacklistedDomainCheck(); | ||
} | ||
this.convertAddressToLink(); | ||
} | ||
} | ||
|
||
var arrWhitelistedTags = new Array("code", "span", "p", "td", "li", "em", "i", "b", "strong", "small"); | ||
var strRegex = /(^|\s|:|-)((?:0x)[0-9a-fA-F]{40})(?:\s|$)/gi; | ||
/** | ||
* @name Convert Address To Link | ||
* @desc Finds Ethereum addresses and converts to a link to a block explorer | ||
*/ | ||
convertAddressToLink() | ||
{ | ||
var arrWhitelistedTags = ["code", "span", "p", "td", "li", "em", "i", "b", "strong", "small"]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've also refactored the array instantiation, let me know if this is a problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's all good :) |
||
|
||
//Get the whitelisted nodes | ||
for(var i=0; i<arrWhitelistedTags.length; i++) { | ||
var objNodes = document.getElementsByTagName(arrWhitelistedTags[i]); | ||
//Loop through the whitelisted content | ||
for(var x=0; x<objNodes.length; x++) { | ||
var strContent = objNodes[x].innerHTML; | ||
if( /((?:0x)[0-9a-fA-F]{40})/gi.exec(strContent) !== null) { | ||
//If we are on our favourite blockchain explorer, don't target blank. | ||
objNodes[x].innerHTML = strContent.replace( | ||
new RegExp(strRegex, "gi"), | ||
'$1<a title="See this address on the blockchain explorer" ' + | ||
'href="' + this.strBlockchainExplorer + '/$2" ' + | ||
'class="ext-etheraddresslookup-link" ' + | ||
'target="'+ (objBlockchainExplorer.hostname === window.location.hostname ? '_self' : '_blank') +'">$2</a>' | ||
); | ||
} | ||
this.convertAddresses(objNodes[x]); | ||
} | ||
} | ||
|
||
this.tidyUpSlots(); | ||
|
||
if(this.blHighlight) { | ||
this.addHighlightStyle(); | ||
} | ||
} | ||
|
||
/** | ||
* @name Convert Addresses | ||
* @desc Takes a Node and checks if any of its children are textNodes. On success replace textNode with slot node | ||
* @desc slot node contains regex replaced content; see generateReplacementContent() | ||
* @param {Node} objNode | ||
*/ | ||
convertAddresses(objNode) | ||
{ | ||
// Some nodes have non-textNode children | ||
// we need to ensure regex is applied only to text otherwise we will mess the html up | ||
for(var i=0; i < objNode.childNodes.length; i++){ | ||
// Only check textNodes to prevent applying RegEx against element attributes | ||
if(objNode.childNodes[i].nodeType == 3){ // nodeType 3 = a text node | ||
|
||
var child = objNode.childNodes[i]; | ||
var childContent = child.textContent; | ||
|
||
// Only start replacing stuff if the we get a RegEx match. | ||
if(this.isPatternMatched(childContent)) { | ||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot | ||
var replacement = document.createElement('slot'); | ||
replacement.setAttribute('class', 'ext-etheraddresslookup-temporary'); | ||
replacement.innerHTML = this.generateReplacementContent(childContent); | ||
objNode.replaceChild(replacement, child); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @name Generate Replacement Content | ||
* @desc Takes string and replaces any regex pattern matches with the associated replace patterns | ||
* @param {string} content | ||
* @returns {string} | ||
*/ | ||
generateReplacementContent(content) | ||
{ | ||
for(var i=0; i < this.regExPatterns.length; i++){ | ||
content = content.replace(this.regExPatterns[i], this.replacePatterns[i]); | ||
} | ||
return content; | ||
} | ||
|
||
/** | ||
* @name Is Pattern Matched | ||
* @desc Checks content matches any of the object's matchPatterns | ||
* @param {string} content | ||
* @returns {boolean} | ||
*/ | ||
isPatternMatched(content) | ||
{ | ||
for(var i=0; i < this.matchPatterns.length; i++){ | ||
if(this.matchPatterns[i].exec(content) !== null){ | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* @name Is Blockchain Explorer Site | ||
* @desc Check if the current website is the user's selected block explorer | ||
* @returns {boolean} | ||
*/ | ||
isBlockchainExplorerSite() | ||
{ | ||
var objBlockchainExplorer = document.createElement("a"); | ||
objBlockchainExplorer.href = this.strBlockchainExplorer; | ||
return (objBlockchainExplorer.hostname === window.location.hostname); | ||
} | ||
|
||
/** | ||
* @name Tidy Slots | ||
* @desc Searches document for slots adds the slot's child nodes to its parent then removes the slot | ||
*/ | ||
tidyUpSlots() | ||
{ | ||
var slots = document.querySelectorAll("slot.ext-etheraddresslookup-temporary"); | ||
for(var i=0; i < slots.length; i++){ | ||
while(slots[i].childNodes.length > 0){ | ||
slots[i].parentNode.appendChild(slots[i].firstChild); | ||
} | ||
slots[i].parentNode.removeChild(slots[i]); | ||
} | ||
} | ||
|
||
//Removes the highlight style from Ethereum addresses | ||
removeHighlightStyle() | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,11 +42,14 @@ <h3 class="text-center">EtherAddressLookup</h3> | |
<label>Preferred Blockchain Explorer</label> | ||
<select class="form-control" name="ext-etheraddresslookup-choose_blockchain" | ||
id="ext-etheraddresslookup-choose_blockchain"> | ||
<option value="https://etherscan.io/address">Etherscan.io</option> | ||
<option value="https://etherchain.org/account">Etherchain.org</option> | ||
<option value="https://etherscan.io/address">Etherscan.io *</option> | ||
<option value="https://etherchain.org/account">Etherchain.org *</option> | ||
<option value="https://ethplorer.io/address">Ethplorer.io</option> | ||
<option value="http://ethergraphs.com/dashboard">Ethergraphs.com</option> | ||
</select> | ||
<div> | ||
<p>* ENS address compatible.</p> | ||
</div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made this amendment to allow the user to know which explorers will allow them the ability view ENS addresses. We can in future add new functionality to lookup the underlying Ethereum address then link to this on the user's chosen explorer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make this text smaller please? Or do you have an idea on how to present notes/not-main-labels on the UI? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll make this smaller for now, we can discuss ideas later, though UI isn't really my strong suit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Once v1.9 is up, we can arrange a more in-depth discussion on it for later this week when both our schedules are free. |
||
|
||
<br/><br/> | ||
<div id="footer"> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed this because it is basically the thing:
(objResponse.resp == 1 ? true : false)
==(objResponse.resp == 1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha, nice spot! 👍