1/* http://keith-wood.name/more.html 2 Text truncation and show more for jQuery v2.0.1. 3 Written by Keith Wood (kwood{at}iinet.com.au) May 2010. 4 Available under the MIT (https://github.com/jquery/jquery/blob/master/LICENSE.txt) license. 5 Please attribute the author if you use it. */ 6 7(function($) { // Hide scope, no $ conflict 8 9 var pluginName = 'more'; 10 11 /** Create the more plugin. 12 <p>Sets an element to hide/show additional text.</p> 13 <p>Expects HTML like:</p> 14 <pre><p>...</p></pre> 15 <p>Provide inline configuration like:</p> 16 <pre><p data-more="name: 'value'">...</p></pre> 17 @module More 18 @augments JQPlugin 19 @example $(selector).more() 20 $(selector).more({length: 200, toggle: false}) */ 21 $.JQPlugin.createPlugin({ 22 23 /** The name of the plugin. */ 24 name: pluginName, 25 26 /** More/less change callback. 27 Triggered when the more/less button is clicked. 28 @callback changeCallback 29 @param expanding {boolean} True if expanding the text, false if collapsing. */ 30 31 /** Default settings for the plugin. 32 @property [length=100] {number} Truncation length. 33 @property [leeway=5] {number} Overrun allowed without truncation. 34 @property [wordBreak=false] {boolean} True to break between words, false to break anywhere. 35 @property [ignoreTags=['br','hr','img']] {string[]} Non-terminated tags to ignore. 36 @property [toggle=true] {boolean} True to toggle, false to display and exit. 37 @property [ellipsisText='...'] {string} Display text for ellipsis. 38 @property [moreText='Show more'] {string} Display text for more link. 39 @property [lessText='Show less'] {string} Display text for less link. 40 @property [andNext=''] {string} Selector for any following tags to include in the collapse. 41 @property [onChange=null] {changeCallback} Callback function when expanded/collapsed. 42 @example onChange: function(expanding) { 43 console.log('Showing ' + (expanding ? 'more' : 'less')); 44 } */ 45 defaultOptions: { 46 length: 100, 47 leeway: 5, 48 wordBreak: false, 49 ignoreTags: ['br', 'hr', 'img'], 50 toggle: true, 51 ellipsisText: '...', 52 moreText: 'Show more', 53 lessText: 'Show less', 54 andNext: '', 55 onChange: null 56 }, 57 58 _ellipsisClass: pluginName + '-ellipsis', // The ellipsis marker class 59 _linkClass: pluginName + '-link', // The link marker class 60 _hiddenClass: pluginName + '-hidden', // The text hidden marker class 61 62 _tagName: /^<(\w+).*>$/, // Extract a tag name 63 64 _instSettings: function(elem, options) { 65 return {html: elem.html()}; 66 }, 67 68 _optionsChanged: function(elem, inst, options) { 69 var self = this; 70 $.extend(inst.options, options); 71 this._preDestroy(elem, inst); // Reset 72 var html = ''; 73 if (elem.text().length > inst.options.length + inst.options.leeway) { // If text is longer 74 var matches = elem.html().match(/(<[^>]+>)|([^<]+)/g); // Extract text and tags 75 var i = 0; 76 var pos = 0; 77 var tags = []; 78 for (; i < matches.length; i++) { 79 if (matches[i][0] === '<') { // A tag 80 if (matches[i][1] === '/' || matches[i][matches[i].length - 2] === '/') { 81 tags.pop(); // Closing 82 } 83 else if ($.inArray(matches[i].toLowerCase().replace(this._tagName, '$1'), 84 inst.options.ignoreTags) === -1) { 85 tags.push(matches[i]); // Opening 86 } 87 } 88 else if (pos + matches[i].length > inst.options.length) { // Found truncation point 89 break; 90 } 91 else { // Count text 92 pos += matches[i].length; 93 } 94 } 95 pos = inst.options.length - pos; // Split point 96 if (inst.options.wordBreak) { // Move back to start of word 97 var matched = matches[i].substring(0, pos + 1).replace('\n', ' ').match(/^.*\W/m); 98 pos = (matched ? matched[0].length - 1 : pos); 99 } 100 var closeTags = function(tags) { // Close any opened tags 101 var html = ''; 102 for (var i = tags.length - 1; i >= 0; i--) { 103 html += '</' + tags[i].replace(self._tagName, '$1') + '>'; 104 } 105 return html; 106 }; 107 // Generate new content 108 html = matches.slice(0, i).join('') + matches[i].substring(0, pos) + closeTags(tags) + 109 '<span class="' + this._ellipsisClass + '">' + inst.options.ellipsisText + '</span>' + 110 '<span class="' + this._hiddenClass + '">' + tags.join('') + 111 matches[i].substring(pos) + closeTags(tags) + matches.slice(i + 1).join('') + '</span>'; 112 } 113 else if (options.andNext && elem.nextAll(options.andNext).length) { 114 html = elem.html(); 115 } 116 if (html) { 117 html += '<a href="#" class="' + this._linkClass + '">' + inst.options.moreText + '</a>'; 118 elem.html(html).find('a.' + this._linkClass).click(function(event) { 119 var link = $(this); 120 var expanding = link.html() === inst.options.moreText; 121 link.html(expanding ? inst.options.lessText : inst.options.moreText). 122 siblings('span.' + self._ellipsisClass + ',span.' + self._hiddenClass).toggle(); 123 if (options.andNext) { 124 link.parent().nextAll(options.andNext).toggle(); 125 } 126 if (!inst.options.toggle) { // Once only 127 link.remove(); 128 } 129 if ($.isFunction(inst.options.onChange)) { // Callback 130 inst.options.onChange.apply(elem, [expanding]); 131 } 132 event.stopPropagation(); 133 return false; 134 }); 135 if (options.andNext) { 136 elem.nextAll(options.andNext).hide(); 137 } 138 } 139 }, 140 141 _preDestroy: function(elem, inst) { 142 elem.html(inst.html); 143 if (inst.options.andNext) { 144 elem.nextAll(inst.options.andNext).show(); 145 } 146 } 147 }); 148 149})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.