PageSourceSearch

https://hub.farthinghalearms.com/library/readmore.js/readmore.js?v=11.4.1

js farthinghalearms.com collected 2026-10-07 21:29:20 UTC 9,194 bytes, 342 lines download raw bytes

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

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.