1/*! 2 * @preserve 3 * 4 * Readmore.js jQuery plugin 5 * Author: @jed_foster 6 * Project home: http://jedfoster.github.io/Readmore.js 7 * Licensed under the MIT license 8 * 9 * Debounce function from http://davidwalsh.name/javascript-debounce-function 10 */ 11 12/* global jQuery */ 13 14(function($) { 15 'use strict'; 16 17 var readmore = 'readmore', 18 defaults = { 19 speed: 100, 20 collapsedHeight: 200, 21 heightMargin: 16, 22 moreLink: '<a href="#">Leggi tutto</a>', 23 lessLink: '<a href="#">Chiudi</a>', 24 embedCSS: true, 25 blockCSS: 'display: block; width: 100%;', 26 startOpen: false, 27 28 // callbacks 29 beforeToggle: function(){}, 30 afterToggle: function(){} 31 }, 32 cssEmbedded = {}, 33 uniqueIdCounter = 0; 34 35 function debounce(func, wait, immediate) { 36 var timeout; 37 38 return function() { 39 var context = this, args = arguments; 40 var later = function() { 41 timeout = null; 42 if (! immediate) { 43 func.apply(context, args); 44 } 45 }; 46 var callNow = immediate && !timeout; 47 48 clearTimeout(timeout); 49 timeout = setTimeout(later, wait); 50 51 if (callNow) { 52 func.apply(context, args); 53 } 54 }; 55 } 56 57 function uniqueId(prefix) { 58 var id = ++uniqueIdCounter; 59 60 return String(prefix == null ? 'rmjs-' : prefix) + id; 61 } 62 63 function setBoxHeights(element) { 64 var el = element.clone().css({ 65 height: 'auto', 66 width: element.width(), 67 maxHeight: 'none', 68 overflow: 'hidden' 69 }).insertAfter(element), 70 expandedHeight = el.outerHeight(), 71 cssMaxHeight = parseInt(el.css({maxHeight: ''}).css('max-height').replace(/[^-\d\.]/g, ''), 10), 72 defaultHeight = element.data('defaultHeight'); 73 74 el.remove(); 75 76 var collapsedHeight = cssMaxHeight || element.data('collapsedHeight') || defaultHeight; 77 78 // Store our measurements. 79 element.data({ 80 expandedHeight: expandedHeight, 81 maxHeight: cssMaxHeight, 82 collapsedHeight: collapsedHeight 83 }) 84 // and disable any `max-height` property set in CSS 85 .css({ 86 maxHeight: 'none' 87 }); 88 } 89 90 var resizeBoxes = debounce(function() { 91 $('[data-readmore]').each(function() { 92 var current = $(this), 93 isExpanded = (current.attr('aria-expanded') === 'true'); 94 95 setBoxHeights(current); 96 97 current.css({ 98 height: current.data( (isExpanded ? 'expandedHeight' : 'collapsedHeight') ) 99 }); 100 }); 101 }, 100); 102 103 function embedCSS(options) { 104 if (! cssEmbedded[options.selector]) { 105 var styles = ' '; 106 107 if (options.embedCSS && options.blockCSS !== '') { 108 styles += options.selector + ' + [data-readmore-toggle], ' + 109 options.selector + '[data-readmore]{' + 110 options.blockCSS + 111 '}'; 112 } 113 114 // Include the transition CSS even if embedCSS is false 115 styles += options.selector + '[data-readmore]{' + 116 'transition: height ' + options.speed + 'ms;' + 117 'overflow: hidden;' + 118 '}'; 119 120 (function(d, u) { 121 var css = d.createElement('style'); 122 css.type = 'text/css'; 123 124 if (css.styleSheet) { 125 css.styleSheet.cssText = u; 126 } 127 else { 128 css.appendChild(d.createTextNode(u)); 129 } 130 131 d.getElementsByTagName('head')[0].appendChild(css); 132 }(document, styles)); 133 134 cssEmbedded[options.selector] = true; 135 } 136 } 137 138 function Readmore(element, options) { 139 var $this = this; 140 141 this.element = element; 142 143 this.options = $.extend({}, defaults, options); 144 145 embedCSS(this.options); 146 147 this._defaults = defaults; 148 this._name = readmore; 149 150 this.init(); 151 152 // IE8 chokes on `window.addEventListener`, so need to test for support. 153 if (window.addEventListener) { 154 // Need to resize boxes when the page has fully loaded. 155 window.addEventListener('load', resizeBoxes); 156 window.addEventListener('resize', resizeBoxes); 157 } 158 else { 159 window.attachEvent('load', resizeBoxes); 160 window.attachEvent('resize', resizeBoxes); 161 } 162 } 163 164 165 Readmore.prototype = { 166 init: function() { 167 var $this = this, 168 current = $(this.element); 169 170 current.data({ 171 defaultHeight: this.options.collapsedHeight, 172 heightMargin: this.options.heightMargin 173 }); 174 175 setBoxHeights(current); 176 177 var collapsedHeight = current.data('collapsedHeight'), 178 heightMargin = current.data('heightMargin'); 179 180 if (current.outerHeight(true) <= collapsedHeight + heightMargin) { 181 // The block is shorter than the limit, so there's no need to truncate it. 182 return true; 183 } 184 else { 185 var id = current.attr('id') || uniqueId(), 186 useLink = $this.options.startOpen ? $this.options.lessLink : $this.options.moreLink; 187 188 current.attr({ 189 'data-readmore': '', 190 'aria-expanded': false, 191 'id': id 192 }); 193 194 current.after($(useLink) 195 .on('click', function(event) { $this.toggle(this, current[0], event); }) 196 .attr({ 197 'data-readmore-toggle': '', 198 'aria-controls': id 199 })); 200 201 if (! $this.options.startOpen) { 202 current.css({ 203 height: collapsedHeight 204 }); 205 } 206 } 207 }, 208 209 toggle: function(trigger, element, event) { 210 if (event) { 211 event.preventDefault(); 212 } 213 214 if (! trigger) {
215 trigger = $('[aria-controls="' + this.element.id + '"]')[0]; 216 } 217 218 if (! element) { 219 element = this.element; 220 } 221 222 var $this = this, 223 $element = $(element), 224 newHeight = '', 225 newLink = '', 226 expanded = false, 227 collapsedHeight = $element.data('collapsedHeight'); 228 229 if ($element.height() <= collapsedHeight) { 230 newHeight = $element.data('expandedHeight') + 'px'; 231 newLink = 'lessLink'; 232 expanded = true; 233 } 234 else { 235 newHeight = collapsedHeight; 236 newLink = 'moreLink'; 237 } 238 239 // Fire beforeToggle callback 240 // Since we determined the new "expanded" state above we're now out of sync 241 // with our true current state, so we need to flip the value of `expanded` 242 $this.options.beforeToggle(trigger, element, ! expanded); 243 244 $element.css({'height': newHeight}); 245 246 // Fire afterToggle callback 247 $element.on('transitionend', function() { 248 $this.options.afterToggle(trigger, element, expanded); 249 250 $(this).attr({ 251 'aria-expanded': expanded 252 }).off('transitionend'); 253 }); 254 255 $(trigger).replaceWith($($this.options[newLink]) 256 .on('click', function(event) { $this.toggle(this, element, event); }) 257 .attr({ 258 'data-readmore-toggle': '', 259 'aria-controls': $element.attr('id') 260 })); 261 }, 262 263 destroy: function() { 264 $(this.element).each(function() { 265 var current = $(this); 266 267 current.attr({ 268 'data-readmore': null, 269 'aria-expanded': null 270 }) 271 .css({ 272 maxHeight: '', 273 height: '' 274 }) 275 .next('[data-readmore-toggle]') 276 .remove(); 277 278 current.removeData(); 279 }); 280 } 281 }; 282 283 284 $.fn.readmore = function(options) { 285 var args = arguments, 286 selector = this.selector; 287 288 options = options || {}; 289 290 if (typeof options === 'object') { 291 return this.each(function() { 292 if ($.data(this, 'plugin_' + readmore)) { 293 var instance = $.data(this, 'plugin_' + readmore); 294 instance.destroy.apply(instance); 295 } 296 297 options.selector = selector; 298 299 $.data(this, 'plugin_' + readmore, new Readmore(this, options)); 300 }); 301 } 302 else if (typeof options === 'string' && options[0] !== '_' && options !== 'init') { 303 return this.each(function () { 304 var instance = $.data(this, 'plugin_' + readmore); 305 if (instance instanceof Readmore && typeof instance[options] === 'function') { 306 instance[options].apply(instance, Array.prototype.slice.call(args, 1)); 307 } 308 }); 309 } 310 }; 311 312})(jQuery); 313
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.