From 21290d4e80711fb0de8dd101db8c6d1c5171a627 Mon Sep 17 00:00:00 2001
From: Michael de Wit <mjwwit@users.noreply.github.com>
Date: Wed, 12 Apr 2017 10:01:08 +0200
Subject: [PATCH] Optimize and fix autolink function (#1442) (#1444)

* Optimize and fix autolink function (#1442)

* Fix bug in autolink recursive fallback function
---
 public/js/libs/autolink.js | 60 ++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 15 deletions(-)

diff --git a/public/js/libs/autolink.js b/public/js/libs/autolink.js
index 3a9c0d4bcb..039cd7db24 100644
--- a/public/js/libs/autolink.js
+++ b/public/js/libs/autolink.js
@@ -1,15 +1,45 @@
-jQuery.fn.autolink = function() {
-	var re = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-]*)?\??(?:[\-\+:=&;%@\.\w]*)#?(?:[\.\!\/\\\w]*))?)/g;
-	return this.find('*').contents()
-		.filter(function () { return this.nodeType === 3; })
-		.each(function() {
-			$(this).each(function() {
-				if (re.test($(this).text()))
-					$(this).replaceWith(
-						$("<span />").html(
-							this.nodeValue.replace(re, "<a href='$1'>$1</a>")
-						)
-					);
-			});
-		});
-};
\ No newline at end of file
+(function () {
+    var re = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-]*)?\??(?:[\-\+:=&;%@\.\w]*)#?(?:[\.\!\/\\\w]*))?)/g;
+    function textNodesUnder(node) {
+        var textNodes = [];
+        if(typeof document.createTreeWalker === 'function') {
+            // Efficient TreeWalker
+            var currentNode, walker;
+            walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
+            while(currentNode = walker.nextNode()) {
+                textNodes.push(currentNode);
+            }
+        } else {
+            // Less efficient recursive function
+            for(node = node.firstChild; node; node = node.nextSibling) {
+                if(node.nodeType === 3) {
+                    textNodes.push(node);
+                } else {
+                    textNodes = textNodes.concat(textNodesUnder(node));
+                }
+            }
+        }
+        return textNodes;
+    }
+
+    function processNode(node) {
+        re.lastIndex = 0;
+        var results = re.exec(node.textContent);
+        if(results !== null) {
+            if($(node).parents().filter('pre>code').length === 0) {
+                $(node).replaceWith(
+                    $('<span />').html(
+                        node.nodeValue.replace(re, '<a href="$1">$1</a>')
+                    )
+                );
+            }
+        }
+    }
+
+    jQuery.fn.autolink = function () {
+        this.each(function () {
+            textNodesUnder(this).forEach(processNode);
+        });
+        return this;
+    };
+})();