PageSourceSearch

https://odf.univ-spn.fr/skins/odf-univ-paris13/resources/templates…/plugins/hs-megamenu/src/hs.megamenu.js

js univ-spn.fr collected 2026-10-01 10:38:31 UTC 22,574 bytes, 1,000 lines download raw bytes

1/*
2 * HS Mega Menu - jQuery Plugin
3 * @version: 1.0.0 (Sun, 26 Feb 2017)
4 * @requires: jQuery v1.6 or later
5 * @author: HtmlStream
6 * @event-namespace: .HSMegaMenu
7 * @browser-support: IE9+
8 * @license:
9 *
10 * Copyright 2017 HtmlStream
11 *
12 */
13;(function ($) {
14  'use strict';
15
16  /**
17   * Creates a mega menu.
18   *
19   * @constructor
20   * @param {HTMLElement|jQuery} element - The element to create the mega menu for.
21   * @param {Object} options - The options
22   */
23
24  var MegaMenu = window.MegaMenu || {};
25
26  MegaMenu = (function () {
27
28    var isMenuOpened = false;
29
30    function MegaMenu(element, options) {
31
32      var self = this;
33
34      /**
35       * Current element.
36       *
37       * @public
38       */
39      this.$element = $(element);
40
41      /**
42       * Current options set by the caller including defaults.
43       *
44       * @public
45       */
46      this.options = $.extend(true, {}, MegaMenu.defaults, options);
47
48
49      /**
50       * Collection of menu elements.
51       *
52       * @private
53       */
54      this._items = $();
55
56
57      Object.defineProperties(this, {
58
59        /**
60         * Contains composed selector of menu items.
61         *
62         * @public
63         */
64        itemsSelector: {
65          get: function () {
66            return self.options.classMap.hasSubMenu + ',' +
67              self.options.classMap.hasMegaMenu;
68          }
69        },
70
71        /**
72         * Contains chain of active items.
73         *
74         * @private
75         */
76        _tempChain: {
77          value: null,
78          writable: true
79        },
80
81        /**
82         * Contains current behavior state.
83         *
84         * @public
85         */
86        state: {
87          value: null,
88          writable: true
89        }
90
91      });
92
93      this.initialize();
94
95    }
96
97    return MegaMenu;
98
99  }());
100
101
102  /**
103   * Default options of the mega menu.
104   *
105   * @public
106   */
107  MegaMenu.defaults = {
108    event: 'hover',
109    direction: 'horizontal',
110    breakpoint: 991,
111    animationIn: false,
112    animationOut: false,
113
114    rtl: false,
115    hideTimeOut: 300,
116
117    // For 'vertical' direction only
118    sideBarRatio: 1 / 4,
119    pageContainer: $('body'),
120
121    classMap: {
122      initialized: '.hs-menu-initialized',
123      mobileState: '.hs-mobile-state',
124
125      subMenu: '.hs-sub-menu',
126      hasSubMenu: '.hs-has-sub-menu',
127      hasSubMenuActive: '.hs-sub-menu-opened',
128
129      megaMenu: '.hs-mega-menu',
130      hasMegaMenu: '.hs-has-mega-menu',
131      hasMegaMenuActive: '.hs-mega-menu-opened'
132    },
133
134    mobileSpeed: 400,
135    mobileEasing: 'linear',
136
137    beforeOpen: function () {},
138    beforeClose: function () {},
139    afterOpen: function () {},
140    afterClose: function () {}
141  };
142
143  /**
144   * Initialization of the plugin.
145   *
146   * @protected
147   */
148  MegaMenu.prototype.initialize = function () {
149    var self = this,
150      $w = $(window);
151
152    if (this.options.rtl) this.$element.addClass('hs-rtl');
153
154    this.$element
155      .addClass(this.options.classMap.initialized.slice(1))
156      .addClass('hs-menu-' + this.options.direction);
157
158
159    // Independent events
160    $w.on('resize.HSMegaMenu', function (e) {
161
162      if (self.resizeTimeOutId) clearTimeout(self.resizeTimeOutId);
163
164      self.resizeTimeOutId = setTimeout(function () {
165
166        if (window.innerWidth <= self.options.breakpoint && self.state == 'desktop') self.initMobileBehavior();
167        else if (window.innerWidth > self.options.breakpoint && self.state == 'mobile') self.initDesktopBehavior();
168
169        self.refresh();
170
171      }, 50);
172
173    });
174
175    $(document).on('click.HSMegaMenu touchstart.HSMegaMenu', 'body', function (e) {
176
177      var $parents = $(e.target).parents(self.itemsSelector);
178
179      self.closeAll($parents.add($(e.target)));
180
181    });
182
183    $w.on('keyup.HSMegaMenu', function (e) {
184
185      if (e.keyCode && e.keyCode === 27) {
186
187        self.closeAll();
188
189        isMenuOpened = false;
190      }
191
192    });
193
194    if (window.innerWidth <= this.options.breakpoint) this.initMobileBehavior();
195    else if (window.innerWidth > this.options.breakpoint) this.initDesktopBehavior();
196
197    this.smartPositions();
198
199    return this;
200
201  };
202
203  MegaMenu.prototype.smartPositions = function () {
204
205    var self = this,
206      $submenus = this.$element.find(this.options.classMap.subMenu);
207
208    $submenus.each(function (i, el) {
209
210      MenuItem.smartPosition($(el), self.options);
211
212    });
213
214  };
215
216  /**
217   * Binding events to menu elements.
218   *
219   * @protected
220   */
221  MegaMenu.prototype.bindEvents = function () {
222
223    var self = this,
224      selector;
225
226    // Hover case
227    if (this.options.event === 'hover' && !_isTouch()) {
228      this.$element
229        .on(
230          'mouseenter.HSMegaMenu',
231          this.options.classMap.hasMegaMenu + ':not([data-event="click"]),' +
232          this.options.classMap.hasSubMenu + ':not([data-event="click"])',
233          function (e) {
234
235            var $this = $(this),
236              $chain = $this.parents(self.itemsSelector);
237
238            // Lazy initialization
239            if (!$this.data('HSMenuItem')) {
240              self.initMenuItem($this, self.getType($this));
241            }
242
243            $chain = $chain.add($this);
244
245            self.closeAll($chain);
246
247            $chain.each(function (i, el) {
248
249              var HSMenuItem = $(el).data('HSMenuItem');
250
251              if (HSMenuItem.hideTimeOutId) clearTimeout(HSMenuItem.hideTimeOutId);
252              HSMenuItem.desktopShow();
253
254            });
255
256            self._items = self._items.not($chain);
257            self._tempChain = $chain;
258
259            e.preventDefault();
260            e.stopPropagation();
261          }
262        )
263        .on(
264          'mouseleave.HSMegaMenu',
265          this.options.classMap.hasMegaMenu + ':not([data-event="click"]),' +
266          this.options.classMap.hasSubMenu + ':not([data-event="click"])',
267          function (e) {
268
269            var $this = $(this),
270              HSMenuItem = $this.data('HSMenuItem'),
271              $chain = $(e.relatedTarget).parents(self.itemsSelector);
272
273            HSMenuItem.hideTimeOutId = setTimeout(function () {
274              self.closeAll($chain);
275            }, self.options.hideTimeOut);
276
277            self._items = self._items.add(self._tempChain);
278            self._tempChain = null;
279
280            e.preventDefault();
281            e.stopPropagation();
282          }
283        )
284        .on(
285          'click.HSMegaMenu',
286          this.options.classMap.hasMegaMenu + '[data-event="click"] > a, ' +
287          this.options.classMap.hasSubMenu + '[data-event="click"] > a',
288          function (e) {
289
290            var $this = $(this).parent('[data-event="click"]'),
291              HSMenuItem;
292
293            // Lazy initialization
294            if (!$this.data('HSMenuItem')) {
295              self.initMenuItem($this, self.getType($this));
296            }
297
298
299            self.closeAll($this.add(
300              $this.parents(self.itemsSelector)
301            ));
302
303            HSMenuItem = $this
304              .data('HSMenuItem');
305
306            if (HSMenuItem.isOpened) {
307              HSMenuItem.desktopHide();
308            }
309            else {
310              HSMenuItem.desktopShow();
311            }
312
313
314            e.preventDefault();
315            e.stopPropagation();
316
317          }
318        );
319    }
320    // Click case
321    else {
322
323      this.$element
324        .on(
325          'click.HSMegaMenu touchstart.HSMegaMenu',
326          (_isTouch() ?
327            this.options.classMap.hasMegaMenu + ' > a, ' +
328            this.options.classMap.hasSubMenu + ' > a' :
329            this.options.classMap.hasMegaMenu + ':not([data-event="hover"]) > a,' +
330            this.options.classMap.hasSubMenu + ':not([data-event="hover"]) > a'),
331          function (e) {
332
333            var $this = $(this).parent(),
334              HSMenuItem,
335              $parents = $this.parents(self.itemsSelector);
336
337            // Lazy initialization
338            if (!$this.data('HSMenuItem')) {
339              self.initMenuItem($this, self.getType($this));
340            }
341
342            self.closeAll($this.add(
343              $this.parents(self.itemsSelector)
344            ));
345
346            HSMenuItem = $this
347              .addClass('hs-event-prevented')
348              .data('HSMenuItem');
349
350            if (HSMenuItem.isOpened) {
351              HSMenuItem.desktopHide();
352            }
353            else {
354              HSMenuItem.desktopShow();
355            }
356
357            e.preventDefault();
358            e.stopPropagation();
359          }
360        );
361
362      if (!_isTouch()) {
363        this.$element
364          .on(
365            'mouseenter.HSMegaMenu',
366            this.options.classMap.hasMegaMenu + '[data-event="hover"],' +
367            this.options.classMap.hasSubMenu + '[data-event="hover"]',
368            function (e) {
369
370              var $this = $(this),
371                $parents = $this.parents(self.itemsSelector);
372
373              // Lazy initialization
374              if (!$this.data('HSMenuItem')) {
375                self.initMenuItem($this, self.getType($this));
376              }
377
378              self.closeAll($this.add($parents));
379
380              $parents.add($this).each(function (i, el) {
381
382                var HSMenuItem = $(el).data('HSMenuItem');
383
384                if (HSMenuItem.hideTimeOutId) clearTimeout(HSMenuItem.hideTimeOutId);
385                HSMenuItem.desktopShow();
386
387              });
388
389              e.preventDefault();
390              e.stopPropagation();
391            }
392          )
393          .on(
394            'mouseleave.HSMegaMenu',
395            this.options.classMap.hasMegaMenu + '[data-event="hover"],' +
396            this.options.classMap.hasSubMenu + '[data-event="hover"]',
397            function (e) {
398
399              var $this = $(this),
400                HSMenuItem = $this.data('HSMenuItem');
401
402              HSMenuItem.hideTimeOutId = setTimeout(function () {
403
404                self.closeAll(
405                  $(e.relatedTarget).parents(self.itemsSelector)
406                );
407
408              }, self.options.hideTimeOut);
409
410              e.preventDefault();
411              e.stopPropagation();
412            }
413          )
414      }
415    }
416
417    this.$element.on('keydown.HSMegaMenu',
418      this.options.classMap.hasMegaMenu + ' > a,' +
419      this.options.classMap.hasSubMenu + ' > a',
420      function (e) {
421
422        var $this = $(this),
423          $parent = $this.parent(),
424          HSMenuItem;
425
426        // Lazy initialization
427        if (!$parent.data('HSMenuItem')) {
428
429          self.initMenuItem($parent, self.getType($parent));
430
431        }
432
433        HSMenuItem = $parent.data('HSMenuItem');
434
435        if ($this.is(':focus')) {
436
437          if (e.keyCode && e.keyCode === 40) {
438
439            e.preventDefault();
440
441            HSMenuItem.desktopShow();
442
443            isMenuOpened = true;
444
445          }
446
447          if (e.keyCode && e.keyCode === 13) {
448
449            if (isMenuOpened === true) {
450
451              HSMenuItem.desktopHide();
452
453              isMenuOpened = false;
454
455            } else {
456
457              HSMenuItem.desktopShow();
458
459              isMenuOpened = true;
460
461            }
462
463          }
464
465        }
466
467        $this.on('focusout', function () {
468
469          isMenuOpened = false;
470
471        });
472
473        HSMenuItem.menu.find('a').on('focusout', function () {
474
475          setTimeout(function () {
476
477            if (!HSMenuItem.menu.find('a').is(':focus')) {
478
479              HSMenuItem.desktopHide();
480
481              isMenuOpened = false;
482
483            }
484
485          });
486
487        });
488
489      })
490  };
491
492  /**
493   * Initialization of certain menu item.
494   *
495   * @protected
496   */
497  MegaMenu.prototype.initMenuItem = function (element, type) {
498
499    var self = this,
500      Item = new MenuItem(
501        element,
502        element.children(
503          self.options.classMap[type === 'mega-menu' ? 'megaMenu' : 'subMenu']
504        ),
505        $.extend(true, {type: type}, self.options, element.data()),
506        self.$element
507      );
508
509    element.data('HSMenuItem', Item);
510    this._items = this._items.add(element);
511
512  };
513
514  /**
515   * Destroys of desktop behavior, then makes initialization of mobile behavior.
516   *
517   * @protected
518   */
519  MegaMenu.prototype.initMobileBehavior = function () {
520
521    var self = this;
522
523    this.state = 'mobile';
524
525    this.$element
526      .off('.HSMegaMenu')
527      .addClass(this.options.classMap.mobileState.slice(1))
528      .on('click.HSMegaMenu', self.options.classMap.hasSubMenu + ' > a, ' + self.options.classMap.hasMegaMenu + ' > a', function (e) {
529
530        var $this = $(this).parent(),
531          MenuItemInstance;
532
533        // Lazy initialization
534        if (!$this.data('HSMenuItem')) {
535          self.initMenuItem($this, self.getType($this));
536        }
537
538        self.closeAll($this.parents(self.itemsSelector).add($this));
539
540        MenuItemInstance = $this
541          .data('HSMenuItem');
542
543        if (MenuItemInstance.isOpened) {
544          MenuItemInstance.mobileHide();
545        }
546        else {
547          MenuItemInstance.mobileShow();
548        }
549
550        e.preventDefault();
551        e.stopPropagation();
552
553      })
554      .find(this.itemsSelector)
555      .not(
556        this.options.classMap.hasSubMenuActive + ',' +
557        this.options.classMap.hasMegaMenuActive
558      )
559      .children(
560        this.options.classMap.subMenu + ',' +
561        this.options.classMap.megaMenu
562      )
563      .hide();
564
565  };
566
567  /**
568   * Destroys of mobile behavior, then makes initialization of desktop behavior.
569   *
570   * @protected
571   */
572  MegaMenu.prototype.initDesktopBehavior = function () {
573
574    this.state = 'desktop';
575
576    this.$element
577      .removeClass(this.options.classMap.mobileState.slice(1))
578      .off('.HSMegaMenu')
579      .find(this.itemsSelector)
580      .not(
581        this.options.classMap.hasSubMenuActive + ',' +
582        this.options.classMap.hasMegaMenuActive
583      )
584      .children(
585        this.options.classMap.subMenu + ',' +
586        this.options.classMap.megaMenu
587      )
588      .hide();
589
590    this.bindEvents();
591
592  };
593
594  /**
595   * Hides all of opened submenus/megamenus.
596   *
597   * @param {jQuery} except - collection of elements, which shouldn't be closed.
598   * @return {jQuery}
599   * @public
600   */
601  MegaMenu.prototype.closeAll = function (except) {
602
603    var self = this;
604
605    return this._items.not(except && except.length ? except : $()).each(function (i, el) {
606
607      $(el)
608        .removeClass('hs-event-prevented')
609        .data('HSMenuItem')[self.state === 'mobile' ? 'mobileHide' : 'desktopHide']();
610
611    });
612
613  };
614
615  /**
616   * Returns type of sub menu based on specified menu item.
617   *
618   * @param {jQuery} item
619   * @return {String|null}
620   * @public
621   */
622  MegaMenu.prototype.getType = function (item) {
623
624    if (!item || !item.length) return null;
625
626    return item.hasClass(this.options.classMap.hasSubMenu.slice(1)) ? 'sub-menu' :
627      (item.hasClass(this.options.classMap.hasMegaMenu.slice(1)) ? 'mega-menu' : null);
628
629  };
630
631  /**
632   * Returns current menu state.
633   *
634   * @return {String}
635   * @public
636   */
637  MegaMenu.prototype.getState = function () {
638    return this.state;
639  };
640
641  /**
642   * Updates bounds of all menu items.
643   *
644   * @return {jQuery}
645   * @public
646   */
647  MegaMenu.prototype.refresh = function () {
648
649    return this._items.add(this._tempChain).each(function (i, el) {
650      $(el).data('HSMenuItem')._updateMenuBounds();
651    });
652
653  };
654
655
656  /**
657   * Creates a mega-menu element.
658   *
659   * @param {jQuery} element
660   * @param {jQuery} menu
661   * @param {Object} options
662   * @param {jQuery} container
663   * @constructor
664   */
665  function MenuItem(element, menu, options, container) {
666
667    var self = this;
668
669    /**
670     * Current menu item element.
671     *
672     * @public
673     */
674    this.$element = element;
675
676    /**
677     * Current mega menu element.
678     *
679     * @public
680     */
681    this.menu = menu;
682
683    /**
684     * Item options.
685     *
686     * @public
687     */
688    this.options = options;
689
690
691    /**
692     * MegaMenu container.
693     *
694     * @public
695     */
696    this.$container = container;
697
698    Object.defineProperties(this, {
699
700      /**
701       * Contains css class of menu item element.
702       *
703       * @public
704       */
705      itemClass: {
706        get: function () {
707          return self.options.type === 'mega-menu' ?
708            self.options.classMap.hasMegaMenu :
709            self.options.classMap.hasSubMenu;
710        }
711      },
712
713      /**
714       * Contains css active-class of menu item element.
715       *
716       * @public
717       */
718      activeItemClass: {
719        get: function () {
720          return self.options.type === 'mega-menu' ?
721            self.options.classMap.hasMegaMenuActive :
722            self.options.classMap.hasSubMenuActive;
723        }
724      },
725
726      /**
727       * Contains css class of menu element.
728       *
729       * @public
730       */
731      menuClass: {
732        get: function () {
733          return self.options.type === 'mega-menu' ?
734            self.options.classMap.megaMenu :
735            self.options.classMap.subMenu;
736        }
737      },
738
739      isOpened: {
740        get: function () {
741          return this.$element.hasClass(this.activeItemClass.slice(1));
742        }
743      }
744
745    });
746
747
748    this.menu.addClass('animated').on('click.HSMegaMenu', function (e) {
749      self._updateMenuBounds();
750    });
751
752    if (this.$element.data('max-width')) this.menu.css('max-width', this.$element.data('max-width'));
753    if (this.$element.data('position')) this.menu.addClass('hs-position-' + this.$element.data('position'));
754
755
756    if (this.options.animationOut) {
757
758      this.menu.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function (e) {
759
760        if (self.menu.hasClass(self.options.animationOut)) {
761          self.$element.removeClass(self.activeItemClass.slice(1));
762          self.options.afterClose.call(self, self.$element, self.menu);
763        }
764
765        if (self.menu.hasClass(self.options.animationIn)) {
766          self.options.afterOpen.call(self, self.$element, self.menu);
767        }
768
769        e.stopPropagation();
770        e.preventDefault();
771      });
772    }
773
774  }
775
776  /**
777   * Shows the mega-menu item.
778   *
779   * @public
780   * @return {MenuItem}
781   */
782  MenuItem.prototype.desktopShow = function () {
783    if (!this.menu.length) return this;
784
785    this.$element.addClass(this.activeItemClass.slice(1));
786
787    this._updateMenuBounds();
788
789    this.menu.show();
790
791    if (this.options.direction == 'horizontal') this.smartPosition(this.menu, this.options);
792
793    if (this.options.animationOut) {
794      this.menu.removeClass(this.options.animationOut);
795    }
796    else {
797      this.options.afterOpen.call(this, this.$element, this.menu);
798    }
799
800    if (this.options.animationIn) {
801      this.menu.addClass(this.options.animationIn)
802    }
803
804    return this;
805  }
806
807  /**
808   * Hides the mega-menu item.
809   *
810   * @public
811   * @return {MenuItem}
812   */
813  MenuItem.prototype.desktopHide = function () {
814
815    var self = this;
816
817    if (!this.menu.length) return this;
818
819    this.$element.removeClass(this.activeItemClass.slice(1));
820
821    this.menu.hide();
822
823    if (this.options.animationIn) {
824      this.menu.removeClass(this.options.animationIn);
825    }
826    if (this.options.animationOut) {
827      this.menu.addClass(this.options.animationOut);
828    }
829    else {
830      this.options.afterClose.call(this, this.$element, this.menu);
831    }
832
833    return this;
834  }
835
836  /**
837   * Shows the mega-menu item.
838   *
839   * @public
840   * @return {MenuItem}
841   */
842  MenuItem.prototype.mobileShow = function () {
843    var self = this;
844
845    if (!this.menu.length) return this;
846
847
848    this.menu
849      .removeClass(this.options.animationIn)
850      .removeClass(this.options.animationOut)
851      .stop()
852      .slideDown({
853        duration: self.options.mobileSpeed,
854        easing: self.options.mobileEasing,
855        complete: function () {
856          self.options.afterOpen.call(self, self.$element, self.menu);
857        }
858      });
859
860    this.$element.addClass(this.activeItemClass.slice(1));
861
862    return this;
863  };
864
865  /**
866   * Hides the mega-menu item.
867   *
868   * @public
869   * @return {MenuItem}
870   */
871  MenuItem.prototype.mobileHide = function () {
872    var self = this;
873
874    if (!this.menu.length) return this;
875
876    this.menu.stop().slideUp({
877      duration: self.options.mobileSpeed,
878      easing: self.options.mobileEasing,
879      complete: function () {
880        self.options.afterClose.call(self, self.$element, self.menu);
881      }
882    });
883
884    this.$element.removeClass(this.activeItemClass.slice(1));
885
886    return this;
887  };
888
889  /**
890   * Check, if element is in viewport.
891   *
892   * @param {jQuery} element
893   * @param {Object} options
894   * @public
895   */
896  MenuItem.prototype.smartPosition = function (element, options) {
897
898    MenuItem.smartPosition(element, options);
899
900  };
901
902  /**
903   * Check, if element is in viewport.
904   *
905   * @param {jQuery} element
906   * @param {Object} options
907   * @static
908   * @public
909   */
910  MenuItem.smartPosition = function (element, options) {
911    if (!element && !element.length) return;
912
913    var $w = $(window);
914
915    element.removeClass('hs-reversed');
916
917    if (!options.rtl) {
918
919      if (element.offset().left + element.outerWidth() > window.innerWidth) {
920        element.addClass('hs-reversed');
921      }
922
923    }
924    else {
925
926      if (element.offset().left < 0) {
927        element.addClass('hs-reversed');
928      }
929
930    }
931  };
932
933  /**
934   * Updates bounds of current opened menu.
935   *
936   * @private
937   */
938  MenuItem.prototype._updateMenuBounds = function () {
939
940    var width = 'auto';
941
942    if (this.options.direction == 'vertical' && this.options.type == 'mega-menu') {
943
944      if (this.$container && this.$container.data('HSMegaMenu').get
944State() == 'desktop') {
945        if (!this.options.pageContainer.length) this.options.pageContainer = $('body');
946        width = this.options.pageContainer.outerWidth() * (1 - this.options.sideBarRatio);
947      }
948      else {
949        width = 'auto';
950      }
951
952
953      this.menu.css({
954        'width': width,
955        'height': 'auto'
956      });
957
958      if (this.menu.outerHeight() > this.$container.outerHeight()) {
959        return;
960      }
961
962      this.menu.css('height', '100%');
963    }
964
965  };
966
967  /**
968   * The jQuery plugin for the MegaMenu.
969   *
970   * @public
971   */
972
973  $.fn.HSMegaMenu = function () {
974    var _ = this,
975      opt = arguments[0],
976      args = Array.prototype.slice.call(arguments, 1),
977      l = _.length,
978      i,
979      ret;
980    for (i = 0; i < l; i++) {
981      if (typeof opt == 'object' || typeof opt == 'undefined')
982        _[i].MegaMenu = new MegaMenu(_[i], opt);
983      else
984        ret = _[i].MegaMenu[opt].apply(_[i].MegaMenu, args);
985      if (typeof ret != 'undefined') return ret;
986    }
987    return _;
988  };
989
990  /**
991   * Helper function for detect touch events in the environment.
992   *
993   * @return {Boolean}
994   * @private
995   */
996  function _isTouch() {
997    return ('ontouchstart' in window);
998  }
999
1000})(jQuery);

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.