Skip to content

Commit

Permalink
Merge pull request #140 from Samyoul/issue/139
Browse files Browse the repository at this point in the history
Issue #139 - Convert ENS Address To Link functionality
  • Loading branch information
409H committed Oct 30, 2017
2 parents bcf8ba5 + 311f014 commit 611b7e4
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.idea/
*.iml
5 changes: 5 additions & 0 deletions css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
color: inherit;
}

.ext-etheraddresslookup-warning {
color: red;
border-bottom: 1px dashed red;
}

#ext-etheraddresslookup-popup {
margin: 0;
padding: 0px;
Expand Down
211 changes: 185 additions & 26 deletions js/DomManipulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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>$2';
}
}

//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"];

//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.insertBefore(slots[i].firstChild, slots[i]);
}
slots[i].parentNode.removeChild(slots[i]);
}
}

//Removes the highlight style from Ethereum addresses
removeHighlightStyle()
{
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "EtherAddressLookup",
"short_name": "EtherAddressLookup",
"description": "Adds links to strings that look like Ethereum addresses to your favorite blockchain explorer.",
"version": "1.8.1",
"version": "1.9.0",

"browser_action": {
"default_icon": "images/icon.png",
Expand Down
7 changes: 5 additions & 2 deletions options.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
<small>* ENS address compatible.</small>
</div>

<br/><br/>
<div id="footer">
Expand Down

0 comments on commit 611b7e4

Please sign in to comment.