ref: master
public/javascripts/vendor/ba-linkify.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
/*! * JavaScript Linkify - v0.3 - 6/27/2009 * http://benalman.com/projects/javascript-linkify/ * * Copyright (c) 2009 "Cowboy" Ben Alman * Dual licensed under the MIT and GPL licenses. * http://benalman.com/about/license/ * * Some regexps adapted from http://userscripts.org/scripts/review/7122 */ // Script: JavaScript Linkify: Process links in text! // // *Version: 0.3, Last updated: 6/27/2009* // // Project Home - http://benalman.com/projects/javascript-linkify/ // GitHub - http://github.com/cowboy/javascript-linkify/ // Source - http://github.com/cowboy/javascript-linkify/raw/master/ba-linkify.js // (Minified) - http://github.com/cowboy/javascript-linkify/raw/master/ba-linkify.min.js (2.8kb) // // About: License // // Copyright (c) 2009 "Cowboy" Ben Alman, // Dual licensed under the MIT and GPL licenses. // http://benalman.com/about/license/ // // About: Examples // // This working example, complete with fully commented code, illustrates one way // in which this code can be used. // // Linkify - http://benalman.com/code/projects/javascript-linkify/examples/linkify/ // // About: Support and Testing // // Information about what browsers this code has been tested in. // // Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10. // // About: Release History // // 0.3 - (6/27/2009) Initial release // Function: linkify // // Turn text into linkified html. // // Usage: // // > var html = linkify( text [, options ] ); // // Arguments: // // text - (String) Non-HTML text containing links to be parsed. // options - (Object) An optional object containing linkify parse options. // // Options: // // callback (Function) - If specified, this will be called once for each link- // or non-link-chunk with two arguments, text and href. If the chunk is // non-link, href will be omitted. If unspecified, the default linkification // callback is used. // punct_regexp (RegExp) - A RegExp that will be used to trim trailing // punctuation from links, instead of the default. If set to null, trailing // punctuation will not be trimmed. // // Returns: // // (String) An HTML string containing links. window.linkify = (function(){ var SCHEME = "[a-z\\d.-]+://", IPV4 = "(?:(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.){3}(?:[0-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])", HOSTNAME = "(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)+", TLD = "(?:ac|ad|aero|ae|af|ag|ai|al|am|an|ao|aq|arpa|ar|asia|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|biz|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|cat|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|coop|com|co|cr|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|edu|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gov|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|info|int|in|io|iq|ir|is|it|je|jm|jobs|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|mil|mk|ml|mm|mn|mobi|mo|mp|mq|mr|ms|mt|museum|mu|mv|mw|mx|my|mz|name|na|nc|net|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|org|pa|pe|pf|pg|ph|pk|pl|pm|pn|pro|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|sy|sz|tc|td|tel|tf|tg|th|tj|tk|tl|tm|tn|to|tp|travel|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|xn--0zwm56d|xn--11b5bs3a9aj6g|xn--80akhbyknj4f|xn--9t4b11yi5a|xn--deba0ad|xn--g6w251d|xn--hgbk6aj7f53bba|xn--hlcj6aya9esc7a|xn--jxalpdlp|xn--kgbechtv|xn--zckzah|ye|yt|yu|za|zm|zw)", HOST_OR_IP = "(?:" + HOSTNAME + TLD + "|" + IPV4 + ")", PATH = "(?:[;/][^#?<>\\s]*)?", QUERY_FRAG = "(?:\\?[^#<>\\s]*)?(?:#[^<>\\s]*)?", URI1 = "\\b" + SCHEME + "[^<>\\s]+", URI2 = "\\b" + HOST_OR_IP + PATH + QUERY_FRAG + "(?!\\w)", MAILTO = "mailto:", EMAIL = "(?:" + MAILTO + ")?[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@" + HOST_OR_IP + QUERY_FRAG + "(?!\\w)", URI_RE = new RegExp( "(?:" + URI1 + "|" + URI2 + "|" + EMAIL + ")", "ig" ), SCHEME_RE = new RegExp( "^" + SCHEME, "i" ), quotes = { "'": "`", '>': '<', ')': '(', ']': '[', '}': '{', '»': '«', '›': '‹' }, default_options = { callback: function( text, href ) { return href ? '<a href="' + href + '" title="' + href + '">' + text + '</a>' : text; }, punct_regexp: /(?:[!?.,:;'"]|(?:&|&)(?:lt|gt|quot|apos|raquo|laquo|rsaquo|lsaquo);)$/ }; return function( txt, options ) { options = options || {}; // Temp variables. var arr, i, link, href, // Output HTML. html = '', // Store text / link parts, in order, for re-combination. parts = [], // Used for keeping track of indices in the text. idx_prev, idx_last, idx, link_last, // Used for trimming trailing punctuation and quotes from links. matches_begin, matches_end, quote_begin, quote_end; // Initialize options. for ( i in default_options ) { if ( options[ i ] === undefined ) { options[ i ] = default_options[ i ]; } } // Find links. while ( arr = URI_RE.exec( txt ) ) { link = arr[0]; idx_last = URI_RE.lastIndex; idx = idx_last - link.length; // Not a link if preceded by certain characters. if ( /[\/:]/.test( txt.charAt( idx - 1 ) ) ) { continue; } // Trim trailing punctuation. do { // If no changes are made, we don't want to loop forever! link_last = link; quote_end = link.substr( -1 ) quote_begin = quotes[ quote_end ]; // Ending quote character? if ( quote_begin ) { matches_begin = link.match( new RegExp( '\\' + quote_begin + '(?!$)', 'g' ) ); matches_end = link.match( new RegExp( '\\' + quote_end, 'g' ) ); // If quotes are unbalanced, remove trailing quote character. if ( ( matches_begin ? matches_begin.length : 0 ) < ( matches_end ? matches_end.length : 0 ) ) { link = link.substr( 0, link.length - 1 ); idx_last--; } } // Ending non-quote punctuation character? if ( options.punct_regexp ) { link = link.replace( options.punct_regexp, function(a){ idx_last -= a.length; return ''; }); } } while ( link.length && link !== link_last ); href = link; // Add appropriate protocol to naked links. if ( !SCHEME_RE.test( href ) ) { href = ( href.indexOf( '@' ) !== -1 ? ( !href.indexOf( MAILTO ) ? '' : MAILTO ) : !href.indexOf( 'irc.' ) ? 'irc://' : !href.indexOf( 'ftp.' ) ? 'ftp://' : 'http://' ) + href; } // Push preceding non-link text onto the array. if ( idx_prev != idx ) { parts.push([ txt.slice( idx_prev, idx ) ]); idx_prev = idx_last; } // Push massaged link onto the array parts.push([ link, href ]); }; // Push remaining non-link text onto the array. parts.push([ txt.substr( idx_prev ) ]); // Process the array items. for ( i = 0; i < parts.length; i++ ) { html += options.callback.apply( window, parts[i] ); } // In case of catastrophic failure, return the original text; return html || txt; }; })(); |