Updated Autolinker library (Closes #532)

This commit is contained in:
RainLoop Team 2015-03-17 19:36:24 +04:00
parent 45fc261b28
commit f817a680a2
15 changed files with 3145 additions and 869 deletions

View file

@ -17,8 +17,7 @@
this.sBase = '#/';
this.sServer = './?';
this.sSubQuery = '&s=/';
this.sSubSubQuery = '&ss=/';
this.sVersion = Settings.settingsGet('Version');
this.sSpecSuffix = Settings.settingsGet('AuthAccountHash') || '0';
this.sWebPrefix = Settings.settingsGet('WebPath') || '';
@ -26,6 +25,14 @@
this.sStaticPrefix = this.sVersionPrefix + 'static/';
}
/**
* @return {string}
*/
Links.prototype.subQueryPrefix = function ()
{
return '&q[]=';
};
/**
* @return {string}
*/
@ -48,7 +55,7 @@
*/
Links.prototype.attachmentDownload = function (sDownload)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + this.sSubSubQuery + sDownload;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/Download/' + this.subQueryPrefix() + '/' + sDownload;
};
/**
@ -57,7 +64,7 @@
*/
Links.prototype.attachmentPreview = function (sDownload)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/View/' + this.sSubSubQuery + sDownload;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/View/' + this.subQueryPrefix() + '/' + sDownload;
};
/**
@ -66,7 +73,7 @@
*/
Links.prototype.attachmentThumbnailPreview = function (sDownload)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewThumbnail/' + this.sSubSubQuery + sDownload;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ViewThumbnail/' + this.subQueryPrefix() + '/' + sDownload;
};
/**
@ -75,7 +82,7 @@
*/
Links.prototype.attachmentPreviewAsPlain = function (sDownload)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + this.sSubSubQuery + sDownload;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ViewAsPlain/' + this.subQueryPrefix() + '/' + sDownload;
};
/**
@ -84,7 +91,7 @@
*/
Links.prototype.attachmentFramed = function (sDownload)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/FramedView/' + this.sSubSubQuery + sDownload;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/FramedView/' + this.subQueryPrefix() + '/' + sDownload;
};
/**
@ -92,7 +99,7 @@
*/
Links.prototype.upload = function ()
{
return this.sServer + '/Upload/' + this.sSubQuery + this.sSpecSuffix + '/';
return this.sServer + '/Upload/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/';
};
/**
@ -100,7 +107,7 @@
*/
Links.prototype.uploadContacts = function ()
{
return this.sServer + '/UploadContacts/' + this.sSubQuery + this.sSpecSuffix + '/';
return this.sServer + '/UploadContacts/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/';
};
/**
@ -108,7 +115,7 @@
*/
Links.prototype.uploadBackground = function ()
{
return this.sServer + '/UploadBackground/' + this.sSubQuery + this.sSpecSuffix + '/';
return this.sServer + '/UploadBackground/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/';
};
/**
@ -116,7 +123,7 @@
*/
Links.prototype.append = function ()
{
return this.sServer + '/Append/' + this.sSubQuery + this.sSpecSuffix + '/';
return this.sServer + '/Append/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/';
};
/**
@ -125,7 +132,7 @@
*/
Links.prototype.change = function (sEmail)
{
return this.sServer + '/Change/' + this.sSubQuery + this.sSpecSuffix + '/' + Utils.encodeURIComponent(sEmail) + '/';
return this.sServer + '/Change/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/' + Utils.encodeURIComponent(sEmail) + '/';
};
/**
@ -134,7 +141,7 @@
*/
Links.prototype.ajax = function (sAdd)
{
return this.sServer + '/Ajax/' + this.sSubQuery + this.sSpecSuffix + '/' + sAdd;
return this.sServer + '/Ajax/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/' + sAdd;
};
/**
@ -143,7 +150,7 @@
*/
Links.prototype.messageViewLink = function (sRequestHash)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ViewAsPlain/' + this.sSubSubQuery + sRequestHash;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ViewAsPlain/' + this.subQueryPrefix() + '/' + sRequestHash;
};
/**
@ -152,7 +159,7 @@
*/
Links.prototype.messageDownloadLink = function (sRequestHash)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/Download/' + this.sSubSubQuery + sRequestHash;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/Download/' + this.subQueryPrefix() + '/' + sRequestHash;
};
/**
@ -179,8 +186,8 @@
*/
Links.prototype.userBackground = function (sHash)
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/UserBackground/' +
this.sSubSubQuery + sHash;
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix +
'/UserBackground/' + this.subQueryPrefix() + '/' + sHash;
};
/**
@ -298,7 +305,7 @@
*/
Links.prototype.exportContactsVcf = function ()
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ContactsVcf/';
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ContactsVcf/';
};
/**
@ -306,7 +313,7 @@
*/
Links.prototype.exportContactsCsv = function ()
{
return this.sServer + '/Raw/' + this.sSubQuery + this.sSpecSuffix + '/ContactsCsv/';
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ContactsCsv/';
};
/**
@ -363,7 +370,7 @@
*/
Links.prototype.socialGoogle = function ()
{
return this.sServer + 'SocialGoogle' + ('' !== this.sSpecSuffix ? '/' + this.sSubQuery + this.sSpecSuffix + '/' : '');
return this.sServer + 'SocialGoogle' + ('' !== this.sSpecSuffix ? '/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/' : '');
};
/**
@ -371,7 +378,7 @@
*/
Links.prototype.socialTwitter = function ()
{
return this.sServer + 'SocialTwitter' + ('' !== this.sSpecSuffix ? '/' + this.sSubQuery + this.sSpecSuffix + '/' : '');
return this.sServer + 'SocialTwitter' + ('' !== this.sSpecSuffix ? '/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/' : '');
};
/**
@ -379,7 +386,7 @@
*/
Links.prototype.socialFacebook = function ()
{
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.sSubQuery + this.sSpecSuffix + '/' : '');
return this.sServer + 'SocialFacebook' + ('' !== this.sSpecSuffix ? '/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/' : '');
};
module.exports = new Links();

View file

