@esfaenza/core 20.3.82 → 20.3.84

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, ChangeDetectorRef, Type, ElementRef, NgZone, Injector, TemplateRef, SimpleChanges } from '@angular/core';
2
+ import { NgZone, EventEmitter, ChangeDetectorRef, Type, ElementRef, Injector, TemplateRef, SimpleChanges } from '@angular/core';
3
3
  import * as i2 from '@angular/router';
4
4
  import { Router, ActivatedRoute, UrlTree, UrlSegment, Data } from '@angular/router';
5
5
  import { Title, DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
@@ -30,13 +30,20 @@ import { DropdownOption } from '@esfaenza/utility-components';
30
30
  import { HttpParams } from '@angular/common/http';
31
31
 
32
32
  declare class BackTop {
33
+ private zone;
33
34
  position: number;
34
35
  showSpeed: number;
35
36
  moveSpeed: number;
36
37
  private _selector;
38
+ private visible;
39
+ constructor(zone: NgZone);
37
40
  ngAfterViewInit(): void;
38
41
  _onClick(): boolean;
39
42
  _onWindowScroll(): void;
43
+ /** Torna in cima in `duration` ms con l'andamento "swing", quello di default delle animazioni jQuery */
44
+ private scrollToTop;
45
+ /** Dissolvenza in entrata/uscita fino all'opacita' del foglio di stile (0.4, 0.8 al passaggio del mouse) */
46
+ private fade;
40
47
  static ɵfac: i0.ɵɵFactoryDeclaration<BackTop, never>;
41
48
  static ɵcmp: i0.ɵɵComponentDeclaration<BackTop, "back-top", never, { "position": { "alias": "position"; "required": false; }; "showSpeed": { "alias": "showSpeed"; "required": false; }; "moveSpeed": { "alias": "moveSpeed"; "required": false; }; }, {}, never, never, true, never>;
42
49
  }
@@ -264,11 +271,21 @@ declare class Sidebar {
264
271
  menuCollapse(): void;
265
272
  menuCollapseStateChange(isCollapsed: boolean): void;
266
273
  menuExpand(): void;
267
- hoverItem(jQueryevent: any): void;
274
+ hoverItem(event: any): void;
268
275
  sendAwayHoverElement(): void;
276
+ private hoverElem;
269
277
  updateSidebarHeight(): void;
270
- collapseMenu(jQueryevent: any, item: any): boolean;
278
+ collapseMenu(event: any, item: any): boolean;
271
279
  private outsideAngularClickHandler;
280
+ /** Chiude le voci espanse di un livello (es. "level-2") */
281
+ private collapseLevel;
282
+ /**
283
+ * Apre o chiude un sottomenu animandone l'altezza, come facevano slideDown/slideUp di jQuery:
284
+ * se e' gia' nello stato richiesto non fa nulla, e alla fine lascia `display` inline (block o none),
285
+ * cosi' togliere la classe che lo mostrava non lo nasconde di colpo a meta' animazione.
286
+ * Se un'animazione e' in corso riparte dall'altezza attuale invece di accodarsi.
287
+ */
288
+ private slide;
272
289
  onChangeTenant(): void;
273
290
  onLogout(): void;
274
291
  private getUserProfileData;
@@ -1,34 +1,69 @@
1
1
  import * as i0 from '@angular/core';
2
- import { ElementRef, NgZone, Renderer2, OnInit, OnDestroy, ViewContainerRef, Type } from '@angular/core';
2
+ import { ElementRef, NgZone, Renderer2, ViewContainerRef, Type } from '@angular/core';
3
3
  import { AppEmbeddingExtensions } from '@esfaenza/extensions';
4
4
  import { LocationStrategy } from '@angular/common';
5
5
  import { RouterLinkWithHref, Router, ActivatedRoute, UrlTree } from '@angular/router';
6
6
  import { ModalDirective } from 'ngx-bootstrap/modal';
7
7
  import { Subscription } from 'rxjs';
8
8
 
9
+ /**
10
+ * Rende trascinabile il primo figlio dell'elemento (tipicamente la `.modal-content` dentro una
11
+ * `.modal-dialog`), afferrandolo dall'handle indicato (default `.modal-header`).
12
+ *
13
+ * Riproduce il comportamento che aveva con jQuery UI `draggable`:
14
+ * - lo spostamento si applica con `left`/`top` su un elemento `position: relative`, quindi si somma
15
+ * fra un trascinamento e l'altro;
16
+ * - non parte se si preme su campi, pulsanti o select (il `cancel` di default di jQuery UI);
17
+ * - solo con il tasto principale del mouse (jQuery UI non gestiva il touch);
18
+ * - quando l'applicazione e' incorporata (`AppEmbeddingExtensions.Embedded`) il riquadro resta
19
+ * dentro la pagina, come faceva il vecchio `div_containment`.
20
+ *
21
+ * Tutto gira fuori dalla zona di Angular: i movimenti del mouse non devono scatenare change detection.
22
+ */
9
23
  declare class Draggable {
10
24
  private _elementRef;
11
25
  private zone;
12
26
  private emb;
13
27
  handlerSelector: string;
14
- private $draggable;
28
+ private static readonly CANCEL;
29
+ private target;
30
+ private startX;
31
+ private startY;
32
+ private startLeft;
33
+ private startTop;
34
+ private bounds;
35
+ private bodyUserSelect;
15
36
  constructor(_elementRef: ElementRef, zone: NgZone, emb: AppEmbeddingExtensions);
16
37
  ngOnInit(): void;
17
38
  ngOnDestroy(): void;
39
+ private onDown;
40
+ private onMove;
41
+ private onUp;
42
+ private stopListening;
43
+ /** Di quanto si puo' spostare il riquadro restando dentro la pagina (in px, da dove si trova ora) */
44
+ private computeBounds;
18
45
  static ɵfac: i0.ɵɵFactoryDeclaration<Draggable, never>;
19
46
  static ɵdir: i0.ɵɵDirectiveDeclaration<Draggable, "[emaDraggable]", never, { "handlerSelector": { "alias": "emaDraggable"; "required": false; }; }, {}, never, never, true, never>;
20
47
  }
21
48
 
49
+ /**
50
+ * Area scorrevole ad altezza fissa con una barra sottile.
51
+ *
52
+ * Prima usava il plugin jQuery slimScroll, che avvolgeva l'elemento in un contenitore e disegnava
53
+ * una barra finta. Ora lo scorrimento e' quello nativo: la direttiva imposta altezza e overflow,
54
+ * e la classe `es-slim-scroll` da' alla barra l'aspetto di prima (4px, visibile al passaggio del
55
+ * mouse; vedi `_libs-override.scss`).
56
+ *
57
+ * Delle opzioni di slimScroll l'unica usata nella Suite e' `height` (numero in px o stringa CSS).
58
+ */
22
59
  declare class SlimScroll {
23
60
  private _elementRef;
24
- private zone;
25
- slimScrollOptions: Object;
26
- constructor(_elementRef: ElementRef, zone: NgZone);
27
- ngOnChanges(changes: any): void;
28
- ngOnDestroy(): void;
29
- private _scroll;
30
- private _init;
31
- private _destroy;
61
+ slimScrollOptions: {
62
+ height?: number | string;
63
+ [key: string]: any;
64
+ };
65
+ constructor(_elementRef: ElementRef);
66
+ ngOnChanges(): void;
32
67
  static ɵfac: i0.ɵɵFactoryDeclaration<SlimScroll, never>;
33
68
  static ɵdir: i0.ɵɵDirectiveDeclaration<SlimScroll, "[slim-scroll]", never, { "slimScrollOptions": { "alias": "slimScrollOptions"; "required": false; }; }, {}, never, never, true, never>;
34
69
  }
@@ -43,18 +78,6 @@ declare class esRouterLinkWithHref extends RouterLinkWithHref {
43
78
  static ɵdir: i0.ɵɵDirectiveDeclaration<esRouterLinkWithHref, "a[esRouterLink],area[esRouterLink]", never, { "esRouterLink": { "alias": "esRouterLink"; "required": false; }; }, {}, never, never, true, never>;
44
79
  }
45
80
 
46
- declare class Widget implements OnInit, OnDestroy {
47
- $el: any;
48
- private onClose;
49
- private onFullscreened;
50
- private onRestored;
51
- constructor(el: ElementRef);
52
- ngOnInit(): void;
53
- ngOnDestroy(): void;
54
- static ɵfac: i0.ɵɵFactoryDeclaration<Widget, never>;
55
- static ɵdir: i0.ɵɵDirectiveDeclaration<Widget, "[widget]", never, {}, {}, never, never, true, never>;
56
- }
57
-
58
81
  declare class ComponentHostDirective {
59
82
  viewContainerRef: ViewContainerRef;
60
83
  componentHost: Type<any>;
@@ -106,8 +129,8 @@ declare class EsModalDirective extends ModalDirective {
106
129
 
107
130
  declare class DirectivesModule {
108
131
  static ɵfac: i0.ɵɵFactoryDeclaration<DirectivesModule, never>;
109
- static ɵmod: i0.ɵɵNgModuleDeclaration<DirectivesModule, never, [typeof Draggable, typeof SlimScroll, typeof Widget, typeof esRouterLinkWithHref, typeof ComponentHostDirective, typeof EsModalDirective], [typeof Draggable, typeof SlimScroll, typeof Widget, typeof esRouterLinkWithHref, typeof ComponentHostDirective, typeof EsModalDirective]>;
132
+ static ɵmod: i0.ɵɵNgModuleDeclaration<DirectivesModule, never, [typeof Draggable, typeof SlimScroll, typeof esRouterLinkWithHref, typeof ComponentHostDirective, typeof EsModalDirective], [typeof Draggable, typeof SlimScroll, typeof esRouterLinkWithHref, typeof ComponentHostDirective, typeof EsModalDirective]>;
110
133
  static ɵinj: i0.ɵɵInjectorDeclaration<DirectivesModule>;
111
134
  }
112
135
 
113
- export { ComponentHostDirective, DirectivesModule, Draggable, EsModalDirective, SlimScroll, Widget, esRouterLinkWithHref };
136
+ export { ComponentHostDirective, DirectivesModule, Draggable, EsModalDirective, SlimScroll, esRouterLinkWithHref };
@@ -47,29 +47,60 @@ import { TooltipModule } from 'primeng/tooltip';
47
47
 
48
48
  // Angular
49
49
  class BackTop {
50
- constructor() {
50
+ constructor(zone) {
51
+ this.zone = zone;
51
52
  this.position = 400;
52
53
  this.showSpeed = 500;
53
54
  this.moveSpeed = 1000;
55
+ this.visible = false;
54
56
  }
55
57
  ngAfterViewInit() {
56
58
  this._onWindowScroll();
57
59
  }
58
60
  _onClick() {
59
- $("html, body").animate({ scrollTop: 0 }, { duration: this.moveSpeed });
61
+ this.zone.runOutsideAngular(() => this.scrollToTop(this.moveSpeed));
60
62
  return false;
61
63
  }
62
64
  _onWindowScroll() {
63
- let el = this._selector.nativeElement;
64
- window.scrollY > this.position ? $(el).fadeIn(this.showSpeed) : $(el).fadeOut(this.showSpeed);
65
+ let show = window.scrollY > this.position;
66
+ if (show !== this.visible) {
67
+ this.visible = show;
68
+ this.fade(this._selector.nativeElement, show, this.showSpeed);
69
+ }
65
70
  }
66
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: BackTop, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
71
+ /** Torna in cima in `duration` ms con l'andamento "swing", quello di default delle animazioni jQuery */
72
+ scrollToTop(duration) {
73
+ let start = window.scrollY;
74
+ if (start <= 0)
75
+ return;
76
+ let t0 = performance.now();
77
+ let step = (now) => {
78
+ let p = Math.min(1, (now - t0) / duration);
79
+ window.scrollTo(0, start * (0.5 + Math.cos(p * Math.PI) / 2));
80
+ if (p < 1)
81
+ requestAnimationFrame(step);
82
+ };
83
+ requestAnimationFrame(step);
84
+ }
85
+ /** Dissolvenza in entrata/uscita fino all'opacita' del foglio di stile (0.4, 0.8 al passaggio del mouse) */
86
+ fade(el, show, duration) {
87
+ el.getAnimations().forEach(a => a.cancel());
88
+ if (show) {
89
+ el.style.display = "inline";
90
+ el.animate([{ opacity: 0 }, { opacity: getComputedStyle(el).opacity }], { duration, easing: "ease-in-out" });
91
+ }
92
+ else {
93
+ el.animate([{ opacity: getComputedStyle(el).opacity }, { opacity: 0 }], { duration, easing: "ease-in-out" })
94
+ .finished.then(() => el.style.display = "none", () => { });
95
+ }
96
+ }
97
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: BackTop, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
67
98
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.34", type: BackTop, isStandalone: true, selector: "back-top", inputs: { position: "position", showSpeed: "showSpeed", moveSpeed: "moveSpeed" }, host: { listeners: { "click": "_onClick()", "window:scroll.out-zone": "_onWindowScroll()" } }, viewQueries: [{ propertyName: "_selector", first: true, predicate: ["backTop"], descendants: true }], ngImport: i0, template: "<i #backTop class=\"fa fa-angle-up back-to-top\" title=\"Back to Top\"></i>", styles: [".back-to-top{position:fixed;width:40px;height:40px;cursor:pointer;z-index:9999;display:none;text-decoration:none;right:40px;bottom:40px!important;font-size:30px;text-align:center;opacity:.4;color:#fff;background-color:#242d3abf;border-radius:50%;line-height:34px}.back-to-top:hover{opacity:.8}\n"], encapsulation: i0.ViewEncapsulation.None }); }
68
99
  }
69
100
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.34", ngImport: i0, type: BackTop, decorators: [{
70
101
  type: Component,
71
102
  args: [{ selector: "back-top", encapsulation: ViewEncapsulation.None, standalone: true, template: "<i #backTop class=\"fa fa-angle-up back-to-top\" title=\"Back to Top\"></i>", styles: [".back-to-top{position:fixed;width:40px;height:40px;cursor:pointer;z-index:9999;display:none;text-decoration:none;right:40px;bottom:40px!important;font-size:30px;text-align:center;opacity:.4;color:#fff;background-color:#242d3abf;border-radius:50%;line-height:34px}.back-to-top:hover{opacity:.8}\n"] }]
72
- }], propDecorators: { position: [{
103
+ }], ctorParameters: () => [{ type: i0.NgZone }], propDecorators: { position: [{
73
104
  type: Input
74
105
  }], showSpeed: [{
75
106
  type: Input
@@ -430,7 +461,7 @@ class Sidebar {
430
461
  this.checkSubMenuOverClaims(t, level + 1);
431
462
  }
432
463
  }
433
- //#region JQuery
464
+ //#region Comportamento del menu
434
465
  onWindowResize() {
435
466
  var isMenuShouldCollapsed = this._shouldMenuCollapse();
436
467
  if (this.isMenuShouldCollapsed !== isMenuShouldCollapsed) {
@@ -454,19 +485,27 @@ class Sidebar {
454
485
  this.menuCollapseStateChange(false);
455
486
  this._state.setSidebarWidth(this.sidebar.nativeElement.offsetWidth);
456
487
  }
457
- hoverItem(jQueryevent) {
488
+ hoverItem(event) {
458
489
  if (!this.isMenuCollapsed) {
459
490
  this.showHoverElem = true;
460
- this.hoverElemHeight = jQueryevent.currentTarget.clientHeight;
461
- this.hoverElemTop = jQueryevent.currentTarget.getBoundingClientRect().top;
462
- jQuery(".sidebar-hover-elem").css("top", this.hoverElemTop + "px");
463
- jQuery(".sidebar-hover-elem").css("height", this.hoverElemHeight + "px");
464
- jQuery(".sidebar-hover-elem").addClass("show-hover-elem");
491
+ this.hoverElemHeight = event.currentTarget.clientHeight;
492
+ this.hoverElemTop = event.currentTarget.getBoundingClientRect().top;
493
+ let hoverElem = this.hoverElem();
494
+ if (hoverElem) {
495
+ hoverElem.style.top = this.hoverElemTop + "px";
496
+ hoverElem.style.height = this.hoverElemHeight + "px";
497
+ hoverElem.classList.add("show-hover-elem");
498
+ }
465
499
  }
466
500
  }
467
501
  sendAwayHoverElement() {
468
502
  this.hoverElemTop = -200;
469
- jQuery(".sidebar-hover-elem").css("top", this.hoverElemTop + "px");
503
+ let hoverElem = this.hoverElem();
504
+ if (hoverElem)
505
+ hoverElem.style.top = this.hoverElemTop + "px";
506
+ }
507
+ hoverElem() {
508
+ return this._elementRef.nativeElement.querySelector(".sidebar-hover-elem");
470
509
  }
471
510
  updateSidebarHeight() {
472
511
  let marginTop = 60 + 40;
@@ -475,61 +514,84 @@ class Sidebar {
475
514
  }
476
515
  //Nonostante questa funzione sia collegata con (click.out-zone) per qualche motivo angular le esegue comunque nella sua zone
477
516
  //generando un po' di irresponsività iniziale... succede solo col click... boh
478
- collapseMenu(jQueryevent, item) {
517
+ collapseMenu(event, item) {
479
518
  if (this.isMenuCollapsed)
480
519
  this.menuExpand();
481
520
  if (!item.level)
482
521
  console.warn("Livello non presente in un oggetto del menu!");
483
- //N.B: Tutte le funzioni di JQuery le esguo fuori da Angular dato che c'� una buona probabilit� che siano eventi asincroni
484
- this.zone.runOutsideAngular(() => { this.outsideAngularClickHandler(jQueryevent, item); });
522
+ //N.B: le animazioni girano fuori da Angular: ogni fotogramma scatenerebbe la change detection
523
+ this.zone.runOutsideAngular(() => { this.outsideAngularClickHandler(event, item); });
485
524
  return false;
486
525
  }
487
- outsideAngularClickHandler(jQueryevent, item) {
526
+ outsideAngularClickHandler(event, item) {
488
527
  let levelClass = item.level ? "level-" + (item.level) : "";
489
528
  let levelClassPlusOne = item.level ? "level-" + (item.level + 1) : "";
490
529
  let slidePeriod = 400;
491
- var link = jQuery(jQueryevent.currentTarget);
530
+ let link = event.currentTarget;
531
+ let linkLi = link.closest("li");
532
+ let next = link.nextElementSibling;
492
533
  //Se l'elemento non è espanso
493
- if (!link.closest(".sidebar-item-expanded" + "_" + levelClass).length) {
534
+ if (!link.closest(".sidebar-item-expanded" + "_" + levelClass)) {
494
535
  //Tiro su tutti gli elementi dello stesso livello espansi e li chiudo
495
- //Se ho compresso un menu vado a vedere se c'è anche un altro menu di livello pi� basso da richiudere
496
- jQuery("ul.nav-sidebar li" + "." + (levelClassPlusOne)).each(function () {
497
- let closestLi = jQuery(this).closest("li");
498
- if (closestLi.children("ul").length && closestLi.hasClass("sidebar-item-expanded")) {
499
- closestLi.children("ul").slideUp(slidePeriod);
500
- //Le uso sempre entrambe insieme. La prima è la classe per la logica, la seconda per le animazioni
501
- closestLi.removeClass("sidebar-item-expanded" + "_" + (levelClassPlusOne));
502
- closestLi.removeClass("sidebar-item-expanded");
503
- }
504
- });
505
- //Dopodich� richiudo tutti quelli del mio livello attuale
506
- jQuery("ul.nav-sidebar li" + "." + levelClass).each(function () {
507
- let closestLi = jQuery(this).closest("li");
508
- if (closestLi.children("ul").length && closestLi.hasClass("sidebar-item-expanded")) {
509
- closestLi.children("ul").slideUp(slidePeriod);
510
- //Le uso sempre entrambe insieme. La prima è la classe per la logica, la seconda per le animazioni
511
- closestLi.removeClass("sidebar-item-expanded" + "_" + levelClass);
512
- closestLi.removeClass("sidebar-item-expanded");
513
- }
514
- });
515
- //Dopodich� espando quello attuale
516
- link.next().slideDown(slidePeriod);
536
+ //Se ho compresso un menu vado a vedere se c'è anche un altro menu di livello più basso da richiudere
537
+ this.collapseLevel(levelClassPlusOne, slidePeriod);
538
+ //Dopodiché richiudo tutti quelli del mio livello attuale
539
+ this.collapseLevel(levelClass, slidePeriod);
540
+ //Dopodiché espando quello attuale
541
+ if (next)
542
+ this.slide(next, true, slidePeriod);
517
543
  if (item.subMenu) {
518
544
  //Le uso sempre entrambe insieme. La prima è la classe per la logica, la seconda per le animazioni
519
- link.closest("li").addClass("sidebar-item-expanded" + "_" + levelClass);
520
- link.closest("li").addClass("sidebar-item-expanded");
545
+ linkLi?.classList.add("sidebar-item-expanded" + "_" + levelClass, "sidebar-item-expanded");
521
546
  }
522
547
  }
523
548
  else {
524
549
  //Altrimenti, se l'elemento è già espanso lo chiudo
525
550
  if (item.subMenu) {
526
551
  //Le uso sempre entrambe insieme. La prima è la classe per la logica, la seconda per le animazioni
527
- link.closest("li").removeClass("sidebar-item-expanded" + "_" + levelClass);
528
- link.closest("li").removeClass("sidebar-item-expanded");
552
+ linkLi?.classList.remove("sidebar-item-expanded" + "_" + levelClass, "sidebar-item-expanded");
529
553
  }
530
- link.next().slideUp(slidePeriod);
554
+ if (next)
555
+ this.slide(next, false, slidePeriod);
531
556
  }
532
557
  }
558
+ /** Chiude le voci espanse di un livello (es. "level-2") */
559
+ collapseLevel(levelClass, slidePeriod) {
560
+ if (!levelClass)
561
+ return;
562
+ let root = this._elementRef.nativeElement;
563
+ root.querySelectorAll("ul.nav-sidebar li." + levelClass).forEach(li => {
564
+ let subLists = Array.from(li.children).filter(c => c.tagName === "UL");
565
+ if (subLists.length && li.classList.contains("sidebar-item-expanded")) {
566
+ subLists.forEach(ul => this.slide(ul, false, slidePeriod));
567
+ //Le uso sempre entrambe insieme. La prima è la classe per la logica, la seconda per le animazioni
568
+ li.classList.remove("sidebar-item-expanded" + "_" + levelClass, "sidebar-item-expanded");
569
+ }
570
+ });
571
+ }
572
+ /**
573
+ * Apre o chiude un sottomenu animandone l'altezza, come facevano slideDown/slideUp di jQuery:
574
+ * se e' gia' nello stato richiesto non fa nulla, e alla fine lascia `display` inline (block o none),
575
+ * cosi' togliere la classe che lo mostrava non lo nasconde di colpo a meta' animazione.
576
+ * Se un'animazione e' in corso riparte dall'altezza attuale invece di accodarsi.
577
+ */
578
+ slide(el, open, duration) {
579
+ let running = el.getAnimations();
580
+ let from = el.getBoundingClientRect().height;
581
+ running.forEach(a => a.cancel());
582
+ let visible = getComputedStyle(el).display !== "none";
583
+ if (!running.length && visible === open)
584
+ return;
585
+ el.style.display = "block";
586
+ el.style.overflow = "hidden";
587
+ let to = open ? el.scrollHeight : 0;
588
+ el.animate([{ height: from + "px" }, { height: to + "px" }], { duration, easing: "ease-in-out" })
589
+ .finished.then(() => {
590
+ el.style.overflow = "";
591
+ if (!open)
592
+ el.style.display = "none";
593
+ }, () => { });
594
+ }
533
595
  //#endregion
534
596
  //#region Footer
535
597
  onChangeTenant() {
@@ -884,7 +946,11 @@ class PagesComponent {
884
946
  var url = this._location.path();
885
947
  setTimeout(function () {
886
948
  window.scrollTo(0, 0);
887
- jQuery('a[href="#' + url + '"]').closest("li").closest("ul").closest("li").addClass("sidebar-item-expanded");
949
+ // Espande la voce di menu che contiene il link della pagina corrente
950
+ document.querySelectorAll("a[href]").forEach(a => {
951
+ if (a.getAttribute("href") === "#" + url)
952
+ a.closest("li")?.closest("ul")?.closest("li")?.classList.add("sidebar-item-expanded");
953
+ });
888
954
  });
889
955
  }
890
956
  hideMenu() {