mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Update Autolinker library (Closes #337)
This commit is contained in:
parent
79ad7ccd0b
commit
0a95b79eb2
5 changed files with 580 additions and 274 deletions
|
|
@ -1596,16 +1596,6 @@
|
||||||
'twitter': false
|
'twitter': false
|
||||||
});
|
});
|
||||||
|
|
||||||
// if ($.fn && $.fn.linkify)
|
|
||||||
// {
|
|
||||||
// sHtml = Globals.$div.html(sHtml.replace(/&/ig, 'amp_amp_12345_amp_amp'))
|
|
||||||
// .linkify()
|
|
||||||
// .find('.linkified').removeClass('linkified').end()
|
|
||||||
// .html()
|
|
||||||
// .replace(/amp_amp_12345_amp_amp/g, '&')
|
|
||||||
// ;
|
|
||||||
// }
|
|
||||||
|
|
||||||
return sHtml;
|
return sHtml;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
731
vendors/Autolinker/Autolinker.js
vendored
731
vendors/Autolinker/Autolinker.js
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
/*!
|
/*!
|
||||||
* Autolinker.js
|
* Autolinker.js
|
||||||
* 0.11.0
|
* 0.11.2
|
||||||
*
|
*
|
||||||
* Copyright(c) 2014 Gregory Jacobs <greg@greg-jacobs.com>
|
* Copyright(c) 2014 Gregory Jacobs <greg@greg-jacobs.com>
|
||||||
* MIT Licensed. http://www.opensource.org/licenses/mit-license.php
|
* MIT Licensed. http://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
@ -8,9 +8,8 @@
|
||||||
* https://github.com/gregjacobs/Autolinker.js
|
* https://github.com/gregjacobs/Autolinker.js
|
||||||
*/
|
*/
|
||||||
/*global define, module */
|
/*global define, module */
|
||||||
/*jshint undef:true, smarttabs:true */
|
|
||||||
// Set up Autolinker appropriately for the environment.
|
|
||||||
( function( root, factory ) {
|
( function( root, factory ) {
|
||||||
|
|
||||||
if( typeof define === 'function' && define.amd ) {
|
if( typeof define === 'function' && define.amd ) {
|
||||||
define( factory ); // Define as AMD module if an AMD loader is present (ex: RequireJS).
|
define( factory ); // Define as AMD module if an AMD loader is present (ex: RequireJS).
|
||||||
} else if( typeof exports !== 'undefined' ) {
|
} else if( typeof exports !== 'undefined' ) {
|
||||||
|
|
@ -54,17 +53,34 @@
|
||||||
* @param {Object} [config] The configuration options for the Autolinker instance, specified in an Object (map).
|
* @param {Object} [config] The configuration options for the Autolinker instance, specified in an Object (map).
|
||||||
*/
|
*/
|
||||||
var Autolinker = function( cfg ) {
|
var Autolinker = function( cfg ) {
|
||||||
cfg = cfg || {};
|
Autolinker.Util.assign( this, cfg ); // assign the properties of `cfg` onto the Autolinker instance. Prototype properties will be used for missing configs.
|
||||||
|
|
||||||
// Assign the properties of `cfg` onto the Autolinker instance
|
|
||||||
for( var prop in cfg )
|
|
||||||
if( cfg.hasOwnProperty( prop ) ) this[ prop ] = cfg[ prop ];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Autolinker.prototype = {
|
Autolinker.prototype = {
|
||||||
constructor : Autolinker, // fix constructor property
|
constructor : Autolinker, // fix constructor property
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} urls
|
||||||
|
*
|
||||||
|
* `true` if miscellaneous URLs should be automatically linked, `false` if they should not be.
|
||||||
|
*/
|
||||||
|
urls : true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} email
|
||||||
|
*
|
||||||
|
* `true` if email addresses should be automatically linked, `false` if they should not be.
|
||||||
|
*/
|
||||||
|
email : true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} twitter
|
||||||
|
*
|
||||||
|
* `true` if Twitter handles ("@example") should be automatically linked, `false` if they should not be.
|
||||||
|
*/
|
||||||
|
twitter : true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @cfg {Boolean} newWindow
|
* @cfg {Boolean} newWindow
|
||||||
*
|
*
|
||||||
|
|
@ -75,7 +91,8 @@
|
||||||
/**
|
/**
|
||||||
* @cfg {Boolean} stripPrefix
|
* @cfg {Boolean} stripPrefix
|
||||||
*
|
*
|
||||||
* `true` if 'http://' or 'https://' and/or the 'www.' should be stripped from the beginning of links, `false` otherwise.
|
* `true` if 'http://' or 'https://' and/or the 'www.' should be stripped from the beginning of URL links' text,
|
||||||
|
* `false` otherwise.
|
||||||
*/
|
*/
|
||||||
stripPrefix : true,
|
stripPrefix : true,
|
||||||
|
|
||||||
|
|
@ -84,33 +101,12 @@
|
||||||
*
|
*
|
||||||
* A number for how many characters long URLs/emails/twitter handles should be truncated to inside the text of
|
* A number for how many characters long URLs/emails/twitter handles should be truncated to inside the text of
|
||||||
* a link. If the URL/email/twitter is over this number of characters, it will be truncated to this length by
|
* a link. If the URL/email/twitter is over this number of characters, it will be truncated to this length by
|
||||||
* adding a two period ellipsis ('..') into the middle of the string.
|
* adding a two period ellipsis ('..') to the end of the string.
|
||||||
*
|
*
|
||||||
* For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters might look
|
* For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters might look
|
||||||
* something like this: 'http://www...th/to/a/file'
|
* something like this: 'yahoo.com/some/long/pat..'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @cfg {Boolean} twitter
|
|
||||||
*
|
|
||||||
* `true` if Twitter handles ("@example") should be automatically linked, `false` if they should not be.
|
|
||||||
*/
|
|
||||||
twitter : true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @cfg {Boolean} email
|
|
||||||
*
|
|
||||||
* `true` if email addresses should be automatically linked, `false` if they should not be.
|
|
||||||
*/
|
|
||||||
email : true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @cfg {Boolean} urls
|
|
||||||
*
|
|
||||||
* `true` if miscellaneous URLs should be automatically linked, `false` if they should not be.
|
|
||||||
*/
|
|
||||||
urls : true,
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @cfg {String} className
|
* @cfg {String} className
|
||||||
*
|
*
|
||||||
|
|
@ -126,6 +122,45 @@
|
||||||
className : "",
|
className : "",
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @property {RegExp} htmlRegex
|
||||||
|
*
|
||||||
|
* The regular expression used to pull out HTML tags from a string. Handles namespaced HTML tags and
|
||||||
|
* attribute names, as specified by http://www.w3.org/TR/html-markup/syntax.html.
|
||||||
|
*
|
||||||
|
* Capturing groups:
|
||||||
|
*
|
||||||
|
* 1. If it is an end tag, this group will have the '/'.
|
||||||
|
* 2. The tag name.
|
||||||
|
*/
|
||||||
|
htmlRegex : (function() {
|
||||||
|
var tagNameRegex = /[0-9a-zA-Z:]+/,
|
||||||
|
attrNameRegex = /[^\s\0"'>\/=\x01-\x1F\x7F]+/, // the unicode range accounts for excluding control chars, and the delete char
|
||||||
|
attrValueRegex = /(?:".*?"|'.*?'|[^'"=<>`\s]+)/, // double quoted, single quoted, or unquoted attribute values
|
||||||
|
nameEqualsValueRegex = attrNameRegex.source + '(?:\\s*=\\s*' + attrValueRegex.source + ')?'; // optional '=[value]'
|
||||||
|
|
||||||
|
return new RegExp( [
|
||||||
|
'<(?:!|(/))?', // Beginning of a tag. Either '<' for a start tag, '</' for an end tag, or <! for the <!DOCTYPE ...> tag. The slash or an empty string is Capturing Group 1.
|
||||||
|
|
||||||
|
// The tag name (Capturing Group 2)
|
||||||
|
'(' + tagNameRegex.source + ')',
|
||||||
|
|
||||||
|
// Zero or more attributes following the tag name
|
||||||
|
'(?:',
|
||||||
|
'\\s+', // one or more whitespace chars before an attribute
|
||||||
|
|
||||||
|
// Either:
|
||||||
|
// A. tag="value", or
|
||||||
|
// B. "value" alone (for <!DOCTYPE> tag. Ex: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
|
||||||
|
'(?:', nameEqualsValueRegex, '|', attrValueRegex.source + ')',
|
||||||
|
')*',
|
||||||
|
|
||||||
|
'\\s*/?', // any trailing spaces and optional '/' before the closing '>'
|
||||||
|
'>'
|
||||||
|
].join( "" ), 'g' );
|
||||||
|
} )(),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @property {RegExp} matcherRegex
|
* @property {RegExp} matcherRegex
|
||||||
|
|
@ -212,58 +247,31 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @property {RegExp} protocolRelativeRegex
|
* @property {RegExp} invalidProtocolRelMatchRegex
|
||||||
*
|
*
|
||||||
* The regular expression used to find protocol-relative URLs. A protocol-relative URL is, for example, "//yahoo.com"
|
* The regular expression used to check a potential protocol-relative URL match, coming from the {@link #matcherRegex}.
|
||||||
|
* A protocol-relative URL is, for example, "//yahoo.com"
|
||||||
*
|
*
|
||||||
* This regular expression needs to match the character before the '//', in order to determine if we should actually
|
* This regular expression is used in conjunction with the {@link #matcherRegex}, and checks to see if there is a word character
|
||||||
* autolink a protocol-relative URL. For instance, we want to autolink something like "//google.com", but we
|
* before the '//' in order to determine if we should actually autolink a protocol-relative URL. This is needed because there
|
||||||
* don't want to autolink something like "abc//google.com"
|
* is no negative look-behind in JavaScript regular expressions.
|
||||||
|
*
|
||||||
|
* For instance, we want to autolink something like "//google.com", but we don't want to autolink something
|
||||||
|
* like "abc//google.com"
|
||||||
*/
|
*/
|
||||||
protocolRelativeRegex : /(.)?\/\//,
|
invalidProtocolRelMatchRegex : /^[\w]\/\//,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @property {RegExp} htmlRegex
|
* @property {RegExp} charBeforeProtocolRelMatchRegex
|
||||||
*
|
*
|
||||||
* The regular expression used to pull out HTML tags from a string. Handles namespaced HTML tags and
|
* The regular expression used to retrieve the character before a protocol-relative URL match.
|
||||||
* attribute names, as specified by http://www.w3.org/TR/html-markup/syntax.html.
|
|
||||||
*
|
*
|
||||||
* Capturing groups:
|
* This is used in conjunction with the {@link #matcherRegex}, which needs to grab the character before a protocol-relative
|
||||||
*
|
* '//' due to the lack of a negative look-behind in JavaScript regular expressions. The character before the match is stripped
|
||||||
* 1. If it is an end tag, this group will have the '/'.
|
* from the URL.
|
||||||
* 2. The tag name.
|
|
||||||
*/
|
*/
|
||||||
htmlRegex : (function() {
|
charBeforeProtocolRelMatchRegex : /^(.)?\/\//,
|
||||||
var tagNameRegex = /[0-9a-zA-Z:]+/,
|
|
||||||
attrNameRegex = /[^\s\0"'>\/=\x01-\x1F\x7F]+/, // the unicode range accounts for excluding control chars, and the delete char
|
|
||||||
attrValueRegex = /(?:".*?"|'.*?'|[^'"=<>`\s]+)/; // double quoted, single quoted, or unquoted attribute values
|
|
||||||
|
|
||||||
return new RegExp( [
|
|
||||||
'<(/)?', // Beginning of a tag. Either '<' for a start tag, or '</' for an end tag. The slash or an empty string is Capturing Group 1.
|
|
||||||
|
|
||||||
// The tag name (Capturing Group 2)
|
|
||||||
'(' + tagNameRegex.source + ')',
|
|
||||||
|
|
||||||
// Zero or more attributes following the tag name
|
|
||||||
'(?:',
|
|
||||||
'\\s+', // one or more whitespace chars before an attribute
|
|
||||||
attrNameRegex.source,
|
|
||||||
'(?:\\s*=\\s*' + attrValueRegex.source + ')?', // optional '=[value]'
|
|
||||||
')*',
|
|
||||||
|
|
||||||
'\\s*', // any trailing spaces before the closing '>'
|
|
||||||
'>'
|
|
||||||
].join( "" ), 'g' );
|
|
||||||
} )(),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @property {RegExp} urlPrefixRegex
|
|
||||||
*
|
|
||||||
* A regular expression used to remove the 'http://' or 'https://' and/or the 'www.' from URLs.
|
|
||||||
*/
|
|
||||||
urlPrefixRegex: /^(https?:\/\/)?(www\.)?/i,
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -282,6 +290,27 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lazily instantiates and returns the {@link #anchorTagBuilder} instance for this Autolinker instance.
|
||||||
|
*
|
||||||
|
* @return {Autolinker.AnchorTagBuilder}
|
||||||
|
*/
|
||||||
|
getAnchorTagBuilder : function() {
|
||||||
|
var anchorTagBuilder = this.anchorTagBuilder;
|
||||||
|
|
||||||
|
if( !anchorTagBuilder ) {
|
||||||
|
anchorTagBuilder = this.anchorTagBuilder = new Autolinker.AnchorTagBuilder( {
|
||||||
|
newWindow : this.newWindow,
|
||||||
|
stripPrefix : this.stripPrefix,
|
||||||
|
truncate : this.truncate,
|
||||||
|
className : this.className
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
return anchorTagBuilder;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the given HTML to auto-link URLs/emails/Twitter handles.
|
* Processes the given HTML to auto-link URLs/emails/Twitter handles.
|
||||||
*
|
*
|
||||||
|
|
@ -355,35 +384,28 @@
|
||||||
* @return {String} The text with anchor tags auto-filled.
|
* @return {String} The text with anchor tags auto-filled.
|
||||||
*/
|
*/
|
||||||
processTextNode : function( text ) {
|
processTextNode : function( text ) {
|
||||||
var me = this, // for closures
|
var me = this, // for closure
|
||||||
matcherRegex = this.matcherRegex,
|
invalidProtocolRelMatchRegex = this.invalidProtocolRelMatchRegex,
|
||||||
enableTwitter = this.twitter,
|
charBeforeProtocolRelMatchRegex = this.charBeforeProtocolRelMatchRegex,
|
||||||
enableEmailAddresses = this.email,
|
anchorTagBuilder = this.getAnchorTagBuilder();
|
||||||
enableUrls = this.urls;
|
|
||||||
|
|
||||||
return text.replace( matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7 ) {
|
return text.replace( this.matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7 ) {
|
||||||
var twitterMatch = $1,
|
var twitterMatch = $1,
|
||||||
twitterHandlePrefixWhitespaceChar = $2, // The whitespace char before the @ sign in a Twitter handle match. This is needed because of no lookbehinds in JS regexes
|
twitterHandlePrefixWhitespaceChar = $2, // The whitespace char before the @ sign in a Twitter handle match. This is needed because of no lookbehinds in JS regexes
|
||||||
twitterHandle = $3, // The actual twitterUser (i.e the word after the @ sign in a Twitter handle match)
|
twitterHandle = $3, // The actual twitterUser (i.e the word after the @ sign in a Twitter handle match)
|
||||||
emailAddress = $4, // For both determining if it is an email address, and stores the actual email address
|
emailAddressMatch = $4, // For both determining if it is an email address, and stores the actual email address
|
||||||
urlMatch = $5, // The matched URL string
|
urlMatch = $5, // The matched URL string
|
||||||
protocolRelativeMatch = $6 || $7, // The '//' for a protocol-relative match, with the character that comes before the '//'
|
protocolRelativeMatch = $6 || $7, // The '//' for a protocol-relative match, with the character that comes before the '//'
|
||||||
|
|
||||||
prefixStr = "", // A string to use to prefix the anchor tag that is created. This is needed for the Twitter handle match
|
prefixStr = "", // A string to use to prefix the anchor tag that is created. This is needed for the Twitter handle match
|
||||||
suffixStr = ""; // A string to suffix the anchor tag that is created. This is used if there is a trailing parenthesis that should not be auto-linked.
|
suffixStr = "", // A string to suffix the anchor tag that is created. This is used if there is a trailing parenthesis that should not be auto-linked.
|
||||||
|
|
||||||
// Early exits with no replacements for:
|
match; // Will be an Autolinker.Match object
|
||||||
// 1) Disabled link types
|
|
||||||
// 2) URL matches which do not have at least have one period ('.') in the domain name (effectively skipping over
|
|
||||||
// matches like "abc:def")
|
// Return out with no changes for match types that are disabled (url, email, twitter), or for matches
|
||||||
// 3) A protocol-relative url match (a URL beginning with '//') whose previous character is a word character
|
// that are invalid.
|
||||||
// (effectively skipping over strings like "abc//google.com")
|
if( !me.isValidMatch( twitterMatch, emailAddressMatch, urlMatch, protocolRelativeMatch ) ) {
|
||||||
if(
|
|
||||||
( twitterMatch && !enableTwitter ) || ( emailAddress && !enableEmailAddresses ) || ( urlMatch && !enableUrls ) ||
|
|
||||||
( urlMatch && urlMatch.indexOf( '.' ) === -1 ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL
|
|
||||||
( urlMatch && /^[A-Za-z]{3,9}:/.test( urlMatch ) && !/:.*?[A-Za-z]/.test( urlMatch ) ) || // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
|
|
||||||
( protocolRelativeMatch && /^[\w]\/\//.test( protocolRelativeMatch ) ) // a protocol-relative match which has a word character in front of it (so we can skip something like "abc//google.com")
|
|
||||||
) {
|
|
||||||
return matchStr;
|
return matchStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,60 +428,226 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var anchorHref = matchStr, // initialize both of these
|
|
||||||
anchorText = matchStr, // values as the full match
|
|
||||||
linkType;
|
|
||||||
|
|
||||||
// Process the urls that are found. We need to change URLs like "www.yahoo.com" to "http://www.yahoo.com" (or the browser
|
|
||||||
// will try to direct the user to "http://current-domain.com/www.yahoo.com"), and we need to prefix 'mailto:' to email addresses.
|
|
||||||
if( twitterMatch ) {
|
if( twitterMatch ) {
|
||||||
linkType = 'twitter';
|
|
||||||
prefixStr = twitterHandlePrefixWhitespaceChar;
|
prefixStr = twitterHandlePrefixWhitespaceChar;
|
||||||
anchorHref = 'https://twitter.com/' + twitterHandle;
|
match = new Autolinker.TwitterMatch( { twitterHandle: twitterHandle } );
|
||||||
anchorText = '@' + twitterHandle;
|
|
||||||
|
|
||||||
} else if( emailAddress ) {
|
} else if( emailAddressMatch ) {
|
||||||
linkType = 'email';
|
match = new Autolinker.EmailMatch( { emailAddress: emailAddressMatch } );
|
||||||
anchorHref = 'mailto:' + emailAddress;
|
|
||||||
anchorText = emailAddress;
|
|
||||||
|
|
||||||
} else { // url match
|
} else { // url match
|
||||||
linkType = 'url';
|
// If it's a protocol-relative '//' match, remove the character before the '//' (which the matcherRegex needed
|
||||||
|
// to match due to the lack of a negative look-behind in JavaScript regular expressions)
|
||||||
if( protocolRelativeMatch ) {
|
if( protocolRelativeMatch ) {
|
||||||
// Strip off any protocol-relative '//' from the anchor text (leaving the previous non-word character
|
var charBeforeMatch = protocolRelativeMatch.match( charBeforeProtocolRelMatchRegex )[ 1 ] || "";
|
||||||
// intact, if there is one)
|
|
||||||
var protocolRelRegex = new RegExp( "^" + me.protocolRelativeRegex.source ), // for this one, we want to only match at the beginning of the string
|
|
||||||
charBeforeMatch = protocolRelativeMatch.match( protocolRelRegex )[ 1 ] || "";
|
|
||||||
|
|
||||||
prefixStr = charBeforeMatch + prefixStr; // re-add the character before the '//' to what will be placed before the <a> tag
|
if( charBeforeMatch ) {
|
||||||
anchorHref = anchorHref.replace( protocolRelRegex, "//" ); // remove the char before the match for the href
|
prefixStr = charBeforeMatch; // re-add the character before the '//' to what will be placed before the generated <a> tag
|
||||||
anchorText = anchorText.replace( protocolRelRegex, "" ); // remove both the char before the match and the '//' for the anchor text
|
matchStr = matchStr.slice( 1 );
|
||||||
|
}
|
||||||
} else if( !/^[A-Za-z]{3,9}:/i.test( anchorHref ) ) {
|
|
||||||
// url string doesn't begin with a protocol, assume http://
|
|
||||||
anchorHref = 'http://' + anchorHref;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match = new Autolinker.UrlMatch( { url: matchStr, protocolRelativeMatch: protocolRelativeMatch } );
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap the match in an anchor tag
|
// wrap the match in an anchor tag
|
||||||
var anchorTag = me.createAnchorTag( linkType, anchorHref, anchorText );
|
var anchorTag = anchorTagBuilder.createAnchorTag( match.getType(), match.getAnchorHref(), match.getAnchorText() );
|
||||||
return prefixStr + anchorTag + suffixStr;
|
return prefixStr + anchorTag + suffixStr;
|
||||||
} );
|
} );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the actual anchor (<a>) tag to use in place of a source url/email/twitter link.
|
* Determines if a given match found by {@link #processTextNode} is valid. Will return `false` for:
|
||||||
|
*
|
||||||
|
* 1) Disabled link types (i.e. having a Twitter match, but {@link #twitter} matching is disabled)
|
||||||
|
* 2) URL matches which do not have at least have one period ('.') in the domain name (effectively skipping over
|
||||||
|
* matches like "abc:def")
|
||||||
|
* 3) A protocol-relative url match (a URL beginning with '//') whose previous character is a word character
|
||||||
|
* (effectively skipping over strings like "abc//google.com")
|
||||||
|
*
|
||||||
|
* Otherwise, returns `true`.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {"url"/"email"/"twitter"} linkType The type of link that an anchor tag is being generated for.
|
* @param {String} twitterMatch The matched Twitter handle, if there was one. Will be empty string if the match is not a
|
||||||
|
* Twitter match.
|
||||||
|
* @param {String} emailAddressMatch The matched Email address, if there was one. Will be empty string if the match is not
|
||||||
|
* an Email address match.
|
||||||
|
* @param {String} urlMatch The matched URL, if there was one. Will be an empty string if the match is not a URL match.
|
||||||
|
* @param {String} protocolRelativeMatch The protocol-relative string for a URL match (i.e. '//'), possibly with a preceding
|
||||||
|
* character (ex, a space, such as: ' //', or a letter, such as: 'a//'). The match is invalid if there is a word character
|
||||||
|
* preceding the '//'.
|
||||||
|
* @return {Boolean} `true` if the match given is valid and should be processed, or `false` if the match is invalid and/or
|
||||||
|
* should just not be processed (such as, if it's a Twitter match, but {@link #twitter} matching is disabled}.
|
||||||
|
*/
|
||||||
|
isValidMatch : function( twitterMatch, emailAddressMatch, urlMatch, protocolRelativeMatch ) {
|
||||||
|
if(
|
||||||
|
( twitterMatch && !this.twitter ) || ( emailAddressMatch && !this.email ) || ( urlMatch && !this.urls ) ||
|
||||||
|
( urlMatch && urlMatch.indexOf( '.' ) === -1 ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL
|
||||||
|
( urlMatch && /^[A-Za-z]{3,9}:/.test( urlMatch ) && !/:.*?[A-Za-z]/.test( urlMatch ) ) || // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
|
||||||
|
( protocolRelativeMatch && this.invalidProtocolRelMatchRegex.test( protocolRelativeMatch ) ) // a protocol-relative match which has a word character in front of it (so we can skip something like "abc//google.com")
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically links URLs, email addresses, and Twitter handles found in the given chunk of HTML.
|
||||||
|
* Does not link URLs found within HTML tags.
|
||||||
|
*
|
||||||
|
* For instance, if given the text: `You should go to http://www.yahoo.com`, then the result
|
||||||
|
* will be `You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a>`
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } );
|
||||||
|
* // Produces: "Go to <a href="http://google.com">google.com</a>"
|
||||||
|
*
|
||||||
|
* @static
|
||||||
|
* @method link
|
||||||
|
* @param {String} html The HTML text to link URLs within.
|
||||||
|
* @param {Object} [options] Any of the configuration options for the Autolinker class, specified in an Object (map).
|
||||||
|
* See the class description for an example call.
|
||||||
|
* @return {String} The HTML text, with URLs automatically linked
|
||||||
|
*/
|
||||||
|
Autolinker.link = function( text, options ) {
|
||||||
|
var autolinker = new Autolinker( options );
|
||||||
|
return autolinker.link( text );
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Autolinker.Util
|
||||||
|
* @singleton
|
||||||
|
*
|
||||||
|
* A few utility methods for Autolinker.
|
||||||
|
*/
|
||||||
|
Autolinker.Util = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property {Function} abstractMethod
|
||||||
|
*
|
||||||
|
* A function object which represents an abstract method.
|
||||||
|
*/
|
||||||
|
abstractMethod : function() { throw "abstract"; },
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns (shallow copies) the properties of `src` onto `dest`.
|
||||||
|
*
|
||||||
|
* @param {Object} dest The destination object.
|
||||||
|
* @param {Object} src The source object.
|
||||||
|
* @return {Object} The destination object.
|
||||||
|
*/
|
||||||
|
assign : function( dest, src ) {
|
||||||
|
for( var prop in src ) {
|
||||||
|
if( src.hasOwnProperty( prop ) ) {
|
||||||
|
dest[ prop ] = src[ prop ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends `superclass` to create a new subclass, adding the `protoProps` to the new subclass's prototype.
|
||||||
|
*
|
||||||
|
* @param {Function} superclass The constructor function for the superclass.
|
||||||
|
* @param {Object} protoProps The methods/properties to add to the subclass's prototype. This may contain the
|
||||||
|
* special property `constructor`, which will be used as the new subclass's constructor function.
|
||||||
|
* @return {Function} The new subclass function.
|
||||||
|
*/
|
||||||
|
extend : function( superclass, protoProps ) {
|
||||||
|
var superclassProto = superclass.prototype;
|
||||||
|
|
||||||
|
var F = function() {};
|
||||||
|
F.prototype = superclassProto;
|
||||||
|
|
||||||
|
var subclass;
|
||||||
|
if( protoProps.hasOwnProperty( 'constructor' ) ) {
|
||||||
|
subclass = protoProps.constructor;
|
||||||
|
} else {
|
||||||
|
subclass = function() { superclassProto.constructor.apply( this, arguments ); };
|
||||||
|
}
|
||||||
|
|
||||||
|
var subclassProto = subclass.prototype = new F(); // set up prototype chain
|
||||||
|
subclassProto.constructor = subclass; // fix constructor property
|
||||||
|
subclassProto.superclass = superclassProto;
|
||||||
|
|
||||||
|
delete protoProps.constructor; // don't re-assign constructor property to the prototype, since a new function may have been created (`subclass`), which is now already there
|
||||||
|
Autolinker.Util.assign( subclassProto, protoProps );
|
||||||
|
|
||||||
|
return subclass;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @class Autolinker.AnchorTagBuilder
|
||||||
|
* @extends Object
|
||||||
|
*
|
||||||
|
* Builds the anchor (<a>) tags for the Autolinker utility when a match is found.
|
||||||
|
*/
|
||||||
|
Autolinker.AnchorTagBuilder = Autolinker.Util.extend( Object, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} newWindow
|
||||||
|
*
|
||||||
|
* See {@link Autolinker#newWindow} for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} stripPrefix
|
||||||
|
*
|
||||||
|
* See {@link Autolinker#stripPrefix} for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Number} truncate
|
||||||
|
*
|
||||||
|
* See {@link Autolinker#truncate} for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {String} className
|
||||||
|
*
|
||||||
|
* See {@link Autolinker#className} for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @property {RegExp} urlPrefixRegex
|
||||||
|
*
|
||||||
|
* A regular expression used to remove the 'http://' or 'https://' and/or the 'www.' from URLs.
|
||||||
|
*/
|
||||||
|
urlPrefixRegex: /^(https?:\/\/)?(www\.)?/i,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} [cfg] The configuration options for the AnchorTagBuilder instance, specified in an Object (map).
|
||||||
|
*/
|
||||||
|
constructor : function( cfg ) {
|
||||||
|
Autolinker.Util.assign( this, cfg );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the actual anchor (<a>) tag to use in place of a source url/email/twitter link.
|
||||||
|
*
|
||||||
|
* @param {"url"/"email"/"twitter"} matchType The type of match that an anchor tag is being generated for.
|
||||||
* @param {String} anchorHref The href for the anchor tag.
|
* @param {String} anchorHref The href for the anchor tag.
|
||||||
* @param {String} anchorText The anchor tag's text (i.e. what will be displayed).
|
* @param {String} anchorText The anchor tag's text (i.e. what will be displayed).
|
||||||
* @return {String} The full HTML for the anchor tag.
|
* @return {String} The full HTML for the anchor tag.
|
||||||
*/
|
*/
|
||||||
createAnchorTag : function( linkType, anchorHref, anchorText ) {
|
createAnchorTag : function( matchType, anchorHref, anchorText ) {
|
||||||
var attributesStr = this.createAnchorAttrsStr( linkType, anchorHref );
|
var attributesStr = this.createAnchorAttrsStr( matchType, anchorHref );
|
||||||
anchorText = this.processAnchorText( anchorText );
|
anchorText = this.processAnchorText( anchorText );
|
||||||
|
|
||||||
return '<a ' + attributesStr + '>' + anchorText + '</a>';
|
return '<a ' + attributesStr + '>' + anchorText + '</a>';
|
||||||
|
|
@ -470,14 +658,14 @@
|
||||||
* Creates the string which will be the HTML attributes for the anchor (<a>) tag being generated.
|
* Creates the string which will be the HTML attributes for the anchor (<a>) tag being generated.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {"url"/"email"/"twitter"} linkType The type of link that an anchor tag is being generated for.
|
* @param {"url"/"email"/"twitter"} matchType The type of match that an anchor tag is being generated for.
|
||||||
* @param {String} href The href for the anchor tag.
|
* @param {String} href The href for the anchor tag.
|
||||||
* @return {String} The anchor tag's attribute. Ex: `href="http://google.com" class="myLink myLink-url" target="_blank"`
|
* @return {String} The anchor tag's attribute. Ex: `href="http://google.com" class="myLink myLink-url" target="_blank"`
|
||||||
*/
|
*/
|
||||||
createAnchorAttrsStr : function( linkType, anchorHref ) {
|
createAnchorAttrsStr : function( matchType, anchorHref ) {
|
||||||
var attrs = [ 'href="' + anchorHref + '"' ]; // we'll always have the `href` attribute
|
var attrs = [ 'href="' + anchorHref + '"' ]; // we'll always have the `href` attribute
|
||||||
|
|
||||||
var cssClass = this.createCssClass( linkType );
|
var cssClass = this.createCssClass( matchType );
|
||||||
if( cssClass ) {
|
if( cssClass ) {
|
||||||
attrs.push( 'class="' + cssClass + '"' );
|
attrs.push( 'class="' + cssClass + '"' );
|
||||||
}
|
}
|
||||||
|
|
@ -490,21 +678,21 @@
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the CSS class that will be used for a given anchor tag, based on the `linkType` and the {@link #className}
|
* Creates the CSS class that will be used for a given anchor tag, based on the `matchType` and the {@link #className}
|
||||||
* config.
|
* config.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {"url"/"email"/"twitter"} linkType The type of link that an anchor tag is being generated for.
|
* @param {"url"/"email"/"twitter"} matchType The type of match that an anchor tag is being generated for.
|
||||||
* @return {String} The CSS class string for the link. Example return: "myLink myLink-url". If no {@link #className}
|
* @return {String} The CSS class string for the link. Example return: "myLink myLink-url". If no {@link #className}
|
||||||
* was configured, returns an empty string.
|
* was configured, returns an empty string.
|
||||||
*/
|
*/
|
||||||
createCssClass : function( linkType ) {
|
createCssClass : function( matchType ) {
|
||||||
var className = this.className;
|
var className = this.className;
|
||||||
|
|
||||||
if( !className )
|
if( !className )
|
||||||
return "";
|
return "";
|
||||||
else
|
else
|
||||||
return className + " " + className + "-" + linkType; // ex: "myLink myLink-url", "myLink myLink-email", or "myLink myLink-twitter"
|
return className + " " + className + "-" + matchType; // ex: "myLink myLink-url", "myLink myLink-email", or "myLink myLink-twitter"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -541,7 +729,7 @@
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any trailing slash from the given `anchorText`, in prepration for the text to be displayed.
|
* Removes any trailing slash from the given `anchorText`, in preparation for the text to be displayed.
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing
|
* @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing
|
||||||
|
|
@ -574,33 +762,258 @@
|
||||||
return anchorText;
|
return anchorText;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
} );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Automatically links URLs, email addresses, and Twitter handles found in the given chunk of HTML.
|
* @private
|
||||||
* Does not link URLs found within HTML tags.
|
* @abstract
|
||||||
|
* @class Autolinker.Match
|
||||||
*
|
*
|
||||||
* For instance, if given the text: `You should go to http://www.yahoo.com`, then the result
|
* Represents a match found in an input string which should be Autolinked.
|
||||||
* will be `You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a>`
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } );
|
|
||||||
* // Produces: "Go to <a href="http://google.com">google.com</a>"
|
|
||||||
*
|
|
||||||
* @static
|
|
||||||
* @method link
|
|
||||||
* @param {String} html The HTML text to link URLs within.
|
|
||||||
* @param {Object} [options] Any of the configuration options for the Autolinker class, specified in an Object (map).
|
|
||||||
* See the class description for an example call.
|
|
||||||
* @return {String} The HTML text, with URLs automatically linked
|
|
||||||
*/
|
*/
|
||||||
Autolinker.link = function( text, options ) {
|
Autolinker.Match = Autolinker.Util.extend( Object, {
|
||||||
var autolinker = new Autolinker( options );
|
|
||||||
return autolinker.link( text );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {Object} cfg The configuration properties for the Match instance, specified in an Object (map).
|
||||||
|
*/
|
||||||
|
constructor : function( cfg ) {
|
||||||
|
Autolinker.Util.assign( this, cfg );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string name for the type of match that this class represents.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getType : Autolinker.Util.abstractMethod,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor href that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorHref : Autolinker.Util.abstractMethod,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor text that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @abstract
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorText : Autolinker.Util.abstractMethod
|
||||||
|
|
||||||
|
} );
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @class Autolinker.EmailMatch
|
||||||
|
*
|
||||||
|
* Represents a Email match found in an input string which should be Autolinked.
|
||||||
|
*/
|
||||||
|
Autolinker.EmailMatch = Autolinker.Util.extend( Autolinker.Match, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {String} emailAddress (required)
|
||||||
|
*
|
||||||
|
* The email address that was matched.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string name for the type of match that this class represents.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getType : function() {
|
||||||
|
return 'email';
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the email address that was matched.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getEmailAddress : function() {
|
||||||
|
return this.emailAddress;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor href that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorHref : function() {
|
||||||
|
return 'mailto:' + this.emailAddress;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor text that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorText : function() {
|
||||||
|
return this.emailAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @class Autolinker.TwitterMatch
|
||||||
|
*
|
||||||
|
* Represents a Twitter match found in an input string which should be Autolinked.
|
||||||
|
*/
|
||||||
|
Autolinker.TwitterMatch = Autolinker.Util.extend( Autolinker.Match, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {String} twitterHandle (required)
|
||||||
|
*
|
||||||
|
* The Twitter handle that was matched.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of match that this class represents.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getType : function() {
|
||||||
|
return 'twitter';
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string name for the type of match that this class represents.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getTwitterHandle : function() {
|
||||||
|
return this.twitterHandle;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor href that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorHref : function() {
|
||||||
|
return 'https://twitter.com/' + this.twitterHandle;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor text that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorText : function() {
|
||||||
|
return '@' + this.twitterHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @class Autolinker.TwitterMatch
|
||||||
|
*
|
||||||
|
* Represents a Url match found in an input string which should be Autolinked.
|
||||||
|
*/
|
||||||
|
Autolinker.UrlMatch = Autolinker.Util.extend( Autolinker.Match, {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {String} url (required)
|
||||||
|
*
|
||||||
|
* The url that was matched.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @cfg {Boolean} protocolRelativeMatch (required)
|
||||||
|
*
|
||||||
|
* `true` if the URL is a protocol-relative match. A protocol-relative match is a URL that starts with '//',
|
||||||
|
* and will be either http:// or https:// based on the protocol that the site is loaded under.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @property {RegExp} protocolRelativeRegex
|
||||||
|
*
|
||||||
|
* The regular expression used to remove the protocol-relative '//' from the {@link #url} string, for purposes
|
||||||
|
* of {@link #getAnchorText}. A protocol-relative URL is, for example, "//yahoo.com"
|
||||||
|
*/
|
||||||
|
protocolRelativeRegex : /^\/\//,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @protected
|
||||||
|
* @property {RegExp} checkForProtocolRegex
|
||||||
|
*
|
||||||
|
* A regular expression used to check if the {@link #url} is missing a protocol (in which case, 'http://'
|
||||||
|
* will be added).
|
||||||
|
*/
|
||||||
|
checkForProtocolRegex: /^[A-Za-z]{3,9}:/,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string name for the type of match that this class represents.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getType : function() {
|
||||||
|
return 'url';
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the url that was matched, assuming the protocol to be 'http://' if the match
|
||||||
|
* was missing a protocol.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getUrl : function() {
|
||||||
|
var url = this.url;
|
||||||
|
|
||||||
|
// if the url string doesn't begin with a protocol, assume http://
|
||||||
|
if( !this.protocolRelativeMatch && !this.checkForProtocolRegex.test( url ) ) {
|
||||||
|
url = this.url = 'http://' + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor href that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorHref : function() {
|
||||||
|
return this.getUrl();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the anchor text that should be generated for the match.
|
||||||
|
*
|
||||||
|
* @return {String}
|
||||||
|
*/
|
||||||
|
getAnchorText : function() {
|
||||||
|
var url = this.getUrl();
|
||||||
|
|
||||||
|
if( this.protocolRelativeMatch ) {
|
||||||
|
// Strip off any protocol-relative '//' from the anchor text
|
||||||
|
url = url.replace( this.protocolRelativeRegex, '' );
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
return Autolinker;
|
return Autolinker;
|
||||||
|
|
||||||
|
|
|
||||||
4
vendors/Autolinker/Autolinker.min.js
vendored
4
vendors/Autolinker/Autolinker.min.js
vendored
File diff suppressed because one or more lines are too long
88
vendors/jquery-linkify/jquery.linkify.js
vendored
88
vendors/jquery-linkify/jquery.linkify.js
vendored
|
|
@ -1,88 +0,0 @@
|
||||||
/*
|
|
||||||
* Linkify - v1.1.6
|
|
||||||
* Find URLs in plain text and return HTML for discovered links.
|
|
||||||
* https://github.com/HitSend/jQuery-linkify/
|
|
||||||
*
|
|
||||||
* Made by SoapBox Innovations, Inc.
|
|
||||||
* Under MIT License
|
|
||||||
*/
|
|
||||||
!function($, window, document) {
|
|
||||||
"use strict";
|
|
||||||
function Linkified(element, options) {
|
|
||||||
this._defaults = defaults, this.element = element, this.setOptions(options), this.init();
|
|
||||||
}
|
|
||||||
var defaults = {
|
|
||||||
tagName: "a",
|
|
||||||
newLine: "\n",
|
|
||||||
target: "_blank",
|
|
||||||
linkClass: null,
|
|
||||||
linkClasses: [],
|
|
||||||
linkAttributes: null
|
|
||||||
};
|
|
||||||
Linkified.prototype = {
|
|
||||||
constructor: Linkified,
|
|
||||||
init: function() {
|
|
||||||
1 === this.element.nodeType ? Linkified.linkifyNode.call(this, this.element) : this.element = Linkified.linkify.call(this, this.element.toString());
|
|
||||||
},
|
|
||||||
setOptions: function(options) {
|
|
||||||
this.settings = Linkified.extendSettings(options, this.settings);
|
|
||||||
},
|
|
||||||
toString: function() {
|
|
||||||
return this.element.toString();
|
|
||||||
}
|
|
||||||
}, Linkified.extendSettings = function(options, settings) {
|
|
||||||
var prop;
|
|
||||||
settings = settings || {};
|
|
||||||
for (prop in defaults) settings[prop] || (settings[prop] = defaults[prop]);
|
|
||||||
for (prop in options) settings[prop] = options[prop];
|
|
||||||
return settings;
|
|
||||||
}, Linkified.linkMatch = new RegExp([ "(", '\\s|[^a-zA-Z0-9.\\+_\\/"\\>\\-]|^', ")(?:", "(", "[a-zA-Z0-9\\+_\\-]+", "(?:", "\\.[a-zA-Z0-9\\+_\\-]+", ")*@", ")?(", "http:\\/\\/|https:\\/\\/|ftp:\\/\\/", ")?(", "(?:(?:[a-zA-Z0-9][a-zA-Z0-9_%\\-_+]*\\.)+)", ")(", "(?:com|ca|co|edu|gov|net|org|dev|biz|cat|int|pro|tel|mil|aero|asia|coop|info|jobs|mobi|museum|name|post|travel|local|[a-z]{2})", ")(", "(?::\\d{1,5})", ")?(", "(?:", "[\\/|\\?]", "(?:", "[\\-a-zA-Z0-9_%#*&+=~!?,;:.\\/]*", ")*", ")", "[\\-\\/a-zA-Z0-9_%#*&+=~]", "|", "\\/?", ")?", ")(", '[^a-zA-Z0-9\\+_\\/"\\<\\-]|$', ")" ].join(""), "g"),
|
|
||||||
Linkified.emailLinkMatch = /(<[a-z]+ href=\")(http:\/\/)([a-zA-Z0-9\+_\-]+(?:\.[a-zA-Z0-9\+_\-]+)*@)/g,
|
|
||||||
Linkified.linkify = function(text, options) {
|
|
||||||
var attr, settings, linkClasses, linkReplace = [];
|
|
||||||
this.constructor === Linkified && this.settings ? (settings = this.settings, options && (settings = Linkified.extendSettings(options, settings))) : settings = Linkified.extendSettings(options),
|
|
||||||
linkClasses = settings.linkClass ? settings.linkClass.split(/\s+/) : [], linkClasses.push.apply(linkClasses, settings.linkClasses),
|
|
||||||
text = text.replace(/</g, "<").replace(/(\s)/g, "$1$1"), linkReplace.push("$1<" + settings.tagName, 'href="http://$2$4$5$6$7"'),
|
|
||||||
linkReplace.push('class="linkified' + (linkClasses.length > 0 ? " " + linkClasses.join(" ") : "") + '"'),
|
|
||||||
settings.target && linkReplace.push('target="' + settings.target + '"');
|
|
||||||
for (attr in settings.linkAttributes) linkReplace.push([ attr, '="', settings.linkAttributes[attr].replace(/\"/g, """).replace(/\$/g, "$"), '"' ].join(""));
|
|
||||||
return linkReplace.push(">$2$3$4$5$6$7</" + settings.tagName + ">$8"), text = text.replace(Linkified.linkMatch, linkReplace.join(" ")),
|
|
||||||
text = text.replace(Linkified.emailLinkMatch, "$1mailto:$3"), text = text.replace(/(\s){2}/g, "$1"),
|
|
||||||
text = text.replace(/\n/g, settings.newLine);
|
|
||||||
}, Linkified.linkifyNode = function(node) {
|
|
||||||
var children, childNode, childCount, dummyElement, i;
|
|
||||||
if (node && "object" == typeof node && 1 === node.nodeType && "a" !== node.tagName.toLowerCase() && !/[^\s]linkified[\s$]/.test(node.className)) {
|
|
||||||
for (children = [], dummyElement = Linkified._dummyElement || document.createElement("div"),
|
|
||||||
childNode = node.firstChild, childCount = node.childElementCount; childNode; ) {
|
|
||||||
if (3 === childNode.nodeType) {
|
|
||||||
for (;dummyElement.firstChild; ) dummyElement.removeChild(dummyElement.firstChild);
|
|
||||||
for (dummyElement.innerHTML = Linkified.linkify.call(this, childNode.textContent || childNode.innerText || childNode.nodeValue),
|
|
||||||
children.push.apply(children, dummyElement.childNodes); dummyElement.firstChild; ) dummyElement.removeChild(dummyElement.firstChild);
|
|
||||||
} else 1 === childNode.nodeType ? children.push(Linkified.linkifyNode(childNode)) : children.push(childNode);
|
|
||||||
childNode = childNode.nextSibling;
|
|
||||||
}
|
|
||||||
for (;node.firstChild; ) node.removeChild(node.firstChild);
|
|
||||||
for (i = 0; i < children.length; i++) node.appendChild(children[i]);
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}, Linkified._dummyElement = document.createElement("div"), $.fn.linkify = function(options) {
|
|
||||||
return this.each(function() {
|
|
||||||
var linkified;
|
|
||||||
(linkified = $.data(this, "plugin-linkify")) ? (linkified.setOptions(options), linkified.init()) : $.data(this, "plugin-linkify", new Linkified(this, options));
|
|
||||||
});
|
|
||||||
}, $.fn.linkify.Constructor = Linkified, $(window).on("load", function() {
|
|
||||||
$("[data-linkify]").each(function() {
|
|
||||||
var $target, $this = $(this), target = $this.attr("data-linkify"), options = {
|
|
||||||
tagName: $this.attr("data-linkify-tagname"),
|
|
||||||
newLine: $this.attr("data-linkify-newline"),
|
|
||||||
target: $this.attr("data-linkify-target"),
|
|
||||||
linkClass: $this.attr("data-linkify-linkclass")
|
|
||||||
};
|
|
||||||
for (var option in options) "undefined" == typeof options[option] && delete options[option];
|
|
||||||
$target = "this" === target ? $this : $this.find(target), $target.linkify(options);
|
|
||||||
});
|
|
||||||
}), $("body").on("click", ".linkified", function() {
|
|
||||||
var $link = $(this), url = $link.attr("href"), isEmail = /^mailto:/i.test(url), target = $link.attr("target");
|
|
||||||
return isEmail ? window.location.href = url : window.open(url, target), !1;
|
|
||||||
});
|
|
||||||
}(jQuery, window, document);
|
|
||||||
9
vendors/jquery-linkify/jquery.linkify.min.js
vendored
9
vendors/jquery-linkify/jquery.linkify.min.js
vendored
|
|
@ -1,9 +0,0 @@
|
||||||
/*
|
|
||||||
* Linkify - v1.1.6
|
|
||||||
* Find URLs in plain text and return HTML for discovered links.
|
|
||||||
* https://github.com/HitSend/jQuery-linkify/
|
|
||||||
*
|
|
||||||
* Made by SoapBox Innovations, Inc.
|
|
||||||
* Under MIT License
|
|
||||||
*/
|
|
||||||
!function(a,b,c){"use strict";function d(a,b){this._defaults=e,this.element=a,this.setOptions(b),this.init()}var e={tagName:"a",newLine:"\n",target:"_blank",linkClass:null,linkClasses:[],linkAttributes:null};d.prototype={constructor:d,init:function(){1===this.element.nodeType?d.linkifyNode.call(this,this.element):this.element=d.linkify.call(this,this.element.toString())},setOptions:function(a){this.settings=d.extendSettings(a,this.settings)},toString:function(){return this.element.toString()}},d.extendSettings=function(a,b){var c;b=b||{};for(c in e)b[c]||(b[c]=e[c]);for(c in a)b[c]=a[c];return b},d.linkMatch=new RegExp(["(",'\\s|[^a-zA-Z0-9.\\+_\\/"\\>\\-]|^',")(?:","(","[a-zA-Z0-9\\+_\\-]+","(?:","\\.[a-zA-Z0-9\\+_\\-]+",")*@",")?(","http:\\/\\/|https:\\/\\/|ftp:\\/\\/",")?(","(?:(?:[a-zA-Z0-9][a-zA-Z0-9_%\\-_+]*\\.)+)",")(","(?:com|ca|co|edu|gov|net|org|dev|biz|cat|int|pro|tel|mil|aero|asia|coop|info|jobs|mobi|museum|name|post|travel|local|[a-z]{2})",")(","(?::\\d{1,5})",")?(","(?:","[\\/|\\?]","(?:","[\\-a-zA-Z0-9_%#*&+=~!?,;:.\\/]*",")*",")","[\\-\\/a-zA-Z0-9_%#*&+=~]","|","\\/?",")?",")(",'[^a-zA-Z0-9\\+_\\/"\\<\\-]|$',")"].join(""),"g"),d.emailLinkMatch=/(<[a-z]+ href=\")(http:\/\/)([a-zA-Z0-9\+_\-]+(?:\.[a-zA-Z0-9\+_\-]+)*@)/g,d.linkify=function(a,b){var c,e,f,g=[];this.constructor===d&&this.settings?(e=this.settings,b&&(e=d.extendSettings(b,e))):e=d.extendSettings(b),f=e.linkClass?e.linkClass.split(/\s+/):[],f.push.apply(f,e.linkClasses),a=a.replace(/</g,"<").replace(/(\s)/g,"$1$1"),g.push("$1<"+e.tagName,'href="http://$2$4$5$6$7"'),g.push('class="linkified'+(f.length>0?" "+f.join(" "):"")+'"'),e.target&&g.push('target="'+e.target+'"');for(c in e.linkAttributes)g.push([c,'="',e.linkAttributes[c].replace(/\"/g,""").replace(/\$/g,"$"),'"'].join(""));return g.push(">$2$3$4$5$6$7</"+e.tagName+">$8"),a=a.replace(d.linkMatch,g.join(" ")),a=a.replace(d.emailLinkMatch,"$1mailto:$3"),a=a.replace(/(\s){2}/g,"$1"),a=a.replace(/\n/g,e.newLine)},d.linkifyNode=function(a){var b,e,f,g,h;if(a&&"object"==typeof a&&1===a.nodeType&&"a"!==a.tagName.toLowerCase()&&!/[^\s]linkified[\s$]/.test(a.className)){for(b=[],g=d._dummyElement||c.createElement("div"),e=a.firstChild,f=a.childElementCount;e;){if(3===e.nodeType){for(;g.firstChild;)g.removeChild(g.firstChild);for(g.innerHTML=d.linkify.call(this,e.textContent||e.innerText||e.nodeValue),b.push.apply(b,g.childNodes);g.firstChild;)g.removeChild(g.firstChild)}else 1===e.nodeType?b.push(d.linkifyNode(e)):b.push(e);e=e.nextSibling}for(;a.firstChild;)a.removeChild(a.firstChild);for(h=0;h<b.length;h++)a.appendChild(b[h])}return a},d._dummyElement=c.createElement("div"),a.fn.linkify=function(b){return this.each(function(){var c;(c=a.data(this,"plugin-linkify"))?(c.setOptions(b),c.init()):a.data(this,"plugin-linkify",new d(this,b))})},a.fn.linkify.Constructor=d,a(b).on("load",function(){a("[data-linkify]").each(function(){var b,c=a(this),d=c.attr("data-linkify"),e={tagName:c.attr("data-linkify-tagname"),newLine:c.attr("data-linkify-newline"),target:c.attr("data-linkify-target"),linkClass:c.attr("data-linkify-linkclass")};for(var f in e)"undefined"==typeof e[f]&&delete e[f];b="this"===d?c:c.find(d),b.linkify(e)})}),a("body").on("click",".linkified",function(){var c=a(this),d=c.attr("href"),e=/^mailto:/i.test(d),f=c.attr("target");return e?b.location.href=d:b.open(d,f),!1})}(jQuery,window,document);
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue