Fix URL matching RegEx

pull/114/head
Wes Cossick 9 years ago
parent 263827a690
commit 589386dc8a

@ -3,126 +3,123 @@
(function(mod) { (function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay")); mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay"));
else if (typeof define == "function" && define.amd) // AMD else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod); define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod);
else // Plain browser env else // Plain browser env
mod(CodeMirror); mod(CodeMirror);
})(function(CodeMirror) { })(function(CodeMirror) {
"use strict"; "use strict";
var urlRE = /^((?:coap|doi|javascript|aaa|aaas|about|acap|cap|cid|crid|data|dav|dict|dns|file|ftp|geo|go|gopher|h323|http|https|iax|icap|im|imap|info|ipp|iris|iris\.beep|iris\.xpc|iris\.xpcs|iris\.lwz|ldap|mailto|mid|msrp|msrps|mtqp|mupdate|news|nfs|ni|nih|nntp|opaquelocktoken|pop|pres|rtsp|service|session|shttp|sieve|sip|sips|sms|snmp|soap\.beep|soap\.beeps|tag|tel|telnet|tftp|thismessage|tn3270|tip|tv|urn|vemmi|ws|wss|xcon|xcon-userid|xmlrpc\.beep|xmlrpc\.beeps|xmpp|z39\.50r|z39\.50s|adiumxtra|afp|afs|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|chrome|chrome-extension|com-eventbrite-attendee|content|cvs|dlna-playsingle|dlna-playcontainer|dtn|dvb|ed2k|facetime|feed|finger|fish|gg|git|gizmoproject|gtalk|hcp|icon|ipn|irc|irc6|ircs|itms|jar|jms|keyparc|lastfm|ldaps|magnet|maps|market|message|mms|ms-help|msnim|mumble|mvn|notes|oid|palm|paparazzi|platform|proxy|psyc|query|res|resource|rmi|rsync|rtmp|secondlife|sftp|sgn|skype|smb|soldat|spotify|ssh|steam|svn|teamspeak|things|udp|unreal|ut2004|ventrilo|view-source|webcal|wtai|wyciwyg|xfire|xri|ymsgr:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i var urlRE = /^((?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i
CodeMirror.defineMode("gfm", function(config, modeConfig) { CodeMirror.defineMode("gfm", function(config, modeConfig) {
// Should GitHub spice be added (like linking #Num, SHA, etc.)
if (modeConfig.gitHubSpice === undefined)
modeConfig.gitHubSpice = true;
var codeDepth = 0; var codeDepth = 0;
function blankLine(state) { function blankLine(state) {
state.code = false; state.code = false;
return null; return null;
} }
var gfmOverlay = { var gfmOverlay = {
startState: function() { startState: function() {
return { return {
code: false, code: false,
codeBlock: false, codeBlock: false,
ateSpace: false ateSpace: false
}; };
}, },
copyState: function(s) { copyState: function(s) {
return { return {
code: s.code, code: s.code,
codeBlock: s.codeBlock, codeBlock: s.codeBlock,
ateSpace: s.ateSpace ateSpace: s.ateSpace
}; };
}, },
token: function(stream, state) { token: function(stream, state) {
state.combineTokens = null; state.combineTokens = null;
// Hack to prevent formatting override inside code blocks (block and inline) // Hack to prevent formatting override inside code blocks (block and inline)
if (state.codeBlock) { if (state.codeBlock) {
if (stream.match(/^```/)) { if (stream.match(/^```/)) {
state.codeBlock = false; state.codeBlock = false;
return null; return null;
} }
stream.skipToEnd(); stream.skipToEnd();
return null; return null;
} }
if (stream.sol()) { if (stream.sol()) {
state.code = false; state.code = false;
} }
if (stream.sol() && stream.match(/^```/)) { if (stream.sol() && stream.match(/^```/)) {
stream.skipToEnd(); stream.skipToEnd();
state.codeBlock = true; state.codeBlock = true;
return null; return null;
} }
// If this block is changed, it may need to be updated in Markdown mode // If this block is changed, it may need to be updated in Markdown mode
if (stream.peek() === '`') { if (stream.peek() === '`') {
stream.next(); stream.next();
var before = stream.pos; var before = stream.pos;
stream.eatWhile('`'); stream.eatWhile('`');
var difference = 1 + stream.pos - before; var difference = 1 + stream.pos - before;
if (!state.code) { if (!state.code) {
codeDepth = difference; codeDepth = difference;
state.code = true; state.code = true;
} else { } else {
if (difference === codeDepth) { // Must be exact if (difference === codeDepth) { // Must be exact
state.code = false; state.code = false;
} }
} }
return null; return null;
} else if (state.code) { } else if (state.code) {
stream.next(); stream.next();
return null; return null;
} }
// Check if space. If so, links can be formatted later on // Check if space. If so, links can be formatted later on
if (stream.eatSpace()) { if (stream.eatSpace()) {
state.ateSpace = true; state.ateSpace = true;
return null; return null;
} }
if (stream.sol() || state.ateSpace) { if (stream.sol() || state.ateSpace) {
state.ateSpace = false; state.ateSpace = false;
if (modeConfig.gitHubSpice) { if (modeConfig.gitHubSpice !== false) {
if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) { if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
// User/Project@SHA // User/Project@SHA
// User@SHA // User@SHA
// SHA // SHA
state.combineTokens = true; state.combineTokens = true;
return "link"; return "link";
} else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) { } else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
// User/Project#Num // User/Project#Num
// User#Num // User#Num
// #Num // #Num
state.combineTokens = true; state.combineTokens = true;
return "link"; return "link";
} }
} }
} }
if (stream.match(urlRE) && if (stream.match(urlRE) &&
stream.string.slice(stream.start - 2, stream.start) != "](") { stream.string.slice(stream.start - 2, stream.start) != "](" &&
// URLs (stream.start == 0 || /\W/.test(stream.string.charAt(stream.start - 1)))) {
// Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls // URLs
// And then (issue #1160) simplified to make it not crash the Chrome Regexp engine // Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
// And then limited url schemes to the CommonMark list, so foo:bar isn't matched as a URL // And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
state.combineTokens = true; // And then limited url schemes to the CommonMark list, so foo:bar isn't matched as a URL
return "link"; state.combineTokens = true;
} return "link";
stream.next(); }
return null; stream.next();
}, return null;
blankLine: blankLine },
blankLine: blankLine
}; };
var markdownConfig = { var markdownConfig = {
underscoresBreakWords: false, underscoresBreakWords: false,
taskLists: true, taskLists: true,
fencedCodeBlocks: true, fencedCodeBlocks: true,
strikethrough: true strikethrough: true
}; };
for (var attr in modeConfig) { for (var attr in modeConfig) {
markdownConfig[attr] = modeConfig[attr]; markdownConfig[attr] = modeConfig[attr];
} }
markdownConfig.name = "markdown"; markdownConfig.name = "markdown";
return CodeMirror.overlayMode(CodeMirror.getMode(config, markdownConfig), gfmOverlay); return CodeMirror.overlayMode(CodeMirror.getMode(config, markdownConfig), gfmOverlay);
@ -130,4 +127,4 @@ CodeMirror.defineMode("gfm", function(config, modeConfig) {
}, "markdown"); }, "markdown");
CodeMirror.defineMIME("text/x-gfm", "gfm"); CodeMirror.defineMIME("text/x-gfm", "gfm");
}); });

Loading…
Cancel
Save