PageSourceSearch

https://www4.ti.ch/typo3conf/ext/theme/Resources/Public/bowercomponents/readmore/readmore.js?1776399229

js ti.ch collected 2026-09-24 08:49:13 UTC 8,175 bytes, 313 lines download raw bytes

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.