autolinker
Advanced tools
Comparing version 0.12.3 to 0.12.4
/*! | ||
* Autolinker.js | ||
* 0.12.2 | ||
* 0.12.4 | ||
* | ||
@@ -10,2 +10,2 @@ * Copyright(c) 2014 Gregory Jacobs <greg@greg-jacobs.com> | ||
*/ | ||
!function(a,b){"function"==typeof define&&define.amd?define(b):"undefined"!=typeof exports?module.exports=b():a.Autolinker=b()}(this,function(){var a=function(b){a.Util.assign(this,b)};return a.prototype={constructor:a,urls:!0,email:!0,twitter:!0,newWindow:!0,stripPrefix:!0,className:"",htmlCharacterEntitiesRegex:/( | |<|<|>|>)/gi,matcherRegex:function(){var a=/(^|[^\w])@(\w{1,15})/,b=/(?:[\-;:&=\+\$,\w\.]+@)/,c=/(?:[A-Za-z]{3,9}:(?:\/\/)?)/,d=/(?:www\.)/,e=/[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/,f=/\.(?: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/,g=/(?:[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])?/;return new RegExp(["(",a.source,")","|","(",b.source,e.source,f.source,")","|","(","(?:","(?:",c.source,e.source,")","|","(?:","(.?//)?",d.source,e.source,")","|","(?:","(.?//)?",e.source,f.source,")",")",g.source,")"].join(""),"gi")}(),invalidProtocolRelMatchRegex:/^[\w]\/\//,charBeforeProtocolRelMatchRegex:/^(.)?\/\//,link:function(b){var c=this,d=this.getHtmlParser(),e=this.htmlCharacterEntitiesRegex,f=0,g=[];return d.parse(b,{processHtmlNode:function(a,b,c){"a"===b&&(c?f=Math.max(f-1,0):f++),g.push(a)},processTextNode:function(b){if(0===f)for(var d=a.Util.splitAndCapture(b,e),h=0,i=d.length;i>h;h++){var j=d[h],k=c.processTextNode(j);g.push(k)}else g.push(b)}}),g.join("")},getHtmlParser:function(){var b=this.htmlParser;return b||(b=this.htmlParser=new a.HtmlParser),b},getTagBuilder:function(){var b=this.tagBuilder;return b||(b=this.tagBuilder=new a.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),b},processTextNode:function(b){var c=this,d=this.charBeforeProtocolRelMatchRegex;return b.replace(this.matcherRegex,function(b,e,f,g,h,i,j,k){var l,m=e,n=f,o=g,p=h,q=i,r=j||k,s="",t="";if(!c.isValidMatch(m,p,q,r))return b;if(c.matchHasUnbalancedClosingParen(b)&&(b=b.substr(0,b.length-1),t=")"),p)l=new a.match.Email({matchedText:b,email:p});else if(m)n&&(s=n,b=b.slice(1)),l=new a.match.Twitter({matchedText:b,twitterHandle:o});else{if(r){var u=r.match(d)[1]||"";u&&(s=u,b=b.slice(1))}l=new a.match.Url({matchedText:b,url:b,protocolRelativeMatch:r,stripPrefix:c.stripPrefix})}var v=c.createMatchReturnVal(l,b);return s+v+t})},isValidMatch:function(a,b,c,d){return a&&!this.twitter||b&&!this.email||c&&!this.urls||c&&-1===c.indexOf(".")||c&&/^[A-Za-z]{3,9}:/.test(c)&&!/:.*?[A-Za-z]/.test(c)||d&&this.invalidProtocolRelMatchRegex.test(d)?!1:!0},matchHasUnbalancedClosingParen:function(a){var b=a.charAt(a.length-1);if(")"===b){var c=a.match(/\(/g),d=a.match(/\)/g),e=c&&c.length||0,f=d&&d.length||0;if(f>e)return!0}return!1},createMatchReturnVal:function(b,c){var d;if(this.replaceFn&&(d=this.replaceFn.call(this,this,b)),"string"==typeof d)return d;if(d===!1)return c;if(d instanceof a.HtmlTag)return d.toString();var e=this.getTagBuilder(),f=e.build(b);return f.toString()}},a.link=function(b,c){var d=new a(c);return d.link(b)},a.match={},a.Util={abstractMethod:function(){throw"abstract"},assign:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},extend:function(b,c){var d=b.prototype,e=function(){};e.prototype=d;var f;f=c.hasOwnProperty("constructor")?c.constructor:function(){d.constructor.apply(this,arguments)};var g=f.prototype=new e;return g.constructor=f,g.superclass=d,delete c.constructor,a.Util.assign(g,c),f},ellipsis:function(a,b,c){return a.length>b&&(c=null==c?"..":c,a=a.substring(0,b-c.length)+c),a},indexOf:function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},splitAndCapture:function(a,b){if(!b.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var c,d=[],e=0;c=b.exec(a);)d.push(a.substring(e,c.index)),d.push(c[0]),e=c.index+c[0].length;return d.push(a.substring(e)),d}},a.HtmlParser=a.Util.extend(Object,{htmlRegex:function(){var a=/[0-9a-zA-Z:]+/,b=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,c=/(?:".*?"|'.*?'|[^'"=<>`\s]+)/,d=b.source+"(?:\\s*=\\s*"+c.source+")?";return new RegExp(["<(?:!|(/))?","("+a.source+")","(?:","\\s+","(?:",d,"|",c.source+")",")*","\\s*/?",">"].join(""),"g")}(),parse:function(a,b){b=b||{};for(var c,d=b.processHtmlNode||function(){},e=b.processTextNode||function(){},f=this.htmlRegex,g=0;null!==(c=f.exec(a));){var h=c[0],i=c[2],j=!!c[1],k=a.substring(g,c.index);k&&e(k),d(h,i,j),g=c.index+h.length}if(g<a.length){var l=a.substring(g);l&&e(l)}}}),a.HtmlTag=a.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(b){a.Util.assign(this,b),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(a){return this.tagName=a,this},getTagName:function(){return this.tagName||""},setAttr:function(a,b){var c=this.getAttrs();return c[a]=b,this},getAttr:function(a){return this.getAttrs()[a]},setAttrs:function(b){var c=this.getAttrs();return a.Util.assign(c,b),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(a){return this.setAttr("class",a)},addClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);c=h.shift();)-1===f(g,c)&&g.push(c);return this.getAttrs()["class"]=g.join(" "),this},removeClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);g.length&&(c=h.shift());){var i=f(g,c);-1!==i&&g.splice(i,1)}return this.getAttrs()["class"]=g.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(a){return-1!==(" "+this.getClass()+" ").indexOf(" "+a+" ")},setInnerHtml:function(a){return this.innerHtml=a,this},getInnerHtml:function(){return this.innerHtml||""},toString:function(){var a=this.getTagName(),b=this.buildAttrsStr();return b=b?" "+b:"",["<",a,b,">",this.getInnerHtml(),"</",a,">"].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var a=this.getAttrs(),b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+'="'+a[c]+'"');return b.join(" ")}}),a.AnchorTagBuilder=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},build:function(b){var c=new a.HtmlTag({tagName:"a",attrs:this.createAttrs(b.getType(),b.getAnchorHref()),innerHtml:this.processAnchorText(b.getAnchorText())});return c},createAttrs:function(a,b){var c={href:b},d=this.createCssClass(a);return d&&(c["class"]=d),this.newWindow&&(c.target="_blank"),c},createCssClass:function(a){var b=this.className;return b?b+" "+b+"-"+a:""},processAnchorText:function(a){return a=this.doTruncate(a)},doTruncate:function(b){return a.Util.ellipsis(b,this.truncate||Number.POSITIVE_INFINITY)}}),a.match.Match=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},getType:a.Util.abstractMethod,getMatchedText:function(){return this.matchedText},getAnchorHref:a.Util.abstractMethod,getAnchorText:a.Util.abstractMethod}),a.match.Email=a.Util.extend(a.match.Match,{getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),a.match.Twitter=a.Util.extend(a.match.Match,{getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),a.match.Url=a.Util.extend(a.match.Match,{urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,checkForProtocolRegex:/^[A-Za-z]{3,9}:/,getType:function(){return"url"},getUrl:function(){var a=this.url;return this.protocolRelativeMatch||this.checkForProtocolRegex.test(a)||(a=this.url="http://"+a),a},getAnchorHref:function(){var a=this.getUrl();return a.replace(/&/g,"&")},getAnchorText:function(){var a=this.getUrl();return this.protocolRelativeMatch&&(a=this.stripProtocolRelativePrefix(a)),this.stripPrefix&&(a=this.stripUrlPrefix(a)),a=this.removeTrailingSlash(a)},stripUrlPrefix:function(a){return a.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(a){return a.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(a){return"/"===a.charAt(a.length-1)&&(a=a.slice(0,-1)),a}}),a}); | ||
!function(a,b){"function"==typeof define&&define.amd?define(b):"undefined"!=typeof exports?module.exports=b():a.Autolinker=b()}(this,function(){var a=function(b){a.Util.assign(this,b)};return a.prototype={constructor:a,urls:!0,email:!0,twitter:!0,newWindow:!0,stripPrefix:!0,className:"",htmlCharacterEntitiesRegex:/( | |<|<|>|>)/gi,matcherRegex:function(){var a=/(^|[^\w])@(\w{1,15})/,b=/(?:[\-;:&=\+\$,\w\.]+@)/,c=/(?:[A-Za-z]{3,9}:(?:\/\/)?)/,d=/(?:www\.)/,e=/[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/,f=/\.(?: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/,g=/(?:[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;\$\*]*[\-A-Za-z0-9+&@#\/%=~_()|\$\*])?/;return new RegExp(["(",a.source,")","|","(",b.source,e.source,f.source,")","|","(","(?:","(?:",c.source,e.source,")","|","(?:","(.?//)?",d.source,e.source,")","|","(?:","(.?//)?",e.source,f.source,")",")",g.source,")"].join(""),"gi")}(),invalidProtocolRelMatchRegex:/^[\w]\/\//,charBeforeProtocolRelMatchRegex:/^(.)?\/\//,link:function(b){var c=this,d=this.getHtmlParser(),e=this.htmlCharacterEntitiesRegex,f=0,g=[];return d.parse(b,{processHtmlNode:function(a,b,c){"a"===b&&(c?f=Math.max(f-1,0):f++),g.push(a)},processTextNode:function(b){if(0===f)for(var d=a.Util.splitAndCapture(b,e),h=0,i=d.length;i>h;h++){var j=d[h],k=c.processTextNode(j);g.push(k)}else g.push(b)}}),g.join("")},getHtmlParser:function(){var b=this.htmlParser;return b||(b=this.htmlParser=new a.HtmlParser),b},getTagBuilder:function(){var b=this.tagBuilder;return b||(b=this.tagBuilder=new a.AnchorTagBuilder({newWindow:this.newWindow,truncate:this.truncate,className:this.className})),b},processTextNode:function(a){var b=this;return a.replace(this.matcherRegex,function(a){var c=b.processCandidateMatch.apply(b,arguments);if(c){var d=b.createMatchReturnVal(c.match,c.matchStr);return c.prefixStr+d+c.suffixStr}return a})},processCandidateMatch:function(b,c,d,e,f,g,h,i){var j,k=h||i,l="",m="";if(!this.isValidMatch(c,f,g,k))return null;if(this.matchHasUnbalancedClosingParen(b)&&(b=b.substr(0,b.length-1),m=")"),f)j=new a.match.Email({matchedText:b,email:f});else if(c)d&&(l=d,b=b.slice(1)),j=new a.match.Twitter({matchedText:b,twitterHandle:e});else{if(k){var n=k.match(this.charBeforeProtocolRelMatchRegex)[1]||"";n&&(l=n,b=b.slice(1))}j=new a.match.Url({matchedText:b,url:b,protocolRelativeMatch:k,stripPrefix:this.stripPrefix})}return{prefixStr:l,suffixStr:m,matchStr:b,match:j}},isValidMatch:function(a,b,c,d){return a&&!this.twitter||b&&!this.email||c&&!this.urls||c&&-1===c.indexOf(".")||c&&/^[A-Za-z]{3,9}:/.test(c)&&!/:.*?[A-Za-z]/.test(c)||d&&this.invalidProtocolRelMatchRegex.test(d)?!1:!0},matchHasUnbalancedClosingParen:function(a){var b=a.charAt(a.length-1);if(")"===b){var c=a.match(/\(/g),d=a.match(/\)/g),e=c&&c.length||0,f=d&&d.length||0;if(f>e)return!0}return!1},createMatchReturnVal:function(b,c){var d;if(this.replaceFn&&(d=this.replaceFn.call(this,this,b)),"string"==typeof d)return d;if(d===!1)return c;if(d instanceof a.HtmlTag)return d.toString();var e=this.getTagBuilder(),f=e.build(b);return f.toString()}},a.link=function(b,c){var d=new a(c);return d.link(b)},a.match={},a.Util={abstractMethod:function(){throw"abstract"},assign:function(a,b){for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a},extend:function(b,c){var d=b.prototype,e=function(){};e.prototype=d;var f;f=c.hasOwnProperty("constructor")?c.constructor:function(){d.constructor.apply(this,arguments)};var g=f.prototype=new e;return g.constructor=f,g.superclass=d,delete c.constructor,a.Util.assign(g,c),f},ellipsis:function(a,b,c){return a.length>b&&(c=null==c?"..":c,a=a.substring(0,b-c.length)+c),a},indexOf:function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},splitAndCapture:function(a,b){if(!b.global)throw new Error("`splitRegex` must have the 'g' flag set");for(var c,d=[],e=0;c=b.exec(a);)d.push(a.substring(e,c.index)),d.push(c[0]),e=c.index+c[0].length;return d.push(a.substring(e)),d}},a.HtmlParser=a.Util.extend(Object,{htmlRegex:function(){var a=/[0-9a-zA-Z:]+/,b=/[^\s\0"'>\/=\x01-\x1F\x7F]+/,c=/(?:".*?"|'.*?'|[^'"=<>`\s]+)/,d=b.source+"(?:\\s*=\\s*"+c.source+")?";return new RegExp(["<(?:!|(/))?","("+a.source+")","(?:","\\s+","(?:",d,"|",c.source+")",")*","\\s*/?",">"].join(""),"g")}(),parse:function(a,b){b=b||{};for(var c,d=b.processHtmlNode||function(){},e=b.processTextNode||function(){},f=this.htmlRegex,g=0;null!==(c=f.exec(a));){var h=c[0],i=c[2],j=!!c[1],k=a.substring(g,c.index);k&&e(k),d(h,i,j),g=c.index+h.length}if(g<a.length){var l=a.substring(g);l&&e(l)}}}),a.HtmlTag=a.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(b){a.Util.assign(this,b),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(a){return this.tagName=a,this},getTagName:function(){return this.tagName||""},setAttr:function(a,b){var c=this.getAttrs();return c[a]=b,this},getAttr:function(a){return this.getAttrs()[a]},setAttrs:function(b){var c=this.getAttrs();return a.Util.assign(c,b),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(a){return this.setAttr("class",a)},addClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);c=h.shift();)-1===f(g,c)&&g.push(c);return this.getAttrs()["class"]=g.join(" "),this},removeClass:function(b){for(var c,d=this.getClass(),e=this.whitespaceRegex,f=a.Util.indexOf,g=d?d.split(e):[],h=b.split(e);g.length&&(c=h.shift());){var i=f(g,c);-1!==i&&g.splice(i,1)}return this.getAttrs()["class"]=g.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(a){return-1!==(" "+this.getClass()+" ").indexOf(" "+a+" ")},setInnerHtml:function(a){return this.innerHtml=a,this},getInnerHtml:function(){return this.innerHtml||""},toString:function(){var a=this.getTagName(),b=this.buildAttrsStr();return b=b?" "+b:"",["<",a,b,">",this.getInnerHtml(),"</",a,">"].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var a=this.getAttrs(),b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c+'="'+a[c]+'"');return b.join(" ")}}),a.AnchorTagBuilder=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},build:function(b){var c=new a.HtmlTag({tagName:"a",attrs:this.createAttrs(b.getType(),b.getAnchorHref()),innerHtml:this.processAnchorText(b.getAnchorText())});return c},createAttrs:function(a,b){var c={href:b},d=this.createCssClass(a);return d&&(c["class"]=d),this.newWindow&&(c.target="_blank"),c},createCssClass:function(a){var b=this.className;return b?b+" "+b+"-"+a:""},processAnchorText:function(a){return a=this.doTruncate(a)},doTruncate:function(b){return a.Util.ellipsis(b,this.truncate||Number.POSITIVE_INFINITY)}}),a.match.Match=a.Util.extend(Object,{constructor:function(b){a.Util.assign(this,b)},getType:a.Util.abstractMethod,getMatchedText:function(){return this.matchedText},getAnchorHref:a.Util.abstractMethod,getAnchorText:a.Util.abstractMethod}),a.match.Email=a.Util.extend(a.match.Match,{getType:function(){return"email"},getEmail:function(){return this.email},getAnchorHref:function(){return"mailto:"+this.email},getAnchorText:function(){return this.email}}),a.match.Twitter=a.Util.extend(a.match.Match,{getType:function(){return"twitter"},getTwitterHandle:function(){return this.twitterHandle},getAnchorHref:function(){return"https://twitter.com/"+this.twitterHandle},getAnchorText:function(){return"@"+this.twitterHandle}}),a.match.Url=a.Util.extend(a.match.Match,{urlPrefixRegex:/^(https?:\/\/)?(www\.)?/i,protocolRelativeRegex:/^\/\//,checkForProtocolRegex:/^[A-Za-z]{3,9}:/,getType:function(){return"url"},getUrl:function(){var a=this.url;return this.protocolRelativeMatch||this.checkForProtocolRegex.test(a)||(a=this.url="http://"+a),a},getAnchorHref:function(){var a=this.getUrl();return a.replace(/&/g,"&")},getAnchorText:function(){var a=this.getUrl();return this.protocolRelativeMatch&&(a=this.stripProtocolRelativePrefix(a)),this.stripPrefix&&(a=this.stripUrlPrefix(a)),a=this.removeTrailingSlash(a)},stripUrlPrefix:function(a){return a.replace(this.urlPrefixRegex,"")},stripProtocolRelativePrefix:function(a){return a.replace(this.protocolRelativeRegex,"")},removeTrailingSlash:function(a){return"/"===a.charAt(a.length-1)&&(a=a.slice(0,-1)),a}}),a}); |
@@ -84,3 +84,3 @@ /*global require, module */ | ||
// docs output dir | ||
dest: 'docs', | ||
dest: 'gh-pages/docs', | ||
@@ -148,3 +148,3 @@ // extra options | ||
"/*global define, module */", | ||
"( function( root, factory ) {\n", | ||
"( function( root, factory ) {", | ||
"\tif( typeof define === 'function' && define.amd ) {", | ||
@@ -151,0 +151,0 @@ "\t\tdefine( factory ); // Define as AMD module if an AMD loader is present (ex: RequireJS).", |
{ | ||
"name": "autolinker", | ||
"version": "0.12.3", | ||
"version": "0.12.4", | ||
"description": "Utility to automatically link the URLs, email addresses, and Twitter handles in a given block of text/HTML", | ||
@@ -5,0 +5,0 @@ "main": "dist/Autolinker.js", |
214
README.md
@@ -59,3 +59,3 @@ # Autolinker.js | ||
Using the static `link()` method: | ||
Using the static [link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-static-method-link) method: | ||
@@ -75,3 +75,3 @@ ```javascript | ||
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). | ||
@@ -88,12 +88,12 @@ | ||
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 | ||
@@ -108,9 +108,9 @@ plus "url"/"email"/"twitter" suffixes for styling url/email/twitter links differently. | ||
- **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 | ||
@@ -120,3 +120,3 @@ <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: | ||
@@ -143,3 +143,3 @@ ```javascript | ||
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): | ||
@@ -164,3 +164,3 @@ ```javascript | ||
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. | ||
@@ -175,35 +175,35 @@ | ||
replaceFn : function( autolinker, match ) { | ||
console.log( "href = ", match.getAnchorHref() ); | ||
console.log( "text = ", match.getAnchorText() ); | ||
console.log( "href = ", match.getAnchorHref() ); | ||
console.log( "text = ", match.getAnchorText() ); | ||
switch( match.getType() ) { | ||
case 'url' : | ||
console.log( "url: ", match.getUrl() ); | ||
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' ); | ||
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; | ||
return tag; | ||
} else { | ||
return true; // let Autolinker perform its normal anchor tag replacement | ||
} | ||
} else { | ||
return true; // let Autolinker perform its normal anchor tag replacement | ||
} | ||
case 'email' : | ||
var email = match.getEmail(); | ||
console.log( "email: ", email ); | ||
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`) | ||
} | ||
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>'; | ||
case 'twitter' : | ||
var twitterHandle = match.getTwitterHandle(); | ||
console.log( twitterHandle ); | ||
return '<a href="http://newplace.to.link.twitter.handles.to/">' + twitterHandle + '</a>'; | ||
} | ||
@@ -218,4 +218,4 @@ } | ||
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. | ||
@@ -229,3 +229,3 @@ | ||
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. | ||
@@ -238,124 +238,4 @@ | ||
## 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 <a> 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 </a> 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 wiki: [Changelog](https://github.com/gregjacobs/Autolinker.js/wiki/Changelog) |
@@ -224,3 +224,3 @@ /** | ||
// 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+&@#\/%=~_()|\$\*])?/; // note: optional part of the full regex | ||
@@ -328,3 +328,4 @@ return new RegExp( [ | ||
* | ||
* @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. | ||
@@ -439,72 +440,120 @@ */ | ||
processTextNode : function( text ) { | ||
var me = this, // for closure | ||
charBeforeProtocolRelMatchRegex = this.charBeforeProtocolRelMatchRegex; | ||
var me = this; // for closure | ||
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 matchDescObj = me.processCandidateMatch.apply( me, arguments ); // 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 {@link #isValidMatch}. 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} 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, 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( !this.isValidMatch( twitterMatch, emailAddressMatch, urlMatch, 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( this.matchHasUnbalancedClosingParen( matchStr ) ) { | ||
matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")" | ||
suffixStr = ")"; // this will be added after the generated <a> tag | ||
} | ||
if( emailAddressMatch ) { | ||
match = new Autolinker.match.Email( { matchedText: matchStr, email: emailAddressMatch } ); | ||
// 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 ) ) { | ||
matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")" | ||
suffixStr = ")"; // this will be added after the generated <a> tag | ||
} else if( twitterMatch ) { | ||
// fix up the `matchStr` if there was a preceding whitespace char, which was needed to determine the match | ||
// itself (since there are no look-behinds in JS regexes) | ||
if( twitterHandlePrefixWhitespaceChar ) { | ||
prefixStr = twitterHandlePrefixWhitespaceChar; | ||
matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match | ||
} | ||
match = new Autolinker.match.Twitter( { matchedText: matchStr, twitterHandle: twitterHandle } ); | ||
if( emailAddressMatch ) { | ||
match = new Autolinker.match.Email( { matchedText: matchStr, email: emailAddressMatch } ); | ||
} else { // url match | ||
// 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( this.charBeforeProtocolRelMatchRegex )[ 1 ] || ""; | ||
} else if( twitterMatch ) { | ||
// fix up the `matchStr` if there was a preceding whitespace char, which was needed to determine the match | ||
// itself (since there are no look-behinds in JS regexes) | ||
if( twitterHandlePrefixWhitespaceChar ) { | ||
prefixStr = twitterHandlePrefixWhitespaceChar; | ||
matchStr = matchStr.slice( 1 ); // remove the prefixed whitespace char from the match | ||
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; | ||
matchStr = matchStr.slice( 1 ); // remove the prefixed char from the match | ||
} | ||
match = new Autolinker.match.Twitter( { matchedText: matchStr, twitterHandle: twitterHandle } ); | ||
} else { // url match | ||
// 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 ] || ""; | ||
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; | ||
matchStr = matchStr.slice( 1 ); // remove the prefixed char from the match | ||
} | ||
} | ||
match = new Autolinker.match.Url( { | ||
matchedText : matchStr, | ||
url : matchStr, | ||
protocolRelativeMatch : protocolRelativeMatch, | ||
stripPrefix : me.stripPrefix | ||
} ); | ||
} | ||
// Generate the replacement text for the match | ||
var matchReturnVal = me.createMatchReturnVal( match, matchStr ); | ||
return prefixStr + matchReturnVal + suffixStr; | ||
} ); | ||
match = new Autolinker.match.Url( { | ||
matchedText : matchStr, | ||
url : matchStr, | ||
protocolRelativeMatch : protocolRelativeMatch, | ||
stripPrefix : this.stripPrefix | ||
} ); | ||
} | ||
return { | ||
prefixStr : prefixStr, | ||
suffixStr : suffixStr, | ||
matchStr : matchStr, | ||
match : match | ||
}; | ||
}, | ||
/** | ||
@@ -633,4 +682,4 @@ * Determines if a given match found by {@link #processTextNode} is valid. Will return `false` for: | ||
* @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). | ||
@@ -640,5 +689,5 @@ * See the class description for an example call. | ||
*/ | ||
Autolinker.link = function( text, options ) { | ||
Autolinker.link = function( textOrHtml, options ) { | ||
var autolinker = new Autolinker( options ); | ||
return autolinker.link( text ); | ||
return autolinker.link( textOrHtml ); | ||
}; | ||
@@ -645,0 +694,0 @@ |
@@ -27,3 +27,3 @@ /*global Autolinker */ | ||
* @cfg {Boolean} stripPrefix (required) | ||
* @inheritdoc {@link Autolinker#stripPrefix} | ||
* @inheritdoc Autolinker#stripPrefix | ||
*/ | ||
@@ -30,0 +30,0 @@ |
@@ -24,3 +24,3 @@ /*global Autolinker */ | ||
* @param {Object} src The source object. | ||
* @return {Object} The destination object. | ||
* @return {Object} The destination object (`dest`) | ||
*/ | ||
@@ -27,0 +27,0 @@ assign : function( dest, src ) { |
@@ -337,2 +337,29 @@ /*global Autolinker, _, describe, beforeEach, afterEach, it, expect */ | ||
describe( "Special character handling", function() { | ||
it( "should include $ in URLs", function() { | ||
var result = autolinker.link( "Check out pair programming: http://c2.com/cgi/wiki$?VirtualPairProgramming" ); | ||
expect( result ).toBe( 'Check out pair programming: <a href="http://c2.com/cgi/wiki$?VirtualPairProgramming">c2.com/cgi/wiki$?VirtualPairProgramming</a>' ); | ||
} ); | ||
it( "should include $ in URLs with query strings", function() { | ||
var result = autolinker.link( "Check out the image at http://server.com/template?fmt=jpeg&$base=700." ); | ||
expect( result ).toBe( 'Check out the image at <a href="http://server.com/template?fmt=jpeg&$base=700">server.com/template?fmt=jpeg&$base=700</a>.' ); | ||
} ); | ||
it( "should include * in URLs", function() { | ||
var result = autolinker.link( "Google from wayback http://wayback.archive.org/web/*/http://google.com" ); | ||
expect( result ).toBe( 'Google from wayback <a href="http://wayback.archive.org/web/*/http://google.com">wayback.archive.org/web/*/http://google.com</a>' ); | ||
} ); | ||
it( "should include * in URLs with query strings", function() { | ||
var result = autolinker.link( "Twitter search for bob smith https://api.twitter.com/1.1/users/search.json?count=20&q=Bob+*+Smith" ); | ||
expect( result ).toBe( 'Twitter search for bob smith <a href="https://api.twitter.com/1.1/users/search.json?count=20&q=Bob+*+Smith">api.twitter.com/1.1/users/search.json?count=20&q=Bob+*+Smith</a>' ); | ||
} ); | ||
} ); | ||
describe( "URL path, query string, and hash handling", function() { | ||
@@ -339,0 +366,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
3118216
469
4662
231