1/*! 2 * Readmore.js jQuery plugin 3 * Author: @jed_foster 4 * Project home: jedfoster.github.io/Readmore.js 5 * Licensed under the MIT license 6 */ 7 8;(function($) { 9 10 var readmore = 'readmore', 11 defaults = { 12 speed: 100, 13 maxHeight: 200, 14 heightMargin: 16, 15 moreLink: '<a href="#">Read More</a>', 16 lessLink: '<a href="#">Close</a>', 17 embedCSS: true, 18 sectionCSS: 'display: block; font-family: CenturyGothicRegular', 19 startOpen: false, 20 expandedClass: 'readmore-js-expanded', 21 collapsedClass: 'readmore-js-collapsed', 22 23 // callbacks 24 beforeToggle: function(){}, 25 afterToggle: function(){} 26 }, 27 cssEmbedded = false; 28 29 function Readmore( element, options ) { 30 this.element = element; 31 32 this.options = $.extend( {}, defaults, options); 33 34 $(this.element).data('max-height', this.options.maxHeight); 35 $(this.element).data('height-margin', this.options.heightMargin); 36 37 delete(this.options.maxHeight); 38 39 if(this.options.embedCSS && ! cssEmbedded) { 40 var styles = '.readmore-js-toggle, .readmore-js-section { ' + this.options.sectionCSS + ' } .readmore-js-section { overflow: hidden; }'; 41 42 (function(d,u) { 43 var css=d.createElement('style'); 44 css.type = 'text/css'; 45 if(css.styleSheet) { 46 css.styleSheet.cssText = u; 47 } 48 else { 49 css.appendChild(d.createTextNode(u)); 50 } 51 d.getElementsByTagName('head')[0].appendChild(css); 52 }(document, styles)); 53 54 cssEmbedded = true; 55 } 56 57 this._defaults = defaults; 58 this._name = readmore; 59 60 this.init(); 61 } 62 63 Readmore.prototype = { 64 65 init: function() { 66 var $this = this; 67 68 $(this.element).each(function() { 69 var current = $(this), 70 maxHeight = (current.css('max-height').replace(/[^-\d\.]/g, '') > current.data('max-height')) ? current.css('max-height').replace(/[^-\d\.]/g, '') : current.data('max-height'), 71 heightMargin = current.data('height-margin'); 72 73 if(current.css('max-height') != 'none') { 74 current.css('max-height', 'none'); 75 } 76 77 $this.setBoxHeight(current); 78 79 if(current.outerHeight(true) <= maxHeight + heightMargin) { 80 // The block is shorter than the limit, so there's no need to truncate it. 81 return true; 82 } 83 else { 84 current.addClass('readmore-js-section ' + $this.options.collapsedClass).data('collapsedHeight', maxHeight); 85 86 var useLink = $this.options.startOpen ? $this.options.lessLink : $this.options.moreLink; 87 current.after($(useLink).on('click', function(event) { $this.toggleSlider(this, current, event) }).addClass('readmore-js-toggle')); 88 89 if(!$this.options.startOpen) { 90 current.css({height: maxHeight}); 91 } 92 } 93 }); 94 95 $(window).on('resize', function(event) { 96 $this.resizeBoxes(); 97 }); 98 }, 99 100 toggleSlider: function(trigger, element, event) 101 { 102 event.preventDefault(); 103 104 var $this = this, 105 newHeight = newLink = sectionClass = '', 106 expanded = false, 107 collapsedHeight = $(element).data('collapsedHeight'); 108 109 if ($(element).height() <= collapsedHeight) { 110 newHeight = $(element).data('expandedHeight') + 'px'; 111 newLink = 'lessLink'; 112 expanded = true; 113 sectionClass = $this.options.expandedClass; 114 } 115 116 else { 117 newHeight = collapsedHeight; 118 newLink = 'moreLink'; 119 sectionClass = $this.options.collapsedClass; 120 } 121 122 // Fire beforeToggle callback 123 $this.options.beforeToggle(trigger, element, expanded); 124 125 $(element).animate({'height': newHeight}, {duration: $this.options.speed, complete: function() { 126 // Fire afterToggle callback 127 $this.options.afterToggle(trigger, element, expanded); 128 129 $(trigger).replaceWith($($this.options[newLink]).on('click', function(event) { $this.toggleSlider(this, element, event) }).addClass('readmore-js-toggle')); 130 131 $(this).removeClass($this.options.collapsedClass + ' ' + $this.options.expandedClass).addClass(sectionClass); 132 } 133 }); 134 }, 135 136 setBoxHeight: function(element) { 137 var el = element.clone().css({'height': 'auto', 'width': element.width(), 'overflow': 'hidden'}).insertAfter(element), 138 height = el.outerHeight(true); 139 140 el.remove(); 141 142 element.data('expandedHeight', height); 143 }, 144 145 resizeBoxes: function() { 146 var $this = this; 147 148 $('.readmore-js-section').each(function() { 149 var current = $(this); 150 151 $this.setBoxHeight(current); 152 153 if(current.height() > current.data('expandedHeight') || (current.hasClass($this.options.expandedClass) && current.height() < current.data('expandedHeight')) ) { 154 current.css('height', current.data('expandedHeight')); 155 } 156 }); 157 }, 158 159 destroy: function() { 160 var $this = this; 161 162 $(this.element).each(function() { 163 var current = $(this); 164 165 current.removeClass('readmore-js-section ' + $this.options.collapsedClass + ' ' + $this.options.expandedClass).css({'max-height': '', 'height': 'auto'}).next('.readmore-js-toggle').remove(); 166 167 current.removeData(); 168 }); 169 } 170 }; 171 172 $.fn[readmore] = function( options ) { 173 var args = arguments; 174 if (options === undefined || typeof options === 'object') { 175 return this.each(function () { 176 if ($.data(this, 'plugin_' + readmore)) { 177 var instance = $.data(this, 'plugin_' + readmore); 178 instance['destroy'].apply(instance); 179 } 180 181 $.data(this, 'plugin_' + readmore, new Readmore( this, options )); 182 }); 183 } else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { 184 return this.each(function () { 185 var instance = $.data(this, 'plugin_' + readmore); 186 if (instance instanceof Readmore && typeof instance[options] === 'function') { 187 instance[options].apply( instance, Array.prototype.slice.call( args, 1 ) ); 188 } 189 }); 190 } 191 } 192})(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.