/** * @class Autolinker * @extends Object * * Utility class used to process a given string of text, and wrap the matches in * the appropriate anchor (<a>) tags to turn them into links. * * Any of the configuration options may be provided in an Object (map) provided * to the Autolinker constructor, which will configure how the {@link #link link()} * method will process the links. * * For example: * * var autolinker = new Autolinker( { * newWindow : false, * truncate : 30 * } ); * * var html = autolinker.link( "Joe went to www.yahoo.com" ); * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>' * * * The {@link #static-link static link()} method may also be used to inline * options into a single call, which may be more convenient for one-off uses. * For example: * * var html = Autolinker.link( "Joe went to www.yahoo.com", { * newWindow : false, * truncate : 30 * } ); * // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>' * * * ## Custom Replacements of Links * * If the configuration options do not provide enough flexibility, a {@link #replaceFn} * may be provided to fully customize the output of Autolinker. This function is * called once for each URL/Email/Phone#/Hashtag/Mention (Twitter, Instagram) * match that is encountered. * * For example: * * var input = "..."; // string with URLs, Email Addresses, Phone #s, Hashtags, and Mentions (Twitter, Instagram) * * var linkedText = Autolinker.link( input, { * replaceFn : function( 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 = match.buildTag(); // 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 'phone' : * var phoneNumber = match.getPhoneNumber(); * console.log( phoneNumber ); * * return '<a href="http://newplace.to.link.phone.numbers.to/">' + phoneNumber + '</a>'; * * case 'hashtag' : * var hashtag = match.getHashtag(); * console.log( hashtag ); * * return '<a href="http://newplace.to.link.hashtag.handles.to/">' + hashtag + '</a>'; * * case 'mention' : * var mention = match.getMention(); * console.log( mention ); * * return '<a href="http://newplace.to.link.mention.to/">' + mention + '</a>'; * } * } * } ); * * * The function may return the following values: * * - `true` (Boolean): Allow 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 {@link Autolinker.HtmlTag} instance, which can be used to build/modify * an HTML tag before writing out its HTML text. * * @constructor * @param {Object} [cfg] The configuration options for the Autolinker instance, * specified in an Object (map). */ var Autolinker = function( cfg ) { cfg = cfg || {}; this.version = Autolinker.version; this.urls = this.normalizeUrlsCfg( cfg.urls ); this.email = typeof cfg.email === 'boolean' ? cfg.email : true; this.phone = typeof cfg.phone === 'boolean' ? cfg.phone : true; this.hashtag = cfg.hashtag || false; this.mention = cfg.mention || false; this.newWindow = typeof cfg.newWindow === 'boolean' ? cfg.newWindow : true; this.stripPrefix = this.normalizeStripPrefixCfg( cfg.stripPrefix ); this.stripTrailingSlash = typeof cfg.stripTrailingSlash === 'boolean' ? cfg.stripTrailingSlash : true; // Validate the value of the `mention` cfg var mention = this.mention; if( mention !== false && mention !== 'twitter' && mention !== 'instagram' ) { throw new Error( "invalid `mention` cfg - see docs" ); } // Validate the value of the `hashtag` cfg var hashtag = this.hashtag; if( hashtag !== false && hashtag !== 'twitter' && hashtag !== 'facebook' && hashtag !== 'instagram' ) { throw new Error( "invalid `hashtag` cfg - see docs" ); } this.truncate = this.normalizeTruncateCfg( cfg.truncate ); this.className = cfg.className || ''; this.replaceFn = cfg.replaceFn || null; this.context = cfg.context || this; this.htmlParser = null; this.matchers = null; this.tagBuilder = null; }; /** * Automatically links URLs, Email addresses, Phone Numbers, Twitter handles, * Hashtags, and Mentions 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 * @param {String} textOrHtml The HTML or text to find matches within (depending * on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #mention}, * {@link #hashtag}, and {@link #mention} 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 matches automatically linked. */ Autolinker.link = function( textOrHtml, options ) { var autolinker = new Autolinker( options ); return autolinker.link( textOrHtml ); }; /** * Parses the input `textOrHtml` looking for URLs, email addresses, phone * numbers, username handles, and hashtags (depending on the configuration * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} * objects describing those matches (without making any replacements). * * Note that if parsing multiple pieces of text, it is slightly more efficient * to create an Autolinker instance, and use the instance-level {@link #parse} * method. * * Example: * * var matches = Autolinker.parse( "Hello google.com, I am asdf@asdf.com", { * urls: true, * email: true * } ); * * console.log( matches.length ); // 2 * console.log( matches[ 0 ].getType() ); // 'url' * console.log( matches[ 0 ].getUrl() ); // 'google.com' * console.log( matches[ 1 ].getType() ); // 'email' * console.log( matches[ 1 ].getEmail() ); // 'asdf@asdf.com' * * @static * @param {String} textOrHtml The HTML or text to find matches within * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, * {@link #hashtag}, and {@link #mention} 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 {Autolinker.match.Match[]} The array of Matches found in the * given input `textOrHtml`. */ Autolinker.parse = function( textOrHtml, options ) { var autolinker = new Autolinker( options ); return autolinker.parse( textOrHtml ); }; /** * @static * @property {String} version (readonly) * * The Autolinker version number in the form major.minor.patch * * Ex: 0.25.1 */ Autolinker.version = '/* @echo VERSION */'; Autolinker.prototype = { constructor : Autolinker, // fix constructor property /** * @cfg {Boolean/Object} [urls] * * `true` if URLs should be automatically linked, `false` if they should not * be. Defaults to `true`. * * Examples: * * urls: true * * // or * * urls: { * schemeMatches : true, * wwwMatches : true, * tldMatches : true * } * * As shown above, this option also accepts an Object form with 3 properties * to allow for more customization of what exactly gets linked. All default * to `true`: * * @cfg {Boolean} [urls.schemeMatches] `true` to match URLs found prefixed * with a scheme, i.e. `http://google.com`, or `other+scheme://google.com`, * `false` to prevent these types of matches. * @cfg {Boolean} [urls.wwwMatches] `true` to match urls found prefixed with * `'www.'`, i.e. `www.google.com`. `false` to prevent these types of * matches. Note that if the URL had a prefixed scheme, and * `schemeMatches` is true, it will still be linked. * @cfg {Boolean} [urls.tldMatches] `true` to match URLs with known top * level domains (.com, .net, etc.) that are not prefixed with a scheme or * `'www.'`. This option attempts to match anything that looks like a URL * in the given text. Ex: `google.com`, `asdf.org/?page=1`, etc. `false` * to prevent these types of matches. */ /** * @cfg {Boolean} [email=true] * * `true` if email addresses should be automatically linked, `false` if they * should not be. */ /** * @cfg {Boolean} [phone=true] * * `true` if Phone numbers ("(555)555-5555") should be automatically linked, * `false` if they should not be. */ /** * @cfg {Boolean/String} [hashtag=false] * * A string for the service name to have hashtags (ex: "#myHashtag") * auto-linked to. The currently-supported values are: * * - 'twitter' * - 'facebook' * - 'instagram' * * Pass `false` to skip auto-linking of hashtags. */ /** * @cfg {String/Boolean} [mention=false] * * A string for the service name to have mentions (ex: "@myuser") * auto-linked to. The currently supported values are: * * - 'twitter' * - 'instagram' * * Defaults to `false` to skip auto-linking of mentions. */ /** * @cfg {Boolean} [newWindow=true] * * `true` if the links should open in a new window, `false` otherwise. */ /** * @cfg {Boolean/Object} [stripPrefix] * * `true` if 'http://' (or 'https://') and/or the 'www.' should be stripped * from the beginning of URL links' text, `false` otherwise. Defaults to * `true`. * * Examples: * * stripPrefix: true * * // or * * stripPrefix: { * scheme : true, * www : true * } * * As shown above, this option also accepts an Object form with 2 properties * to allow for more customization of what exactly is prevented from being * displayed. Both default to `true`: * * @cfg {Boolean} [stripPrefix.scheme] `true` to prevent the scheme part of * a URL match from being displayed to the user. Example: * `'http://google.com'` will be displayed as `'google.com'`. `false` to * not strip the scheme. NOTE: Only an `'http://'` or `'https://'` scheme * will be removed, so as not to remove a potentially dangerous scheme * (such as `'file://'` or `'javascript:'`) * @cfg {Boolean} [stripPrefix.www] www (Boolean): `true` to prevent the * `'www.'` part of a URL match from being displayed to the user. Ex: * `'www.google.com'` will be displayed as `'google.com'`. `false` to not * strip the `'www'`. */ /** * @cfg {Boolean} [stripTrailingSlash=true] * * `true` to remove the trailing slash from URL matches, `false` to keep * the trailing slash. * * Example when `true`: `http://google.com/` will be displayed as * `http://google.com`. */ /** * @cfg {Number/Object} [truncate=0] * * ## Number Form * * A number for how many characters matched text should be truncated to * inside the text of a link. If the matched text is over this number of * characters, it will be truncated to this length by 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 something like this: * 'yahoo.com/some/long/pat..' * * Example Usage: * * truncate: 25 * * * Defaults to `0` for "no truncation." * * * ## Object Form * * An Object may also be provided with two properties: `length` (Number) and * `location` (String). `location` may be one of the following: 'end' * (default), 'middle', or 'smart'. * * Example Usage: * * truncate: { length: 25, location: 'middle' } * * @cfg {Number} [truncate.length=0] How many characters to allow before * truncation will occur. Defaults to `0` for "no truncation." * @cfg {"end"/"middle"/"smart"} [truncate.location="end"] * * - 'end' (default): will truncate up to the number of characters, and then * add an ellipsis at the end. Ex: 'yahoo.com/some/long/pat..' * - 'middle': will truncate and add the ellipsis in the middle. Ex: * 'yahoo.com/s..th/to/a/file' * - 'smart': for URLs where the algorithm attempts to strip out unnecessary * parts first (such as the 'www.', then URL scheme, hash, etc.), * attempting to make the URL human-readable before looking for a good * point to insert the ellipsis if it is still too long. Ex: * 'yahoo.com/some..to/a/file'. For more details, see * {@link Autolinker.truncate.TruncateSmart}. */ /** * @cfg {String} className * * A CSS class name to add to the generated links. This class will be added * to all links, as well as this class plus match suffixes for styling * url/email/phone/hashtag/mention links differently. * * For example, if this config is provided as "myLink", then: * * - URL links will have the CSS classes: "myLink myLink-url" * - Email links will have the CSS classes: "myLink myLink-email", and * - Phone links will have the CSS classes: "myLink myLink-phone" * - Hashtag links will have the CSS classes: "myLink myLink-hashtag" * - Mention links will have the CSS classes: "myLink myLink-mention myLink-[type]" * where [type] is either "instagram" or "twitter" */ /** * @cfg {Function} replaceFn * * A function to individually process each match found in the input string. * * See the class's description for usage. * * The `replaceFn` can be called with a different context object (`this` * reference) using the {@link #context} cfg. * * This function is called with the following parameter: * * @cfg {Autolinker.match.Match} replaceFn.match The Match instance which * can be used to retrieve information about the match that the `replaceFn` * is currently processing. See {@link Autolinker.match.Match} subclasses * for details. */ /** * @cfg {Object} context * * The context object (`this` reference) to call the `replaceFn` with. * * Defaults to this Autolinker instance. */ /** * @property {String} version (readonly) * * The Autolinker version number in the form major.minor.patch * * Ex: 0.25.1 */ /** * @private * @property {Autolinker.htmlParser.HtmlParser} htmlParser * * The HtmlParser instance used to skip over HTML tags, while finding text * nodes to process. This is lazily instantiated in the {@link #getHtmlParser} * method. */ /** * @private * @property {Autolinker.matcher.Matcher[]} matchers * * The {@link Autolinker.matcher.Matcher} instances for this Autolinker * instance. * * This is lazily created in {@link #getMatchers}. */ /** * @private * @property {Autolinker.AnchorTagBuilder} tagBuilder * * The AnchorTagBuilder instance used to build match replacement anchor tags. * Note: this is lazily instantiated in the {@link #getTagBuilder} method. */ /** * Normalizes the {@link #urls} config into an Object with 3 properties: * `schemeMatches`, `wwwMatches`, and `tldMatches`, all Booleans. * * See {@link #urls} config for details. * * @private * @param {Boolean/Object} urls * @return {Object} */ normalizeUrlsCfg : function( urls ) { if( urls == null ) urls = true; // default to `true` if( typeof urls === 'boolean' ) { return { schemeMatches: urls, wwwMatches: urls, tldMatches: urls }; } else { // object form return { schemeMatches : typeof urls.schemeMatches === 'boolean' ? urls.schemeMatches : true, wwwMatches : typeof urls.wwwMatches === 'boolean' ? urls.wwwMatches : true, tldMatches : typeof urls.tldMatches === 'boolean' ? urls.tldMatches : true }; } }, /** * Normalizes the {@link #stripPrefix} config into an Object with 2 * properties: `scheme`, and `www` - both Booleans. * * See {@link #stripPrefix} config for details. * * @private * @param {Boolean/Object} stripPrefix * @return {Object} */ normalizeStripPrefixCfg : function( stripPrefix ) { if( stripPrefix == null ) stripPrefix = true; // default to `true` if( typeof stripPrefix === 'boolean' ) { return { scheme: stripPrefix, www: stripPrefix }; } else { // object form return { scheme : typeof stripPrefix.scheme === 'boolean' ? stripPrefix.scheme : true, www : typeof stripPrefix.www === 'boolean' ? stripPrefix.www : true }; } }, /** * Normalizes the {@link #truncate} config into an Object with 2 properties: * `length` (Number), and `location` (String). * * See {@link #truncate} config for details. * * @private * @param {Number/Object} truncate * @return {Object} */ normalizeTruncateCfg : function( truncate ) { if( typeof truncate === 'number' ) { return { length: truncate, location: 'end' }; } else { // object, or undefined/null return Autolinker.Util.defaults( truncate || {}, { length : Number.POSITIVE_INFINITY, location : 'end' } ); } }, /** * Parses the input `textOrHtml` looking for URLs, email addresses, phone * numbers, username handles, and hashtags (depending on the configuration * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} * objects describing those matches (without making any replacements). * * This method is used by the {@link #link} method, but can also be used to * simply do parsing of the input in order to discover what kinds of links * there are and how many. * * Example usage: * * var autolinker = new Autolinker( { * urls: true, * email: true * } ); * * var matches = autolinker.parse( "Hello google.com, I am asdf@asdf.com" ); * * console.log( matches.length ); // 2 * console.log( matches[ 0 ].getType() ); // 'url' * console.log( matches[ 0 ].getUrl() ); // 'google.com' * console.log( matches[ 1 ].getType() ); // 'email' * console.log( matches[ 1 ].getEmail() ); // 'asdf@asdf.com' * * @param {String} textOrHtml The HTML or text to find matches within * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, * {@link #hashtag}, and {@link #mention} options are enabled). * @return {Autolinker.match.Match[]} The array of Matches found in the * given input `textOrHtml`. */ parse : function( textOrHtml ) { var htmlParser = this.getHtmlParser(), htmlNodes = htmlParser.parse( textOrHtml ), anchorTagStackCount = 0, // used to only process text around anchor tags, and any inner text/html they may have; matches = []; // Find all matches within the `textOrHtml` (but not matches that are // already nested within <a> tags) for( var i = 0, len = htmlNodes.length; i < len; i++ ) { var node = htmlNodes[ i ], nodeType = node.getType(); if( nodeType === 'element' && node.getTagName() === 'a' ) { // Process HTML anchor element nodes in the input `textOrHtml` to find out when we're within an <a> tag if( !node.isClosing() ) { // it's the start <a> tag anchorTagStackCount++; } else { // it's the end </a> tag anchorTagStackCount = Math.max( anchorTagStackCount - 1, 0 ); // attempt to handle extraneous </a> tags by making sure the stack count never goes below 0 } } else if( nodeType === 'text' && anchorTagStackCount === 0 ) { // Process text nodes that are not within an <a> tag var textNodeMatches = this.parseText( node.getText(), node.getOffset() ); matches.push.apply( matches, textNodeMatches ); } } // After we have found all matches, remove subsequent matches that // overlap with a previous match. This can happen for instance with URLs, // where the url 'google.com/#link' would match '#link' as a hashtag. matches = this.compactMatches( matches ); // And finally, remove matches for match types that have been turned // off. We needed to have all match types turned on initially so that // things like hashtags could be filtered out if they were really just // part of a URL match (for instance, as a named anchor). matches = this.removeUnwantedMatches( matches ); return matches; }, /** * After we have found all matches, we need to remove subsequent matches * that overlap with a previous match. This can happen for instance with * URLs, where the url 'google.com/#link' would match '#link' as a hashtag. * * @private * @param {Autolinker.match.Match[]} matches * @return {Autolinker.match.Match[]} */ compactMatches : function( matches ) { // First, the matches need to be sorted in order of offset matches.sort( function( a, b ) { return a.getOffset() - b.getOffset(); } ); for( var i = 0; i < matches.length - 1; i++ ) { var match = matches[ i ], offset = match.getOffset(), matchedTextLength = match.getMatchedText().length, endIdx = offset + matchedTextLength; if( i + 1 < matches.length ) { // Remove subsequent matches that equal offset with current match if( matches[ i + 1 ].getOffset() === offset ) { var removeIdx = matches[ i + 1 ].getMatchedText().length > matchedTextLength ? i : i + 1; matches.splice( removeIdx, 1 ); continue; } // Remove subsequent matches that overlap with the current match if( matches[ i + 1 ].getOffset() <= endIdx ) { matches.splice( i + 1, 1 ); } } } return matches; }, /** * Removes matches for matchers that were turned off in the options. For * example, if {@link #hashtag hashtags} were not to be matched, we'll * remove them from the `matches` array here. * * @private * @param {Autolinker.match.Match[]} matches The array of matches to remove * the unwanted matches from. Note: this array is mutated for the * removals. * @return {Autolinker.match.Match[]} The mutated input `matches` array. */ removeUnwantedMatches : function( matches ) { var remove = Autolinker.Util.remove; if( !this.hashtag ) remove( matches, function( match ) { return match.getType() === 'hashtag'; } ); if( !this.email ) remove( matches, function( match ) { return match.getType() === 'email'; } ); if( !this.phone ) remove( matches, function( match ) { return match.getType() === 'phone'; } ); if( !this.mention ) remove( matches, function( match ) { return match.getType() === 'mention'; } ); if( !this.urls.schemeMatches ) { remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'scheme'; } ); } if( !this.urls.wwwMatches ) { remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'www'; } ); } if( !this.urls.tldMatches ) { remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'tld'; } ); } return matches; }, /** * Parses the input `text` looking for URLs, email addresses, phone * numbers, username handles, and hashtags (depending on the configuration * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} * objects describing those matches. * * This method processes a **non-HTML string**, and is used to parse and * match within the text nodes of an HTML string. This method is used * internally by {@link #parse}. * * @private * @param {String} text The text to find matches within (depending on if the * {@link #urls}, {@link #email}, {@link #phone}, * {@link #hashtag}, and {@link #mention} options are enabled). This must be a non-HTML string. * @param {Number} [offset=0] The offset of the text node within the * original string. This is used when parsing with the {@link #parse} * method to generate correct offsets within the {@link Autolinker.match.Match} * instances, but may be omitted if calling this method publicly. * @return {Autolinker.match.Match[]} The array of Matches found in the * given input `text`. */ parseText : function( text, offset ) { offset = offset || 0; var matchers = this.getMatchers(), matches = []; for( var i = 0, numMatchers = matchers.length; i < numMatchers; i++ ) { var textMatches = matchers[ i ].parseMatches( text ); // Correct the offset of each of the matches. They are originally // the offset of the match within the provided text node, but we // need to correct them to be relative to the original HTML input // string (i.e. the one provided to #parse). for( var j = 0, numTextMatches = textMatches.length; j < numTextMatches; j++ ) { textMatches[ j ].setOffset( offset + textMatches[ j ].getOffset() ); } matches.push.apply( matches, textMatches ); } return matches; }, /** * Automatically links URLs, Email addresses, Phone numbers, Hashtags, * and Mentions (Twitter, Instagram) 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>` * * 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 (<a>) tags. * * @param {String} textOrHtml The HTML or text to autolink matches within * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #hashtag}, and {@link #mention} options are enabled). * @return {String} The HTML, with matches automatically linked. */ link : function( textOrHtml ) { if( !textOrHtml ) { return ""; } // handle `null` and `undefined` var matches = this.parse( textOrHtml ), newHtml = [], lastIndex = 0; for( var i = 0, len = matches.length; i < len; i++ ) { var match = matches[ i ]; newHtml.push( textOrHtml.substring( lastIndex, match.getOffset() ) ); newHtml.push( this.createMatchReturnVal( match ) ); lastIndex = match.getOffset() + match.getMatchedText().length; } newHtml.push( textOrHtml.substring( lastIndex ) ); // handle the text after the last match return newHtml.join( '' ); }, /** * Creates the return string value for a given match in the input string. * * This method handles the {@link #replaceFn}, if one was provided. * * @private * @param {Autolinker.match.Match} match The Match object that represents * the match. * @return {String} The string that the `match` should be replaced with. * This is usually the anchor tag string, but may be the `matchStr` itself * if the match is not to be replaced. */ createMatchReturnVal : function( match ) { // Handle a custom `replaceFn` being provided var replaceFnResult; if( this.replaceFn ) { replaceFnResult = this.replaceFn.call( this.context, match ); // Autolinker instance is the context } if( typeof replaceFnResult === 'string' ) { return replaceFnResult; // `replaceFn` returned a string, use that } else if( replaceFnResult === false ) { return match.getMatchedText(); // no replacement for the match } else if( replaceFnResult instanceof Autolinker.HtmlTag ) { return replaceFnResult.toAnchorString(); } else { // replaceFnResult === true, or no/unknown return value from function // Perform Autolinker's default anchor tag generation var anchorTag = match.buildTag(); // returns an Autolinker.HtmlTag instance return anchorTag.toAnchorString(); } }, /** * Lazily instantiates and returns the {@link #htmlParser} instance for this * Autolinker instance. * * @protected * @return {Autolinker.htmlParser.HtmlParser} */ getHtmlParser : function() { var htmlParser = this.htmlParser; if( !htmlParser ) { htmlParser = this.htmlParser = new Autolinker.htmlParser.HtmlParser(); } return htmlParser; }, /** * Lazily instantiates and returns the {@link Autolinker.matcher.Matcher} * instances for this Autolinker instance. * * @protected * @return {Autolinker.matcher.Matcher[]} */ getMatchers : function() { if( !this.matchers ) { var matchersNs = Autolinker.matcher, tagBuilder = this.getTagBuilder(); var matchers = [ new matchersNs.Hashtag( { tagBuilder: tagBuilder, serviceName: this.hashtag } ), new matchersNs.Email( { tagBuilder: tagBuilder } ), new matchersNs.Phone( { tagBuilder: tagBuilder } ), new matchersNs.Mention( { tagBuilder: tagBuilder, serviceName: this.mention } ), new matchersNs.Url( { tagBuilder: tagBuilder, stripPrefix: this.stripPrefix, stripTrailingSlash: this.stripTrailingSlash } ) ]; return ( this.matchers = matchers ); } else { return this.matchers; } }, /** * Returns the {@link #tagBuilder} instance for this Autolinker instance, lazily instantiating it * if it does not yet exist. * * This method may be used in a {@link #replaceFn} to generate the {@link Autolinker.HtmlTag HtmlTag} instance that * Autolinker would normally generate, and then allow for modifications before returning it. For example: * * var html = Autolinker.link( "Test google.com", { * replaceFn : function( match ) { * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance * tag.setAttr( 'rel', 'nofollow' ); * * return tag; * } * } ); * * // generated html: * // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a> * * @return {Autolinker.AnchorTagBuilder} */ getTagBuilder : function() { var tagBuilder = this.tagBuilder; if( !tagBuilder ) { tagBuilder = this.tagBuilder = new Autolinker.AnchorTagBuilder( { newWindow : this.newWindow, truncate : this.truncate, className : this.className } ); } return tagBuilder; } }; // Autolinker Namespaces Autolinker.match = {}; Autolinker.matcher = {}; Autolinker.htmlParser = {}; Autolinker.truncate = {};