PageSourceSearch

https://royalpalaces.se/download/18.5699e5e2194ce031fc284f60/1740125111176/jquery.expandable-content.js

js royalpalaces.se collected 2026-10-02 21:50:30 UTC 10,705 bytes, 358 lines download raw bytes

1/**
2 * @file Expandable Content. jQuery plugin which simplifies accordions in SiteVision.
3 * @author Hampus Nordin <[email protected]>
4 * @copyright Limepark AB
5 * @license https://limepark.se/licensvillkor
6 * @module expandableContent
7 * @version 1.2.1
8 */
9
10/* eslint-disable no-magic-numbers */
11
12/* console shim */
13(function () {
14  var f = function () {
15    // ...
16  };
17  if (!window.console) {
18    window.console = {
19      log:f, info:f, warn:f, debug:f, error:f
20    };
21  }
22}());
23
24/* global define, module, $svjq, jQuery, require, lp */
25(function (factory) {
26  'use strict';
27
28  // Use SiteVision's jQuery and fallback on global.
29  /* eslint-disable no-global-assign */
30  jQuery = $svjq || jQuery;
31  /* eslint-enable no-global-assign */
32
33  if (typeof define === 'function' && define.amd) {
34    // AMD. Register as an anonymous module.
35    define(['jquery'], factory);
36  } else if (typeof module === 'object' && module.exports) {
37    // Node/CommonJS
38    module.exports = function( root, jQuery ) {
39      if ( jQuery === undefined ) {
40        // require('jQuery') returns a factory that requires window to
41        // build a jQuery instance, we normalize how we use modules
42        // that require this pattern but the window provided is a noop
43        // if it's defined (how jquery works)
44        if ( typeof window !== 'undefined' ) {
45          jQuery = require('jquery');
46        }
47        else {
48          jQuery = require('jquery')(root);
49        }
50      }
51      factory(jQuery);
52      return jQuery;
53    };
54  } else {
55    // Browser globals
56    factory(jQuery);
57  }
58}(function ($) {
59  'use strict';
60
61  var pluginName = 'expandableContent';
62  var eventKey = 'expandable-content';
63  var events = {
64    "CHANGE": "change." + eventKey,
65    "TOGGLE": "toggle." + eventKey
66  };
67
68  // Extract query parameters from url string as js object.
69  function queryParamsFromUrlString (urlString) {
70    var queryDict = {};
71    var pair;
72    (urlString.split('?')[1] || '').split('&').forEach(function(item) {
73      pair = item.split('=');
74      if (pair[0]) {
75        queryDict[pair[0]] = pair[1];
76      }
77    });
78    return queryDict;
79  }
80
81  // Convert an SiteVision NodeId to it's corresponding html ID.
82  function svid2htmlid (svid) {
83    return 'svid' + (svid + '').replace('.', '_');
84  }
85
86  // Callback for when toggling is finished.
87  function toggleCallback (plugin) {
88    var $toggler = this.$elem;
89
90    // Trigger custom event.
91    $toggler.trigger(events.TOGGLE, [this, plugin]);
92
93    if (this.isOpen()) {
94      $toggler
95        .addClass(plugin.options.openClass)
96        .removeClass(plugin.options.closedClass)
97        .removeClass(plugin.options.openingClass);
98    } else {
99      $toggler
100        .addClass(plugin.options.closedClass)
101        .removeClass(plugin.options.openClass)
102        .removeClass(plugin.options.closingClass);
103    }
104  }
105
106  // Callback for when toggling is starting.
107  function changeCallback (plugin, isOpen) {
108    var $toggler = this.$elem;
109
110    // Trigger custom event.
111    $toggler.trigger(events.CHANGE, [this, plugin, isOpen]);
112
113    if (isOpen) {
114      $toggler.addClass(plugin.options.openingClass);
115    } else {
116      $toggler.addClass(plugin.options.closingClass);
117    }
118  }
119
120  // The actual plugin constructor
121  function Plugin (element, options) {
122    this.element    = element;
123    this.options    = $.extend(true, {}, $.fn[pluginName].defaults, options);
124    this._name      = pluginName;
125    this._toggles   = [];
126
127    this.init();
128  }
129
130  $.extend(Plugin.prototype, {
131    init: function () {
132      var $element = $(this.element);
133      var $children = $element.children();
134
135      // Iterate over every second child.
136      for (var i = 0; i < $children.length; i += 2) {
137        var $toggler = $children.eq(i);
138        var $content = $children.eq(i + 1);
139
140        if (typeof this.options.createButton === 'function') {
141          $toggler = this.options.createButton($toggler, this);
142        }
143
144        if (typeof this.options.createContent === 'function') {
145          $content = this.options.createContent($content, this);
146        }
147
148        if (this.options.wrapClass) {
149          $toggler.add($content).wrapAll('<div class="' + this.options.wrapClass + '">');
150        }
151
152        if (typeof this.options.toggleOptions !== 'object') {
153          this.options.toggleOptions = {};
154        }
155
156        // Setup toggler
157        var toggle = lp.toggle.setup($toggler, $content, this.options.toggleOptions);
158        toggle
159          .opened(toggleCallback.bind(toggle, this))
160          .closed(toggleCallback.bind(toggle, this))
161          .change(changeCallback.bind(toggle, this));
162
163        this._toggles.push(toggle);
164      }
165
166      if (this.options.autoOpenOnUrl) {
167        this.openByUrl();
168      }
169    },
170    destroy: function () {
171      // Todo
172      /* eslint-disable no-console */
173      console.info('Plugin.prototype.destroy is not implemented yet.');
174      /* eslint-enable no-console */
175    },
176    openByUrl: function () {
177      var plugin = this;
178
179      $(function () {
180        var href         = location.href;
181        var locationHash = (href.split("#")[1] || "");
182        var queryParams  = queryParamsFromUrlString(href);
183
184        var urlEls = [];
185        if (locationHash) {
186          var locationEl = '';
187          try {
188            locationEl = $('#' + locationHash).get(0);
189          } catch (e) {
190            // ...
191          }
192          
193          if (locationEl) {
194            urlEls.push(locationEl);
195          }
196        }
197        if (queryParams['sv.url']) {
198          var queryEl = $('#' + svid2htmlid(queryParams['sv.url'])).get(0);
199          if (queryEl) {
200            urlEls.push(queryEl);
201          }
202        }
203
204        if (urlEls.length) {
205          for (var i = plugin._toggles.length - 1; i >= 0; i--) {
206            var j = urlEls.length;
207            var wrapEl = plugin._toggles[i].$elem.closest('.' + plugin.options.wrapClass).get(0);
208            while (j--) {
209              if ($.contains(wrapEl, urlEls[j])) {
210                plugin._toggles[i].open();
211                urlEls.splice(j, 1);
212              }
213            }
214
215            if (urlEls.length === 0) {
216              break;
217            }
218          }
219        }
220      });
221    },
222    helpers: {
223      setAttributes: function (node, attrs) {
224        var attr;
225        var attrFunc;
226        for (var i = attrs.length - 1; i >= 0; i--) {
227          // `attr` should be an array of either 2 or 3 strings
228          attr = attrs[i];
229          if (attr.length === 3 || attr.length === 2) {
230            // Choose either setAttributeNS or setAttribute depending on length of `attr`.
231            attrFunc = attr.length === 3 ? node.setAttributeNS : node.setAttribute;
232            // Apply attr to node.
233            attrFunc.apply(node, attr);
234          }
235        }
236      },
237      _createSvgIcon: function (iconUrl, iconClass) {
238        var useNode = document.createElementNS('http://www.w3.org/2000/svg', 'use');
239        var svgNode = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
240
241        // Set attributes on <use>
242        this.setAttributes(useNode, [
243          ['http://www.w3.org/1999/xlink', 'xlink:href', iconUrl],
244          ['http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink']
245        ]);
246
247        // Set attributes on <svg>
248        this.setAttributes(svgNode, [
249          ['aria-hidden', 'true'],
250          ['class', iconClass || 'lp-icon']
251        ]);
252
253        // add <use> to <svg>
254        svgNode.appendChild(useNode);
255
256        return svgNode;
257      },
258      _createImgIcon: function (iconUrl, iconClass) {
259        var imgNode = document.createElement('img');
260
261        // Set attributes on <img>
262        this.setAttributes(imgNode, [
263          ['class', iconClass || 'lp-icon'],
264          ['alt', ''],
265          ['src', iconUrl]
266        ]);
267
268        return imgNode;
269      },
270      createIcon: function (iconUrl, iconClass) {
271        if (!!iconUrl.match(/\.svg(#[a-z0-9-_]+)?$/i)) {
272          return this._createSvgIcon(iconUrl, iconClass);
273        } else {
274          return this._createImgIcon(iconUrl, iconClass);
275        }
276      },
277      append: function (icon, target) {
278        target.appendChild(icon);
279      },
280      prepend: function (icon, target) {
281        var refNode = target.firstChild;
282        target.insertBefore(icon, refNode);
283      }
284    }
285  });
286
287  /**
288   * Plugin wrapper
289   *
290   * A really lightweight plugin wrapper around the constructor,
291   * preventing against multiple instantiations.
292   *
293   * @param  {Object|String}  options
294   * @return {jQuery}
295   */
296  $.fn[pluginName] = function (options) {
297    var key = "plugin_" + pluginName;
298
299    if (typeof window.lp === 'undefined' || typeof window.lp.toggle === 'undefined') {
300      /* eslint-disable no-console */
301      console.warn('Missing dependency: lp.toggle');
302      /* eslint-enable no-console */
303      return this;
304    }
305
306    return this.each(function () {
307      var plugin = $.data(this, key);
308
309      if (!plugin) {
310        plugin = new Plugin(this, options);
311        $.data(this, key, plugin);
312      } else if (options === 'destroy') {
313        plugin.destroy();
314        $.removeData(this, key);
315      }
316    });
317  };
318
319  /**
320   * Default options
321   *
322   * @type {Object}
323   */
324  $.fn[pluginName].defaults = {
325    buttonClass:   "lp-expandable-content__toggler",
326    contentClass:  "lp-expandable-content__content",
327    wrapClass:     "lp-expandable-content__wrap",
328    openClass:     "lp-expandable-content--is-open",
329    closedClass:   "lp-expandable-content--is-closed",
330    openingClass:  "lp-expandable-content--is-opening",
331    closingClass:  "lp-expandable-content--is-closing",
332    iconOpen:      "/webdav/files/system/svg/lp-icons.svg#lp-plus",
333    iconClose:     "/webdav/files/system/svg/lp-icons.svg#lp-minus",
334    autoOpenOnUrl: true,
335    toggleOptions: {},
336    createButton: function ($content, plugin) {
337      var $toggler = $content.is('button') ? $content : $content.wrap('<button>').parent();
338
339      $toggler.addClass(plugin.options.buttonClass);
340
341      // Create icons and add them to toggler.
342      if (plugin.options.iconOpen) {
343        var iconOpenEl = plugin.helpers.createIcon(plugin.options.iconOpen, 'lp-icon lp-toggler-icon lp-toggler-icon--open');
344        plugin.helpers.prepend(iconOpenEl, $toggler.get(0));
345      }
346      if (plugin.options.iconClose) {
347        var iconCloseEl = plugin.helpers.createIcon(plugin.options.iconClose, 'lp-icon lp-toggler-icon lp-toggler-icon--close');
348        plugin.helpers.prepend(iconCloseEl, $toggler.get(0));
349      }
350
351      return $toggler;
352    },
353    createContent: function ($content, plugin) {
354      $content.addClass(plugin.options.contentClass);
355      return $content;
356    }
357  };
358}));

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.