|
1 | 1 | /*! |
2 | 2 | * Autolinker.js |
3 | | - * 0.12.3 |
| 3 | + * 0.12.4 |
4 | 4 | * |
5 | 5 | * Copyright(c) 2014 Gregory Jacobs <[email protected]> |
6 | 6 | * MIT Licensed. http://www.opensource.org/licenses/mit-license.php |
|
344 | 344 | * This method finds the text around any HTML elements in the input `textOrHtml`, which will be the text that is processed. |
345 | 345 | * Any original HTML elements will be left as-is, as well as the text that is already wrapped in anchor (<a>) tags. |
346 | 346 | * |
347 | | - * @param {String} textOrHtml The HTML or text to link URLs, email addresses, and Twitter handles within. |
| 347 | + * @param {String} textOrHtml The HTML or text to link URLs, email addresses, and Twitter handles within (depending on if |
| 348 | + * the {@link #urls}, {@link #email}, and {@link #twitter} options are enabled). |
348 | 349 | * @return {String} The HTML, with URLs/emails/Twitter handles automatically linked. |
349 | 350 | */ |
350 | 351 | link : function( textOrHtml ) { |
|
454 | 455 | * @return {String} The text with anchor tags auto-filled. |
455 | 456 | */ |
456 | 457 | processTextNode : function( text ) { |
457 | | - var me = this, // for closure |
458 | | - charBeforeProtocolRelMatchRegex = this.charBeforeProtocolRelMatchRegex; |
| 458 | + var me = this; // for closure |
459 | 459 |
|
460 | 460 | return text.replace( this.matcherRegex, function( matchStr, $1, $2, $3, $4, $5, $6, $7 ) { |
461 | | - var twitterMatch = $1, |
462 | | - twitterHandlePrefixWhitespaceChar = $2, // The whitespace char before the @ sign in a Twitter handle match. This is needed because of no lookbehinds in JS regexes. |
463 | | - twitterHandle = $3, // The actual twitterUser (i.e the word after the @ sign in a Twitter handle match) |
464 | | - emailAddressMatch = $4, // For both determining if it is an email address, and stores the actual email address |
465 | | - urlMatch = $5, // The matched URL string |
466 | | - protocolRelativeMatch = $6 || $7, // The '//' for a protocol-relative match, with the character that comes before the '//' |
467 | | - |
468 | | - prefixStr = "", // A string to use to prefix the anchor tag that is created. This is needed for the Twitter handle match |
469 | | - 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. |
470 | | - |
471 | | - match; // Will be an Autolinker.match.Match object |
472 | | - |
| 461 | + var matchDescObj = me.processCandidateMatch.apply( me, arguments ); // match description object |
473 | 462 |
|
474 | 463 | // Return out with no changes for match types that are disabled (url, email, twitter), or for matches that are |
475 | 464 | // invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS). |
476 | | - if( !me.isValidMatch( twitterMatch, emailAddressMatch, urlMatch, protocolRelativeMatch ) ) { |
| 465 | + if( !matchDescObj ) { |
477 | 466 | return matchStr; |
| 467 | + |
| 468 | + } else { |
| 469 | + // Generate the replacement text for the match |
| 470 | + var matchReturnVal = me.createMatchReturnVal( matchDescObj.match, matchDescObj.matchStr ); |
| 471 | + return matchDescObj.prefixStr + matchReturnVal + matchDescObj.suffixStr; |
478 | 472 | } |
| 473 | + } ); |
| 474 | + }, |
| 475 | + |
| 476 | + |
| 477 | + /** |
| 478 | + * Processes a candidate match from the {@link #matcherRegex}. |
| 479 | + * |
| 480 | + * Not all matches found by the regex are actual URL/email/Twitter matches, as determined by {@link #isValidMatch}. In |
| 481 | + * this case, the method returns `null`. Otherwise, a valid Object with `prefixStr`, `match`, and `suffixStr` is returned. |
| 482 | + * |
| 483 | + * @private |
| 484 | + * @param {String} matchStr The full match that was found by the {@link #matcherRegex}. |
| 485 | + * @param {String} twitterMatch The matched text of a Twitter handle, if the match is a Twitter match. |
| 486 | + * @param {String} twitterHandlePrefixWhitespaceChar The whitespace char before the @ sign in a Twitter handle match. This |
| 487 | + * is needed because of no lookbehinds in JS regexes, and is need to re-include the character for the anchor tag replacement. |
| 488 | + * @param {String} twitterHandle The actual Twitter user (i.e the word after the @ sign in a Twitter match). |
| 489 | + * @param {String} emailAddressMatch The matched email address for an email address match. |
| 490 | + * @param {String} urlMatch The matched URL string for a URL match. |
| 491 | + * @param {String} wwwProtocolRelativeMatch The '//' for a protocol-relative match from a 'www' url, with the character that |
| 492 | + * comes before the '//'. |
| 493 | + * @param {String} tldProtocolRelativeMatch The '//' for a protocol-relative match from a TLD (top level domain) match, with |
| 494 | + * the character that comes before the '//'. |
| 495 | + * |
| 496 | + * @return {Object} A "match description object". This will be `null` if the match was invalid, or if a match type is disabled. |
| 497 | + * Otherwise, this will be an Object (map) with the following properties: |
| 498 | + * @return {String} return.prefixStr The char(s) that should be prepended to the replacement string. These are char(s) that |
| 499 | + * were needed to be included from the regex match that were ignored by processing code, and should be re-inserted into |
| 500 | + * the replacement stream. |
| 501 | + * @return {String} return.suffixStr The char(s) that should be appended to the replacement string. These are char(s) that |
| 502 | + * were needed to be included from the regex match that were ignored by processing code, and should be re-inserted into |
| 503 | + * the replacement stream. |
| 504 | + * @return {String} return.matchStr The `matchStr`, fixed up to remove characters that are no longer needed (which have been |
| 505 | + * added to `prefixStr` and `suffixStr`). |
| 506 | + * @return {Autolinker.match.Match} return.match The Match object that represents the match that was found. |
| 507 | + */ |
| 508 | + processCandidateMatch : function( |
| 509 | + matchStr, twitterMatch, twitterHandlePrefixWhitespaceChar, twitterHandle, |
| 510 | + emailAddressMatch, urlMatch, wwwProtocolRelativeMatch, tldProtocolRelativeMatch |
| 511 | + ) { |
| 512 | + var protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch, |
| 513 | + match, // Will be an Autolinker.match.Match object |
| 514 | + |
| 515 | + prefixStr = "", // A string to use to prefix the anchor tag that is created. This is needed for the Twitter handle match |
| 516 | + 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. |
| 517 | + |
| 518 | + |
| 519 | + // Return out with `null` for match types that are disabled (url, email, twitter), or for matches that are |
| 520 | + // invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS). |
| 521 | + if( !this.isValidMatch( twitterMatch, emailAddressMatch, urlMatch, protocolRelativeMatch ) ) { |
| 522 | + return null; |
| 523 | + } |
| 524 | + |
| 525 | + // Handle a closing parenthesis at the end of the match, and exclude it if there is not a matching open parenthesis |
| 526 | + // in the match itself. |
| 527 | + if( this.matchHasUnbalancedClosingParen( matchStr ) ) { |
| 528 | + matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")" |
| 529 | + suffixStr = ")"; // this will be added after the generated <a> tag |
| 530 | + } |
| 531 | + |
| 532 | + |
| 533 | + if( emailAddressMatch ) { |
| 534 | + match = new Autolinker.match.Email( { matchedText: matchStr, email: emailAddressMatch } ); |
479 | 535 |
|
480 | | - // Handle a closing parenthesis at the end of the match, and exclude it if there is not a matching open parenthesis |
481 | | - // in the match itself. |
482 | | - if( me.matchHasUnbalancedClosingParen( matchStr ) ) { |
483 | | - matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")" |
484 | | - suffixStr = ")"; // this will be added after the generated <a> tag |
| 536 | + } else if( twitterMatch ) { |
| 537 | + // fix up the `matchStr` if there was a preceding whitespace char, which was needed to determine the match |
| 538 | + // itself (since there are no look-behinds in JS regexes) |
| 539 | + if( twitterHandlePrefixWhitespaceChar ) { |
| 540 | + prefixStr = twitterHandlePrefixWhitespaceChar; |
| 541 | + matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match |
485 | 542 | } |
| 543 | + match = new Autolinker.match.Twitter( { matchedText: matchStr, twitterHandle: twitterHandle } ); |
486 | 544 |
|
487 | | - |
488 | | - if( emailAddressMatch ) { |
489 | | - match = new Autolinker.match.Email( { matchedText: matchStr, email: emailAddressMatch } ); |
| 545 | + } else { // url match |
| 546 | + // If it's a protocol-relative '//' match, remove the character before the '//' (which the matcherRegex needed |
| 547 | + // to match due to the lack of a negative look-behind in JavaScript regular expressions) |
| 548 | + if( protocolRelativeMatch ) { |
| 549 | + var charBeforeMatch = protocolRelativeMatch.match( this.charBeforeProtocolRelMatchRegex )[ 1 ] || ""; |
490 | 550 |
|
491 | | - } else if( twitterMatch ) { |
492 | | - // fix up the `matchStr` if there was a preceding whitespace char, which was needed to determine the match |
493 | | - // itself (since there are no look-behinds in JS regexes) |
494 | | - if( twitterHandlePrefixWhitespaceChar ) { |
495 | | - prefixStr = twitterHandlePrefixWhitespaceChar; |
496 | | - matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match |
| 551 | + 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) |
| 552 | + prefixStr = charBeforeMatch; |
| 553 | + matchStr = matchStr.slice( 1 ); // remove the prefixed char from the match |
497 | 554 | } |
498 | | - match = new Autolinker.match.Twitter( { matchedText: matchStr, twitterHandle: twitterHandle } ); |
499 | | - |
500 | | - } else { // url match |
501 | | - // If it's a protocol-relative '//' match, remove the character before the '//' (which the matcherRegex needed |
502 | | - // to match due to the lack of a negative look-behind in JavaScript regular expressions) |
503 | | - if( protocolRelativeMatch ) { |
504 | | - var charBeforeMatch = protocolRelativeMatch.match( charBeforeProtocolRelMatchRegex )[ 1 ] || ""; |
505 | | - |
506 | | - 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) |
507 | | - prefixStr = charBeforeMatch; |
508 | | - matchStr = matchStr.slice( 1 ); // remove the prefixed char from the match |
509 | | - } |
510 | | - } |
511 | | - |
512 | | - match = new Autolinker.match.Url( { |
513 | | - matchedText : matchStr, |
514 | | - url : matchStr, |
515 | | - protocolRelativeMatch : protocolRelativeMatch, |
516 | | - stripPrefix : me.stripPrefix |
517 | | - } ); |
518 | 555 | } |
519 | | - |
520 | | - // Generate the replacement text for the match |
521 | | - var matchReturnVal = me.createMatchReturnVal( match, matchStr ); |
522 | | - return prefixStr + matchReturnVal + suffixStr; |
523 | | - } ); |
| 556 | + |
| 557 | + match = new Autolinker.match.Url( { |
| 558 | + matchedText : matchStr, |
| 559 | + url : matchStr, |
| 560 | + protocolRelativeMatch : protocolRelativeMatch, |
| 561 | + stripPrefix : this.stripPrefix |
| 562 | + } ); |
| 563 | + } |
| 564 | + |
| 565 | + return { |
| 566 | + prefixStr : prefixStr, |
| 567 | + suffixStr : suffixStr, |
| 568 | + matchStr : matchStr, |
| 569 | + match : match |
| 570 | + }; |
524 | 571 | }, |
525 | 572 |
|
526 | 573 |
|
| 574 | + |
| 575 | + |
527 | 576 | /** |
528 | 577 | * Determines if a given match found by {@link #processTextNode} is valid. Will return `false` for: |
529 | 578 | * |
|
647 | 696 | * // Produces: "Go to <a href="http://google.com">google.com</a>" |
648 | 697 | * |
649 | 698 | * @static |
650 | | - * @method link |
651 | | - * @param {String} html The HTML text to link URLs within. |
| 699 | + * @param {String} textOrHtml The HTML or text to find URLs, email addresses, and Twitter handles within (depending on if |
| 700 | + * the {@link #urls}, {@link #email}, and {@link #twitter} options are enabled). |
652 | 701 | * @param {Object} [options] Any of the configuration options for the Autolinker class, specified in an Object (map). |
653 | 702 | * See the class description for an example call. |
654 | 703 | * @return {String} The HTML text, with URLs automatically linked |
655 | 704 | */ |
656 | | - Autolinker.link = function( text, options ) { |
| 705 | + Autolinker.link = function( textOrHtml, options ) { |
657 | 706 | var autolinker = new Autolinker( options ); |
658 | | - return autolinker.link( text ); |
| 707 | + return autolinker.link( textOrHtml ); |
659 | 708 | }; |
660 | 709 |
|
661 | 710 |
|
|
0 commit comments