2 * Readmore.js jQuery plugin
4 * Project home: jedfoster.github.io/Readmore.js
5 * Licensed under the MIT license
10 var readmore = 'readmore',
15 moreLink: '<a href="#">Read More</a>',
16 lessLink: '<a href="#">Close</a>',
18 sectionCSS: 'display: block; width: 100%;',
20 expandedClass: 'readmore-js-expanded',
21 collapsedClass: 'readmore-js-collapsed',
24 beforeToggle: function(){},
25 afterToggle: function(){}
29 function Readmore( element, options ) {
30 this.element = element;
32 this.options = $.extend( {}, defaults, options);
34 $(this.element).data('max-height', this.options.maxHeight);
35 $(this.element).data('height-margin', this.options.heightMargin);
37 delete(this.options.maxHeight);
39 if(this.options.embedCSS && ! cssEmbedded) {
40 var styles = '.readmore-js-toggle, .readmore-js-section { ' + this.options.sectionCSS + ' } .readmore-js-section { overflow: hidden; }';
43 var css=d.createElement('style');
44 css.type = 'text/css';
46 css.styleSheet.cssText = u;
49 css.appendChild(d.createTextNode(u));
51 d.getElementsByTagName('head')[0].appendChild(css);
57 this._defaults = defaults;
58 this._name = readmore;
63 Readmore.prototype = {
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');
73 if(current.css('max-height') != 'none') {
74 current.css('max-height', 'none');
77 $this.setBoxHeight(current);
79 if(current.outerHeight(true) <= maxHeight + heightMargin) {
80 // The block is shorter than the limit, so there's no need to truncate it.
84 current.addClass('readmore-js-section ' + $this.options.collapsedClass).data('collapsedHeight', maxHeight);
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'));
89 if(!$this.options.startOpen) {
90 current.css({height: maxHeight});
95 $(window).on('resize', function(event) {
100 toggleSlider: function(trigger, element, event)
102 event.preventDefault();
105 newHeight = newLink = sectionClass = '',
107 collapsedHeight = $(element).data('collapsedHeight');
109 if ($(element).height() <= collapsedHeight) {
110 newHeight = $(element).data('expandedHeight') + 'px';
111 newLink = 'lessLink';
113 sectionClass = $this.options.expandedClass;
117 newHeight = collapsedHeight;
118 newLink = 'moreLink';
119 sectionClass = $this.options.collapsedClass;
122 // Fire beforeToggle callback
123 $this.options.beforeToggle(trigger, element, expanded);
125 $(element).animate({'height': newHeight}, {duration: $this.options.speed, complete: function() {
126 // Fire afterToggle callback
127 $this.options.afterToggle(trigger, element, expanded);
129 $(trigger).replaceWith($($this.options[newLink]).on('click', function(event) { $this.toggleSlider(this, element, event) }).addClass('readmore-js-toggle'));
131 $(this).removeClass($this.options.collapsedClass + ' ' + $this.options.expandedClass).addClass(sectionClass);
136 setBoxHeight: function(element) {
137 var el = element.clone().css({'height': 'auto', 'width': element.width(), 'overflow': 'hidden'}).insertAfter(element),
138 height = el.outerHeight(true);
142 element.data('expandedHeight', height);
145 resizeBoxes: function() {
148 $('.readmore-js-section').each(function() {
149 var current = $(this);
151 $this.setBoxHeight(current);
153 if(current.height() > current.data('expandedHeight') || (current.hasClass($this.options.expandedClass) && current.height() < current.data('expandedHeight')) ) {
154 current.css('height', current.data('expandedHeight'));
159 destroy: function() {
162 $(this.element).each(function() {
163 var current = $(this);
165 current.removeClass('readmore-js-section ' + $this.options.collapsedClass + ' ' + $this.options.expandedClass).css({'max-height': '', 'height': 'auto'}).next('.readmore-js-toggle').remove();
167 current.removeData();
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);
181 $.data(this, 'plugin_' + readmore, new Readmore( this, options ));
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 ) );