@ -1062,6 +1062,7 @@
*/
Utils.findEmailAndLinks = function (sHtml)
{
// return sHtml;
sHtml = Autolinker.link(sHtml, {
'newWindow': true,
'stripPrefix': false,

View file

@ -11,6 +11,7 @@
// Utils = require('Common/Utils'),
// Base64 = require('Common/Base64'),
// Cache = require('Common/Cache'),
// Links = require('Common/Links'),
//
// AppStore = require('Stores/User/App'),
// SettingsStore = require('Stores/User/Settings'),
@ -31,8 +32,6 @@
this.messageListSimpleHash = '';
this.messageListSimpleCache = null;
this.sSubSubQuery = '&ss=/';
}
_.extend(UserAjaxUserPromises.prototype, AbstractAjaxPromises.prototype);
@ -123,7 +122,7 @@
// {
// return this.abort('Message')
// .getRequest('Message', fTrigger,
// this.sSubSubQuery + Base64.urlsafe_encode([
// Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([
// sFolderFullNameRaw, iUid,
// AppStore.projectHash(),
// AppStore.threadsAllowed() && SettingsStore.useThreads() ? '1' : '0'

View file

@ -11,6 +11,7 @@
Base64 = require('Common/Base64'),
Cache = require('Common/Cache'),
Links = require('Common/Links'),
Settings = require('Storage/Settings'),
@ -29,8 +30,6 @@
AbstractAjaxRemote.call(this);
this.oRequests = {};
this.sSubSubQuery = '&ss=/';
}
_.extend(RemoteUserAjax.prototype, AbstractAjaxRemote.prototype);
@ -352,7 +351,7 @@
{
return this.defaultRequest(fCallback, 'MessageList', {},
'' === sSearch ? Consts.Defaults.DefaultAjaxTimeout : Consts.Defaults.SearchAjaxTimeout,
'MessageList/' + this.sSubSubQuery + Base64.urlsafe_encode([
'MessageList/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([
sFolderFullNameRaw,
iOffset,
iLimit,
@ -402,7 +401,7 @@
if (Cache.getFolderFromCacheList(sFolderFullNameRaw) && 0 < iUid)
{
this.defaultRequest(fCallback, 'Message', {}, null,
'Message/' + this.sSubSubQuery + Base64.urlsafe_encode([
'Message/' + Links.subQueryPrefix() + '/' + Base64.urlsafe_encode([
sFolderFullNameRaw,
iUid,
AppStore.projectHash(),

View file

@ -372,11 +372,24 @@ class Actions
$sQuery = \trim(\trim($sQuery), ' /');
$sSubQuerty = \trim(\trim($this->Http()->GetQuery('s', '')), ' /');
$sSubSubQuerty = \trim(\trim($this->Http()->GetQuery('ss', '')), ' /');
$aSubQuery = $this->Http()->GetQuery('q', null);
if (\is_array($aSubQuery))
{
$aSubQuery = \array_map(function ($sS) {
return \trim(\trim($sS), ' /');
}, $aSubQuery);
$sQuery .= 0 < \strlen($sSubQuerty) ? '/'.$sSubQuerty : '';
$sQuery .= 0 < \strlen($sSubSubQuerty) ? '/'.$sSubSubQuerty : '';
if (0 < \count($aSubQuery))
{
$sQuery .= '/'.\implode('/', $aSubQuery);
}
}
// $sSubQuerty = \trim(\trim($this->Http()->GetQuery('s', '')), ' /');
// $sSubSubQuerty = \trim(\trim($this->Http()->GetQuery('ss', '')), ' /');
//
// $sQuery .= 0 < \strlen($sSubQuerty) ? '/'.$sSubQuerty : '';
// $sQuery .= 0 < \strlen($sSubSubQuerty) ? '/'.$sSubSubQuerty : '';
if ('' === $this->GetSpecAuthToken())
{

View file

@ -1,24 +1,28 @@
/*!
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function () {
return (root.returnExportsGlobal = factory());
});
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like enviroments that support module.exports,
// like Node.
module.exports = factory();
} else {
root['Autolinker'] = factory();
}
}(this, function () {
/*!
* Autolinker.js
* 0.12.2
* 0.15.2
*
* Copyright(c) 2014 Gregory Jacobs <greg@greg-jacobs.com>
* Copyright(c) 2015 Gregory Jacobs <greg@greg-jacobs.com>
* MIT Licensed. http://www.opensource.org/licenses/mit-license.php
*
* https://github.com/gregjacobs/Autolinker.js
*/
/*global define, module */
( function( root, factory ) {
if( typeof define === 'function' && define.amd ) {
define( factory ); // Define as AMD module if an AMD loader is present (ex: RequireJS).
} else if( typeof exports !== 'undefined' ) {
module.exports = factory(); // Define as CommonJS module for Node.js, if available.
} else {
root.Autolinker = factory(); // Finally, define as a browser global if no module loader.
}
}( this, function() {
/**
* @class Autolinker
* @extends Object
@ -112,6 +116,8 @@
*/
var Autolinker = function( cfg ) {
Autolinker.Util.assign( this, cfg ); // assign the properties of `cfg` onto the Autolinker instance. Prototype properties will be used for missing configs.
this.matchValidator = new Autolinker.MatchValidator();
};
@ -204,7 +210,7 @@
*
* Ignoring &amp; as it could be part of a query string -- handling it separately.
*/
htmlCharacterEntitiesRegex: /(&nbsp;|&#160;|&lt;|&#60;|&gt;|&#62;)/gi,
htmlCharacterEntitiesRegex: /(&nbsp;|&#160;|&lt;|&#60;|&gt;|&#62;|&quot;|&#34;|&#39;)/gi,
/**
* @private
@ -224,10 +230,12 @@
* address. Ex: 'me@my.com'
* 5. Group that matches a URL in the input text. Ex: 'http://google.com', 'www.google.com', or just 'google.com'.
* This also includes a path, url parameters, or hash anchors. Ex: google.com/path/to/file?q1=1&q2=2#myAnchor
* 6. A protocol-relative ('//') match for the case of a 'www.' prefixed URL. Will be an empty string if it is not a
* 6. Group that matches a protocol URL (i.e. 'http://google.com'). This is used to match protocol URLs with just a single
* word, like 'http://localhost', where we won't double check that the domain name has at least one '.' in it.
* 7. A protocol-relative ('//') match for the case of a 'www.' prefixed URL. Will be an empty string if it is not a
* protocol-relative match. We need to know the character before the '//' in order to determine if it is a valid match
* or the // was in a string we don't want to auto-link.
* 7. A protocol-relative ('//') match for the case of a known TLD prefixed URL. Will be an empty string if it is not a
* 8. A protocol-relative ('//') match for the case of a known TLD prefixed URL. Will be an empty string if it is not a
* protocol-relative match. See #6 for more info.
*/
matcherRegex : (function() {
@ -235,14 +243,14 @@
emailRegex = /(?:[\-;:&=\+\$,\w\.]+@)/, // something@ for email addresses (a.k.a. local-part)
protocolRegex = /(?:[A-Za-z]{3,9}:(?:\/\/)?)/, // match protocol, allow in format http:// or mailto:
protocolRegex = /(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/, // match protocol, allow in format "http://" or "mailto:". However, do not match the first part of something like 'link:http://www.google.com' (i.e. don't match "link:"). Also, make sure we don't interpret 'google.com:8000' as if 'google.com' was a protocol here (i.e. ignore a trailing port number in this regex)
wwwRegex = /(?:www\.)/, // starting with 'www.'
domainNameRegex = /[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/, // anything looking at all like a domain, non-unicode domains, not ending in a period
tldRegex = /\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/, // match our known top level domains (TLDs)
// Allow optional path, query string, and hash anchor, not ending in the following characters: "!:,.;"
// Allow optional path, query string, and hash anchor, not ending in the following characters: "?!:,.;"
// http://blog.codinghorror.com/the-problem-with-urls/
urlSuffixRegex = /(?:[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])?/; // note: optional part of the full regex
urlSuffixRegex = /[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/;
return new RegExp( [
'(', // *** Capturing group $1, which can be used to check for a twitter handle match. Use group $3 for the actual twitter handle though. $2 may be used to reconstruct the original string in a replace()
@ -263,7 +271,7 @@
'(', // *** Capturing group $5, which is used to match a URL
'(?:', // parens to cover match for protocol (optional), and domain
'(?:', // non-capturing paren for a protocol-prefixed url (ex: http://google.com)
'(', // *** Capturing group $6, for a protocol-prefixed url (ex: http://google.com)
protocolRegex.source,
domainNameRegex.source,
')',
@ -271,7 +279,7 @@
'|',
'(?:', // non-capturing paren for a 'www.' prefixed url (ex: www.google.com)
'(.?//)?', // *** Capturing group $6 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
'(.?//)?', // *** Capturing group $7 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
wwwRegex.source,
domainNameRegex.source,
')',
@ -279,33 +287,17 @@
'|',
'(?:', // non-capturing paren for known a TLD url (ex: google.com)
'(.?//)?', // *** Capturing group $7 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
'(.?//)?', // *** Capturing group $8 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
domainNameRegex.source,
tldRegex.source,
')',
')',
urlSuffixRegex.source, // match for path, query string, and/or hash anchor
'(?:' + urlSuffixRegex.source + ')?', // match for path, query string, and/or hash anchor - optional
')'
].join( "" ), 'gi' );
} )(),
/**
* @private
* @property {RegExp} invalidProtocolRelMatchRegex
*
* 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 is used in conjunction with the {@link #matcherRegex}, and checks to see if there is a word character
* before the '//' in order to determine if we should actually autolink a protocol-relative URL. This is needed because there
* 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"
*/
invalidProtocolRelMatchRegex : /^[\w]\/\//,
/**
* @private
* @property {RegExp} charBeforeProtocolRelMatchRegex
@ -318,6 +310,14 @@
*/
charBeforeProtocolRelMatchRegex : /^(.)?\/\//,
/**
* @private
* @property {Autolinker.MatchValidator} matchValidator
*
* The MatchValidator object, used to filter out any false positives from the {@link #matcherRegex}. See
* {@link Autolinker.MatchValidator} for details.
*/
/**
* @private
* @property {Autolinker.HtmlParser} htmlParser
@ -345,7 +345,8 @@
* This method finds the text around any HTML elements in the input `textOrHtml`, which will be the text that is processed.
* Any original HTML elements will be left as-is, as well as the text that is already wrapped in anchor (&lt;a&gt;) tags.
*
* @param {String} textOrHtml The HTML or text to link URLs, email addresses, and Twitter handles within.
* @param {String} textOrHtml The HTML or text to link URLs, email addresses, and Twitter handles within (depending on if
* the {@link #urls}, {@link #email}, and {@link #twitter} options are enabled).
* @return {String} The HTML, with URLs/emails/Twitter handles automatically linked.
*/
link : function( textOrHtml ) {
@ -455,32 +456,81 @@
* @return {String} The text with anchor tags auto-filled.
*/
processTextNode : function( text ) {
var me = this, // for closure
charBeforeProtocolRelMatchRegex = this.charBeforeProtocolRelMatchRegex;
return text.replace( this.matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7 ) {
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.
twitterHandle = $3, // The actual twitterUser (i.e the word after the @ sign in a Twitter handle match)
emailAddressMatch = $4, // For both determining if it is an email address, and stores the actual email address
urlMatch = $5, // The matched URL string
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
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.
match; // Will be an Autolinker.match.Match object
var me = this; // for closure
return text.replace( this.matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7, $8 ) {
var matchDescObj = me.processCandidateMatch( matchStr, $1, $2, $3, $4, $5, $6, $7, $8 ); // match description object
// Return out with no changes for match types that are disabled (url, email, twitter), or for matches that are
// invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS).
if( !me.isValidMatch( twitterMatch, emailAddressMatch, urlMatch, protocolRelativeMatch ) ) {
if( !matchDescObj ) {
return matchStr;
} else {
// Generate the replacement text for the match
var matchReturnVal = me.createMatchReturnVal( matchDescObj.match, matchDescObj.matchStr );
return matchDescObj.prefixStr + matchReturnVal + matchDescObj.suffixStr;
}
} );
},
/**
* Processes a candidate match from the {@link #matcherRegex}.
*
* Not all matches found by the regex are actual URL/email/Twitter matches, as determined by the {@link #matchValidator}. In
* this case, the method returns `null`. Otherwise, a valid Object with `prefixStr`, `match`, and `suffixStr` is returned.
*
* @private
* @param {String} matchStr The full match that was found by the {@link #matcherRegex}.
* @param {String} twitterMatch The matched text of a Twitter handle, if the match is a Twitter match.
* @param {String} twitterHandlePrefixWhitespaceChar The whitespace char before the @ sign in a Twitter handle match. This
* is needed because of no lookbehinds in JS regexes, and is need to re-include the character for the anchor tag replacement.
* @param {String} twitterHandle The actual Twitter user (i.e the word after the @ sign in a Twitter match).
* @param {String} emailAddressMatch The matched email address for an email address match.
* @param {String} urlMatch The matched URL string for a URL match.
* @param {String} protocolUrlMatch The match URL string for a protocol match. Ex: 'http://yahoo.com'. This is used to match
* something like 'http://localhost', where we won't double check that the domain name has at least one '.' in it.
* @param {String} wwwProtocolRelativeMatch The '//' for a protocol-relative match from a 'www' url, with the character that
* comes before the '//'.
* @param {String} tldProtocolRelativeMatch The '//' for a protocol-relative match from a TLD (top level domain) match, with
* the character that comes before the '//'.
*
* @return {Object} A "match description object". This will be `null` if the match was invalid, or if a match type is disabled.
* Otherwise, this will be an Object (map) with the following properties:
* @return {String} return.prefixStr The char(s) that should be prepended to the replacement string. These are char(s) that
* were needed to be included from the regex match that were ignored by processing code, and should be re-inserted into
* the replacement stream.
* @return {String} return.suffixStr The char(s) that should be appended to the replacement string. These are char(s) that
* were needed to be included from the regex match that were ignored by processing code, and should be re-inserted into
* the replacement stream.
* @return {String} return.matchStr The `matchStr`, fixed up to remove characters that are no longer needed (which have been
* added to `prefixStr` and `suffixStr`).
* @return {Autolinker.match.Match} return.match The Match object that represents the match that was found.
*/
processCandidateMatch : function(
matchStr, twitterMatch, twitterHandlePrefixWhitespaceChar, twitterHandle,
emailAddressMatch, urlMatch, protocolUrlMatch, wwwProtocolRelativeMatch, tldProtocolRelativeMatch
) {
var protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch,
match, // Will be an Autolinker.match.Match object
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.
// Return out with `null` for match types that are disabled (url, email, twitter), or for matches that are
// invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS).
if(
( twitterMatch && !this.twitter ) || ( emailAddressMatch && !this.email ) || ( urlMatch && !this.urls ) ||
!this.matchValidator.isValidMatch( urlMatch, protocolUrlMatch, protocolRelativeMatch )
) {
return null;
}
// Handle a closing parenthesis at the end of the match, and exclude it if there is not a matching open parenthesis
// in the match itself.
if( me.matchHasUnbalancedClosingParen( matchStr ) ) {
if( this.matchHasUnbalancedClosingParen( matchStr ) ) {
matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")"
suffixStr = ")"; // this will be added after the generated <a> tag
}
@ -502,7 +552,7 @@
// 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 ) {
var charBeforeMatch = protocolRelativeMatch.match( charBeforeProtocolRelMatchRegex )[ 1 ] || "";
var charBeforeMatch = protocolRelativeMatch.match( this.charBeforeProtocolRelMatchRegex )[ 1 ] || "";
if( charBeforeMatch ) { // fix up the `matchStr` if there was a preceding char before a protocol-relative match, which was needed to determine the match itself (since there are no look-behinds in JS regexes)
prefixStr = charBeforeMatch;
@ -513,52 +563,18 @@
match = new Autolinker.match.Url( {
matchedText : matchStr,
url : matchStr,
protocolRelativeMatch : protocolRelativeMatch,
stripPrefix : me.stripPrefix
protocolUrlMatch : !!protocolUrlMatch,
protocolRelativeMatch : !!protocolRelativeMatch,
stripPrefix : this.stripPrefix
} );
}
// Generate the replacement text for the match
var matchReturnVal = me.createMatchReturnVal( match, matchStr );
return prefixStr + matchReturnVal + suffixStr;
} );
},
/**
* 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
* @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;
return {
prefixStr : prefixStr,
suffixStr : suffixStr,
matchStr : matchStr,
match : match
};
},
@ -648,15 +664,15 @@
* // 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 {String} textOrHtml The HTML or text to find URLs, email addresses, and Twitter handles within (depending on if
* the {@link #urls}, {@link #email}, and {@link #twitter} options are enabled).
* @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.link = function( textOrHtml, options ) {
var autolinker = new Autolinker( options );
return autolinker.link( text );
return autolinker.link( textOrHtml );
};
@ -685,7 +701,7 @@
*
* @param {Object} dest The destination object.
* @param {Object} src The source object.
* @return {Object} The destination object.
* @return {Object} The destination object (`dest`)
*/
assign : function( dest, src ) {
for( var prop in src ) {
@ -834,34 +850,53 @@
*
* Capturing groups:
*
* 1. If it is an end tag, this group will have the '/'.
* 2. The tag name.
* 1. The "!DOCTYPE" tag name, if a tag is a &lt;!DOCTYPE&gt; tag.
* 2. If it is an end tag, this group will have the '/'.
* 3. The tag name for all tags (other than the &lt;!DOCTYPE&gt; tag)
*/
htmlRegex : (function() {
var tagNameRegex = /[0-9a-zA-Z:]+/,
var tagNameRegex = /[0-9a-zA-Z][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
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 + ')',
// for <!DOCTYPE> tag. Ex: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
'(?:',
'<(!DOCTYPE)', // *** Capturing Group 1 - If it's a doctype tag
// 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">)
// A. attr="value", or
// B. "value" alone (To cover example doctype tag: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
'(?:', nameEqualsValueRegex, '|', attrValueRegex.source + ')',
')*',
'>',
')',
'|',
// All other HTML tags (i.e. tags that are not <!DOCTYPE>)
'(?:',
'<(/)?', // Beginning of a tag. Either '<' for a start tag, or '</' for an end tag.
// *** Capturing Group 2: The slash or an empty string. Slash ('/') for end tag, empty string for start or self-closing tag.
// *** Capturing Group 3 - The tag name
'(' + tagNameRegex.source + ')',
// Zero or more attributes following the tag name
'(?:',
'\\s+', // one or more whitespace chars before an attribute
nameEqualsValueRegex, // attr="value" (with optional ="value" part)
')*',
'\\s*/?', // any trailing spaces and optional '/' before the closing '>'
'>'
].join( "" ), 'g' );
'>',
')'
].join( "" ), 'gi' );
} )(),
@ -895,15 +930,15 @@
// wrapping the URLs in anchor tags
while( ( currentResult = htmlRegex.exec( html ) ) !== null ) {
var tagText = currentResult[ 0 ],
tagName = currentResult[ 2 ],
isClosingTag = !!currentResult[ 1 ],
tagName = currentResult[ 1 ] || currentResult[ 3 ], // The <!DOCTYPE> tag (ex: "!DOCTYPE"), or another tag (ex: "a")
isClosingTag = !!currentResult[ 2 ],
inBetweenTagsText = html.substring( lastIndex, currentResult.index );
if( inBetweenTagsText ) {
processTextNodeVisitor( inBetweenTagsText );
}
processHtmlNodeVisitor( tagText, tagName, isClosingTag );
processHtmlNodeVisitor( tagText, tagName.toLowerCase(), isClosingTag );
lastIndex = currentResult.index + tagText.length;
}
@ -1266,6 +1301,175 @@
return attrsArr.join( " " );
}
} );
/*global Autolinker */
/*jshint scripturl:true */
/**
* @private
* @class Autolinker.MatchValidator
* @extends Object
*
* Used by Autolinker to filter out false positives from the {@link Autolinker#matcherRegex}.
*
* Due to the limitations of regular expressions (including the missing feature of look-behinds in JS regular expressions),
* we cannot always determine the validity of a given match. This class applies a bit of additional logic to filter out any
* false positives that have been matched by the {@link Autolinker#matcherRegex}.
*/
Autolinker.MatchValidator = Autolinker.Util.extend( Object, {
/**
* @private
* @property {RegExp} invalidProtocolRelMatchRegex
*
* The regular expression used to check a potential protocol-relative URL match, coming from the
* {@link Autolinker#matcherRegex}. A protocol-relative URL is, for example, "//yahoo.com"
*
* This regular expression checks to see if there is a word character before the '//' match in order to determine if
* we should actually autolink a protocol-relative URL. This is needed because there is no negative look-behind in
* JavaScript regular expressions.
*
* For instance, we want to autolink something like "Go to: //google.com", but we don't want to autolink something
* like "abc//google.com"
*/
invalidProtocolRelMatchRegex : /^[\w]\/\//,
/**
* Regex to test for a full protocol, with the two trailing slashes. Ex: 'http://'
*
* @private
* @property {RegExp} hasFullProtocolRegex
*/
hasFullProtocolRegex : /^[A-Za-z][-.+A-Za-z0-9]+:\/\//,
/**
* Regex to find the URI scheme, such as 'mailto:'.
*
* This is used to filter out 'javascript:' and 'vbscript:' schemes.
*
* @private
* @property {RegExp} uriSchemeRegex
*/
uriSchemeRegex : /^[A-Za-z][-.+A-Za-z0-9]+:/,
/**
* Regex to determine if at least one word char exists after the protocol (i.e. after the ':')
*
* @private
* @property {RegExp} hasWordCharAfterProtocolRegex
*/
hasWordCharAfterProtocolRegex : /:[^\s]*?[A-Za-z]/,
/**
* Determines if a given match found by {@link Autolinker#processTextNode} is valid. Will return `false` for:
*
* 1) URL matches which do not have at least have one period ('.') in the domain name (effectively skipping over
* matches like "abc:def"). However, URL matches with a protocol will be allowed (ex: 'http://localhost')
* 2) URL matches which do not have at least one word character in the domain name (effectively skipping over
* matches like "git:1.0").
* 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`.
*
* @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} protocolUrlMatch The match URL string for a protocol match. Ex: 'http://yahoo.com'. This is used to match
* something like 'http://localhost', where we won't double check that the domain name has at least one '.' in it.
* @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.
*/
isValidMatch : function( urlMatch, protocolUrlMatch, protocolRelativeMatch ) {
if(
( protocolUrlMatch && !this.isValidUriScheme( protocolUrlMatch ) ) ||
this.urlMatchDoesNotHaveProtocolOrDot( urlMatch, protocolUrlMatch ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL, *unless* it was a full protocol match (like 'http://localhost')
this.urlMatchDoesNotHaveAtLeastOneWordChar( urlMatch, protocolUrlMatch ) || // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
this.isInvalidProtocolRelativeMatch( 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;
},
/**
* Determines if the URI scheme is a valid scheme to be autolinked. Returns `false` if the scheme is
* 'javascript:' or 'vbscript:'
*
* @private
* @param {String} uriSchemeMatch The match URL string for a full URI scheme match. Ex: 'http://yahoo.com'
* or 'mailto:a@a.com'.
* @return {Boolean} `true` if the scheme is a valid one, `false` otherwise.
*/
isValidUriScheme : function( uriSchemeMatch ) {
var uriScheme = uriSchemeMatch.match( this.uriSchemeRegex )[ 0 ];
return ( uriScheme !== 'javascript:' && uriScheme !== 'vbscript:' );
},
/**
* Determines if a URL match does not have either:
*
* a) a full protocol (i.e. 'http://'), or
* b) at least one dot ('.') in the domain name (for a non-full-protocol match).
*
* Either situation is considered an invalid URL (ex: 'git:d' does not have either the '://' part, or at least one dot
* in the domain name. If the match was 'git:abc.com', we would consider this valid.)
*
* @private
* @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} protocolUrlMatch The match URL string for a protocol match. Ex: 'http://yahoo.com'. This is used to match
* something like 'http://localhost', where we won't double check that the domain name has at least one '.' in it.
* @return {Boolean} `true` if the URL match does not have a full protocol, or at least one dot ('.') in a non-full-protocol
* match.
*/
urlMatchDoesNotHaveProtocolOrDot : function( urlMatch, protocolUrlMatch ) {
return ( !!urlMatch && ( !protocolUrlMatch || !this.hasFullProtocolRegex.test( protocolUrlMatch ) ) && urlMatch.indexOf( '.' ) === -1 );
},
/**
* Determines if a URL match does not have at least one word character after the protocol (i.e. in the domain name).
*
* At least one letter character must exist in the domain name after a protocol match. Ex: skip over something
* like "git:1.0"
*
* @private
* @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} protocolUrlMatch The match URL string for a protocol match. Ex: 'http://yahoo.com'. This is used to
* know whether or not we have a protocol in the URL string, in order to check for a word character after the protocol
* separator (':').
* @return {Boolean} `true` if the URL match does not have at least one word character in it after the protocol, `false`
* otherwise.
*/
urlMatchDoesNotHaveAtLeastOneWordChar : function( urlMatch, protocolUrlMatch ) {
if( urlMatch && protocolUrlMatch ) {
return !this.hasWordCharAfterProtocolRegex.test( urlMatch );
} else {
return false;
}
},
/**
* Determines if a protocol-relative match is an invalid one. This method returns `true` if there is a `protocolRelativeMatch`,
* and that match contains a word character before the '//' (i.e. it must contain whitespace or nothing before the '//' in
* order to be considered valid).
*
* @private
* @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 it is an invalid protocol-relative match, `false` otherwise.
*/
isInvalidProtocolRelativeMatch : function( protocolRelativeMatch ) {
return ( !!protocolRelativeMatch && this.invalidProtocolRelMatchRegex.test( protocolRelativeMatch ) );
}
} );
/*global Autolinker */
/*jshint sub:true */
@ -1628,6 +1832,13 @@
* The url that was matched.
*/
/**
* @cfg {Boolean} protocolUrlMatch (required)
*
* `true` if the URL is a match which already has a protocol (i.e. 'http://'), `false` if the match was from a 'www' or
* known TLD match.
*/
/**
* @cfg {Boolean} protocolRelativeMatch (required)
*
@ -1637,7 +1848,7 @@
/**
* @cfg {Boolean} stripPrefix (required)
* @inheritdoc {@link Autolinker#stripPrefix}
* @inheritdoc Autolinker#stripPrefix
*/
@ -1659,13 +1870,13 @@
protocolRelativeRegex : /^\/\//,
/**
* @protected
* @property {RegExp} checkForProtocolRegex
* @private
* @property {Boolean} protocolPrepended
*
* A regular expression used to check if the {@link #url} is missing a protocol (in which case, 'http://'
* will be added).
* Will be set to `true` if the 'http://' protocol has been prepended to the {@link #url} (because the
* {@link #url} did not have a protocol)
*/
checkForProtocolRegex: /^[A-Za-z]{3,9}:/,
protocolPrepended : false,
/**
@ -1679,17 +1890,19 @@
/**
* Returns the url that was matched, assuming the protocol to be 'http://' if the match
* was missing a protocol.
* Returns the url that was matched, assuming the protocol to be 'http://' if the original
* 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 ) ) {
// if the url string doesn't begin with a protocol, assume 'http://'
if( !this.protocolRelativeMatch && !this.protocolUrlMatch && !this.protocolPrepended ) {
url = this.url = 'http://' + url;
this.protocolPrepended = true;
}
return url;
@ -1778,4 +1991,5 @@
return Autolinker;
} ) );
}));

File diff suppressed because one or more lines are too long

View file

@ -50,13 +50,13 @@ JavaScript:
```javascript
var Autolinker = require( 'autolinker' );
// note: npm wants an all-lowercase package name, but the utility is a class and should be
// aliased with a captial letter
// aliased with a capital letter
```
## Usage
Using the static `link()` method:
Using the static [link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-static-method-link) method:
```javascript
var linkedText = Autolinker.link( textToAutolink[, options] );
@ -71,7 +71,7 @@ var linkedText = autolinker.link( textToAutoLink );
```
Note: if using the same options to autolink multiple pieces of html/text, it is slightly more efficient to create a single
Autolinker instance, and run the `link()` method repeatedly (i.e. use the "class" form above).
Autolinker instance, and run the [link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-method-link) method repeatedly (i.e. use the "class" form above).
#### Example:
@ -83,16 +83,16 @@ var linkedText = Autolinker.link( "Check out google.com", { className: "myLink"
## Options
These are the options which may be specified for linking. These are specified by providing an Object as the second parameter to `Autolinker.link()`. These include:
These are the options which may be specified for linking. These are specified by providing an Object as the second parameter to [Autolinker.link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-static-method-link). These include:
- **newWindow** : Boolean<br />
- [newWindow](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-newWindow) : Boolean<br />
`true` to have the links should open in a new window when clicked, `false` otherwise. Defaults to `true`.<br /><br />
- **stripPrefix** : Boolean<br />
- [stripPrefix](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-stripPrefix) : Boolean<br />
`true` to have the 'http://' or 'https://' and/or the 'www.' stripped from the beginning of links, `false` otherwise. Defaults to `true`.<br /><br />
- **truncate** : Number<br />
- [truncate](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-truncate) : Number<br />
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 the number of characters, it will be truncated to this length by replacing the end of the string with a two period ellipsis ('..').<br /><br />
Example: a url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters may look like this: 'yahoo.com/some/long/pat..'<br />
- **className** : String<br />
Example: a url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters may look like this: 'yahoo.com/some/long/pat..'<br /><br />
- [className](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-className) : String<br />
A CSS class name to add to the generated anchor tags. This class will be added to all links, as well as this class
plus "url"/"email"/"twitter" suffixes for styling url/email/twitter links differently.
@ -102,18 +102,18 @@ These are the options which may be specified for linking. These are specified by
2) Email links will have the CSS classes: "myLink myLink-email", and<br />
3) Twitter links will have the CSS classes: "myLink myLink-twitter"<br />
- **urls** : Boolean<br />
- [urls](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-urls) : Boolean<br />
`true` to have URLs auto-linked, `false` to skip auto-linking of URLs. Defaults to `true`.<br />
- **email** : Boolean<br />
- [email](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-email) : Boolean<br />
`true` to have email addresses auto-linked, `false` to skip auto-linking of email addresses. Defaults to `true`.<br /><br />
- **twitter** : Boolean<br />
`true` to have Twitter handles auto-linked, `false` to skip auto-linking of Twitter handles. Defaults to `true`.
- **replaceFn** : Function<br />
- [twitter](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-twitter) : Boolean<br />
`true` to have Twitter handles auto-linked, `false` to skip auto-linking of Twitter handles. Defaults to `true`.<br /><br />
- [replaceFn](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-replaceFn) : Function<br />
A function to use to programmatically make replacements of matches in the input string, one at a time. See the section
<a href="#custom-replacement-function">Custom Replacement Function</a> for more details.
For example, if you wanted to disable links from opening in new windows, you could do:
For example, if you wanted to disable links from opening in [new windows](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-newWindow), you could do:
```javascript
var linkedText = Autolinker.link( "Check out google.com", { newWindow: false } );
@ -135,7 +135,7 @@ var myTextEl = document.getElementById( 'text' );
myTextEl.innerHTML = Autolinker.link( myTextEl.innerHTML );
```
Using the same pre-configured Autolinker instance in multiple locations of a codebase (usually by dependency injection):
Using the same pre-configured [Autolinker](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker) instance in multiple locations of a codebase (usually by dependency injection):
```javascript
var autolinker = new Autolinker( { newWindow: false, truncate: 25 } );
@ -155,7 +155,7 @@ autolinker.link( "Go to www.google.com" );
## Custom Replacement Function
A custom replacement function (`replaceFn`) may be provided to replace url/email/twitter matches on an individual basis, based
A custom replacement function ([replaceFn](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-replaceFn)) may be provided to replace url/email/twitter matches on an individual basis, based
on the return from this function.
Full example, for purposes of documenting the API:
@ -207,8 +207,8 @@ var linkedText = Autolinker.link( input, {
The function is provided two arguments:
1. The Autolinker instance that is performing replacements. This can be used to query the options that the Autolinker
instance is configured with, or to retrieve its TagBuilder instance (via `autolinker.getTagBuilder()`).
2. An `Autolinker.match.Match` object which details the match that is to be replaced.
instance is configured with, or to retrieve its TagBuilder instance (via [autolinker.getTagBuilder()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-method-getTagBuilder)).
2. An [Autolinker.match.Match](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker.match.Match) object which details the match that is to be replaced.
A replacement of the match is made based on the return value of the function. The following return values may be provided:
@ -217,7 +217,7 @@ A replacement of the match is made based on the return value of the function. Th
- `false` (Boolean): Do not replace the current match at all - leave as-is.
- Any String: If a string is returned from the function, the string will be used directly as the replacement HTML for
the match.
- An `Autolinker.HtmlTag` instance, which can be used to build/modify an HTML tag before writing out its HTML text.
- An [Autolinker.HtmlTag](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker.HtmlTag) instance, which can be used to build/modify an HTML tag before writing out its HTML text.
## Full API Docs
@ -225,126 +225,6 @@ A replacement of the match is made based on the return value of the function. Th
The full API docs for Autolinker may be referenced at: [http://gregjacobs.github.io/Autolinker.js/docs/](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker)
## Changelog:
## Changelog
### 0.12.3
- Add `Autolinker.match.Match#getMatchedText` method
### 0.12.2
- Add documentation generation, and update inline documentation.
### 0.12.1
- Expose the `Autolinker.HtmlTag` class, and allow it to be used in the `replaceFn`
### 0.12.0
- Add `replaceFn` option
### 0.11.0
- Allow Autolinker to link fully-capitalized URLs/Emails/Twitter handles.
### 0.10.1
- Added fix to not autolink strings like "version:1.0", which were accidentally being interpreted as a protocol:domain string.
### 0.10.0
- Added support for protocol-relative URLs (ex: `//google.com`, which will effectively either have the `http://` or `https://`
protocol depending on the protocol that is hosting the website)
### 0.9.4
- Fixed an issue where a string in the form of `abc:def` would be autolinked as a protocol and domain name URL. Autolinker now
requires the domain name to have at least one period in it to be considered.
### 0.9.3
- Fixed an issue where Twitter handles wouldn't be autolinked if they existed as the sole entity within parenthesis or brackets
(thanks [@busticated](https://github.com/busticated) for pointing this out and providing unit tests)
### 0.9.2
- Fixed an issue with nested tags within an existing &lt;a&gt; tag, where the nested tags' inner text would be accidentally
removed from the output (thanks [@mjsabin01](https://github.com/mjsabin01))
### 0.9.1
- Added a patch to attempt to better handle extraneous &lt;/a&gt; tags in the input string if any exist. This is for when the
input may have some invalid markup (for instance, on sites which allow user comments, blog posts, etc.).
### 0.9.0
- Added better support for the processing of existing HTML in the input string. Now handles namespaced tags, and attribute names
with dashes or any other Unicode character (thanks [@aziraphale](https://github.com/aziraphale))
### 0.8.0
- Added `className` option for easily styling produced links (thanks [@busticated](https://github.com/busticated))
- Refactored into a JS class. Autolinker can now be instantiated using:
```javascript
var autolinker = new Autolinker( { newWindow: false, truncate: 25 } );
autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" );
// Produces: "Check out <a href="http://www.yahoo.com/some/long/path/to/a/file">yahoo.com/some/long/pat..</a>"
```
This allows options to be set on a single instance, and used throughout a codebase by injecting the `autolinker` instance as a dependency to the modules/classes that use it. (Note: Autolinker may still be used with the static `Autolinker.link()` method as was previously available as well.)
### 0.7.0
- Changed build system to Grunt.
- Added AMD and CommonJS module loading support (ex: RequireJS, and Node.js's module loader).
- Added command line Jasmine test runner (`grunt test`)
- Upgraded Jasmine from 1.3.1 to 2.0
- Added license header to dist files.
(Thanks to [@busticated](https://github.com/busticated)!)
### 0.6.1
- Added LICENSE file to repository.
### 0.6.0
- Added options for granular control of which types are linked (urls, email addresses, and/or twitter handles).
(thanks [@aziraphale](https://github.com/aziraphale))
### 0.5.0
- Simplified the path / query string / hash processing into a single regular expression instead of 3 separate ones.
- Added support for parenthesis in URLs, such as: `en.wikipedia.org/wiki/IANA_(disambiguation)` (thanks [@dandv](https://github.com/dandv))
- Add all known top-level domains (TLDs) (thanks [@wouter0100](https://github.com/wouter0100))
### 0.4.0
Merged pull requests from [@afeld](https://github.com/afeld):
- strip protocol and 'www.' by default - fixes #1
- truncate URLs from the end
- make simpler regex for detecting prefix
- remove trailing slashes from URLs, and handle periods at the end of paths
- re-use domain+TLD regexes for email matching
- add .me and .io to list of TLDs
Thanks Aidan :)
### 0.3.1
- Fixed an issue with handling nested HTML tags within anchor tags.
### 0.3
- Implemented the `truncate` option.
### 0.2
- Implemented autolinking Twitter handles.
### 0.1
* Initial implementation, which autolinks URLs and email addresses. Working on linking Twitter handles.
See [Releases](https://github.com/gregjacobs/Autolinker.js/releases)

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -70,6 +70,9 @@ var autolinker = new Autolinker( [ options ] );
var linkedText = autolinker.link( textToAutoLink );
```
Note: if using the same options to autolink multiple pieces of html/text, it is slightly more efficient to create a single
Autolinker instance, and run the `link()` method repeatedly (i.e. use the "class" form above).
#### Example:
@ -105,6 +108,10 @@ These are the options which may be specified for linking. These are specified by
`true` to have email addresses auto-linked, `false` to skip auto-linking of email addresses. Defaults to `true`.<br /><br />
- **twitter** : Boolean<br />
`true` to have Twitter handles auto-linked, `false` to skip auto-linking of Twitter handles. Defaults to `true`.
- **replaceFn** : Function<br />
A function to use to programmatically make replacements of matches in the input string, one at a time. See the section
<a href="#custom-replacement-function">Custom Replacement Function</a> for more details.
For example, if you wanted to disable links from opening in new windows, you could do:
@ -146,8 +153,96 @@ autolinker.link( "Go to www.google.com" );
```
## Custom Replacement Function
A custom replacement function (`replaceFn`) may be provided to replace url/email/twitter matches on an individual basis, based
on the return from this function.
Full example, for purposes of documenting the API:
```javascript
var input = "..."; // string with URLs, Email Addresses, and Twitter Handles
var linkedText = Autolinker.link( input, {
replaceFn : function( autolinker, match ) {
console.log( "href = ", match.getAnchorHref() );
console.log( "text = ", match.getAnchorText() );
switch( match.getType() ) {
case 'url' :
console.log( "url: ", match.getUrl() );
if( match.getUrl().indexOf( 'mysite.com' ) === -1 ) {
var tag = autolinker.getTagBuilder().build( match ); // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes
tag.setAttr( 'rel', 'nofollow' );
tag.addClass( 'external-link' );
return tag;
} else {
return true; // let Autolinker perform its normal anchor tag replacement
}
case 'email' :
var email = match.getEmail();
console.log( "email: ", email );
if( email === "my@own.address" ) {
return false; // don't auto-link this particular email address; leave as-is
} else {
return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`)
}
case 'twitter' :
var twitterHandle = match.getTwitterHandle();
console.log( twitterHandle );
return '<a href="http://newplace.to.link.twitter.handles.to/">' + twitterHandle + '</a>';
}
}
} );
```
The function is provided two arguments:
1. The Autolinker instance that is performing replacements. This can be used to query the options that the Autolinker
instance is configured with, or to retrieve its TagBuilder instance (via `autolinker.getTagBuilder()`).
2. An `Autolinker.match.Match` object which details the match that is to be replaced.
A replacement of the match is made based on the return value of the function. The following return values may be provided:
- No return value (`undefined`), or `true` (Boolean): Delegate back to Autolinker to replace the match as it normally would.
- `false` (Boolean): Do not replace the current match at all - leave as-is.
- Any String: If a string is returned from the function, the string will be used directly as the replacement HTML for
the match.
- An `Autolinker.HtmlTag` instance, which can be used to build/modify an HTML tag before writing out its HTML text.
## Full API Docs
The full API docs for Autolinker may be referenced at: [http://gregjacobs.github.io/Autolinker.js/docs/](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker)
## Changelog:
### 0.12.3
- Add `Autolinker.match.Match#getMatchedText` method
### 0.12.2
- Add documentation generation, and update inline documentation.
### 0.12.1
- Expose the `Autolinker.HtmlTag` class, and allow it to be used in the `replaceFn`
### 0.12.0
- Add `replaceFn` option
### 0.11.0
- Allow Autolinker to link fully-capitalized URLs/Emails/Twitter handles.

1020
vendors/Autolinker/_/_/Autolinker.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

22
vendors/Autolinker/_/_/LICENSE vendored Normal file
View file

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2014 Gregory Jacobs (http://greg-jacobs.com)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

255
vendors/Autolinker/_/_/README.md vendored Normal file
View file

@ -0,0 +1,255 @@
# Autolinker.js
Because I had so much trouble finding a good autolinking implementation out in the wild, I decided to roll my own. It
seemed that everything I found out there was either an implementation that didn't cover every case, or was just limited
in one way or another.
So, this utility attempts to handle everything. It:
- Autolinks URLs, whether or not they start with the protocol (i.e. 'http://'). In other words, it will automatically link the
text "google.com", as well as "http://google.com".
- Will properly handle URLs with special characters
- Will properly handle URLs with query parameters or a named anchor (i.e. hash)
- Will autolink email addresses.
- Will autolink Twitter handles.
- Will properly handle HTML input. The utility will not change the `href` attribute inside anchor (&lt;a&gt;) tags (or any other
tag/attribute for that matter), and will not accidentally wrap the inner text of an anchor tag with a new one (which would cause
doubly-nested anchor tags).
Hope that this utility helps you as well!
## Installation
#### Download
Simply clone or download the zip of the project, and link to either `dist/Autolinker.js` or `dist/Autolinker.min.js` with a script tag:
```html
<script src="path/to/Autolinker.min.js"></script>
```
#### Using with the [Bower](http://bower.io) package manager:
Command line:
```shell
bower install Autolinker.js --save
```
#### Using with [Node.js](http://nodejs.org) via [npm](https://www.npmjs.org/):
Command Line:
```shell
npm install autolinker --save
```
JavaScript:
```javascript
var Autolinker = require( 'autolinker' );
// note: npm wants an all-lowercase package name, but the utility is a class and should be
// aliased with a captial letter
```
## Usage
Using the static `link()` method:
```javascript
var linkedText = Autolinker.link( textToAutolink[, options] );
```
Using as a class:
```javascript
var autolinker = new Autolinker( [ options ] );
var linkedText = autolinker.link( textToAutoLink );
```
#### Example:
```javascript
var linkedText = Autolinker.link( "Check out google.com", { className: "myLink" } );
// Produces: "Check out <a class="myLink myLink-url" href="http://google.com" target="_blank">google.com</a>"
```
## Options
These are the options which may be specified for linking. These are specified by providing an Object as the second parameter to `Autolinker.link()`. These include:
- **newWindow** : Boolean<br />
`true` to have the links should open in a new window when clicked, `false` otherwise. Defaults to `true`.<br /><br />
- **stripPrefix** : Boolean<br />
`true` to have the 'http://' or 'https://' and/or the 'www.' stripped from the beginning of links, `false` otherwise. Defaults to `true`.<br /><br />
- **truncate** : Number<br />
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 the number of characters, it will be truncated to this length by replacing the end of the string with a two period ellipsis ('..').<br /><br />
Example: a url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters may look like this: 'yahoo.com/some/long/pat..'<br />
- **className** : String<br />
A CSS class name to add to the generated anchor tags. This class will be added to all links, as well as this class
plus "url"/"email"/"twitter" suffixes for styling url/email/twitter links differently.
For example, if this config is provided as "myLink", then:
1) URL links will have the CSS classes: "myLink myLink-url"<br />
2) Email links will have the CSS classes: "myLink myLink-email", and<br />
3) Twitter links will have the CSS classes: "myLink myLink-twitter"<br />
- **urls** : Boolean<br />
`true` to have URLs auto-linked, `false` to skip auto-linking of URLs. Defaults to `true`.<br />
- **email** : Boolean<br />
`true` to have email addresses auto-linked, `false` to skip auto-linking of email addresses. Defaults to `true`.<br /><br />
- **twitter** : Boolean<br />
`true` to have Twitter handles auto-linked, `false` to skip auto-linking of Twitter handles. Defaults to `true`.
For example, if you wanted to disable links from opening in new windows, you could do:
```javascript
var linkedText = Autolinker.link( "Check out google.com", { newWindow: false } );
// Produces: "Check out <a href="http://google.com">google.com</a>"
```
And if you wanted to truncate the length of URLs (while also not opening in a new window), you could do:
```javascript
var linkedText = Autolinker.link( "http://www.yahoo.com/some/long/path/to/a/file", { truncate: 25, newWindow: false } );
// Produces: "<a href="http://www.yahoo.com/some/long/path/to/a/file">yahoo.com/some/long/pat..</a>"
```
## More Examples
One could update an entire DOM element that has unlinked text to auto-link them as such:
```javascript
var myTextEl = document.getElementById( 'text' );
myTextEl.innerHTML = Autolinker.link( myTextEl.innerHTML );
```
Using the same pre-configured Autolinker instance in multiple locations of a codebase (usually by dependency injection):
```javascript
var autolinker = new Autolinker( { newWindow: false, truncate: 25 } );
//...
autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" );
// Produces: "Check out <a href="http://www.yahoo.com/some/long/path/to/a/file">yahoo.com/some/long/pat..</a>"
//...
autolinker.link( "Go to www.google.com" );
// Produces: "Go to <a href="http://www.google.com">google.com</a>"
```
## Changelog:
### 0.11.0
- Allow Autolinker to link fully-capitalized URLs/Emails/Twitter handles.
### 0.10.1
- Added fix to not autolink strings like "version:1.0", which were accidentally being interpreted as a protocol:domain string.
### 0.10.0
- Added support for protocol-relative URLs (ex: `//google.com`, which will effectively either have the `http://` or `https://`
protocol depending on the protocol that is hosting the website)
### 0.9.4
- Fixed an issue where a string in the form of `abc:def` would be autolinked as a protocol and domain name URL. Autolinker now
requires the domain name to have at least one period in it to be considered.
### 0.9.3
- Fixed an issue where Twitter handles wouldn't be autolinked if they existed as the sole entity within parenthesis or brackets
(thanks [@busticated](https://github.com/busticated) for pointing this out and providing unit tests)
### 0.9.2
- Fixed an issue with nested tags within an existing &lt;a&gt; tag, where the nested tags' inner text would be accidentally
removed from the output (thanks [@mjsabin01](https://github.com/mjsabin01))
### 0.9.1
- Added a patch to attempt to better handle extraneous &lt;/a&gt; tags in the input string if any exist. This is for when the
input may have some invalid markup (for instance, on sites which allow user comments, blog posts, etc.).
### 0.9.0
- Added better support for the processing of existing HTML in the input string. Now handles namespaced tags, and attribute names
with dashes or any other Unicode character (thanks [@aziraphale](https://github.com/aziraphale))
### 0.8.0
- Added `className` option for easily styling produced links (thanks [@busticated](https://github.com/busticated))
- Refactored into a JS class. Autolinker can now be instantiated using:
```javascript
var autolinker = new Autolinker( { newWindow: false, truncate: 25 } );
autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" );
// Produces: "Check out <a href="http://www.yahoo.com/some/long/path/to/a/file">yahoo.com/some/long/pat..</a>"
```
This allows options to be set on a single instance, and used throughout a codebase by injecting the `autolinker` instance as a dependency to the modules/classes that use it. (Note: Autolinker may still be used with the static `Autolinker.link()` method as was previously available as well.)
### 0.7.0
- Changed build system to Grunt.
- Added AMD and CommonJS module loading support (ex: RequireJS, and Node.js's module loader).
- Added command line Jasmine test runner (`grunt test`)
- Upgraded Jasmine from 1.3.1 to 2.0
- Added license header to dist files.
(Thanks to [@busticated](https://github.com/busticated)!)
### 0.6.1
- Added LICENSE file to repository.
### 0.6.0
- Added options for granular control of which types are linked (urls, email addresses, and/or twitter handles).
(thanks [@aziraphale](https://github.com/aziraphale))
### 0.5.0
- Simplified the path / query string / hash processing into a single regular expression instead of 3 separate ones.
- Added support for parenthesis in URLs, such as: `en.wikipedia.org/wiki/IANA_(disambiguation)` (thanks [@dandv](https://github.com/dandv))
- Add all known top-level domains (TLDs) (thanks [@wouter0100](https://github.com/wouter0100))
### 0.4.0
Merged pull requests from [@afeld](https://github.com/afeld):
- strip protocol and 'www.' by default - fixes #1
- truncate URLs from the end
- make simpler regex for detecting prefix
- remove trailing slashes from URLs, and handle periods at the end of paths
- re-use domain+TLD regexes for email matching
- add .me and .io to list of TLDs
Thanks Aidan :)
### 0.3.1
- Fixed an issue with handling nested HTML tags within anchor tags.
### 0.3
- Implemented the `truncate` option.
### 0.2
- Implemented autolinking Twitter handles.
### 0.1
* Initial implementation, which autolinks URLs and email addresses. Working on linking Twitter handles.