@sapui5/sap.fe.templates 1.147.0 → 1.148.0
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.
- package/package.json +1 -1
- package/src/sap/fe/templates/.library +1 -1
- package/src/sap/fe/templates/AnalyticalListPage/manifest.json +1 -1
- package/src/sap/fe/templates/ListReport/ListReportController.controller.js +4 -14
- package/src/sap/fe/templates/ListReport/ListReportController.controller.ts +2 -12
- package/src/sap/fe/templates/ListReport/controls/MultipleModeControl.js +4 -1
- package/src/sap/fe/templates/ListReport/controls/MultipleModeControl.ts +3 -0
- package/src/sap/fe/templates/ListReport/manifest.json +1 -1
- package/src/sap/fe/templates/ObjectPage/ExtensionAPI.js +134 -24
- package/src/sap/fe/templates/ObjectPage/ExtensionAPI.ts +132 -19
- package/src/sap/fe/templates/ObjectPage/ObjectPageController.controller.js +169 -17
- package/src/sap/fe/templates/ObjectPage/ObjectPageController.controller.ts +195 -19
- package/src/sap/fe/templates/ObjectPage/ObjectPageTemplating.js +13 -8
- package/src/sap/fe/templates/ObjectPage/ObjectPageTemplating.ts +17 -9
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDiscardDialog.js +4 -1
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDiscardDialog.tsx +1 -0
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDraft.js +15 -4
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDraft.tsx +11 -2
- package/src/sap/fe/templates/ObjectPage/controls/StashableHBox.js +28 -1
- package/src/sap/fe/templates/ObjectPage/controls/StashableHBox.ts +31 -0
- package/src/sap/fe/templates/ObjectPage/helpers/SectionNavigationHelper.js +72 -0
- package/src/sap/fe/templates/ObjectPage/helpers/SectionNavigationHelper.ts +75 -0
- package/src/sap/fe/templates/ObjectPage/manifest.json +1 -15
- package/src/sap/fe/templates/ObjectPage/overrides/CollaborationManager.js +29 -20
- package/src/sap/fe/templates/ObjectPage/overrides/CollaborationManager.ts +28 -21
- package/src/sap/fe/templates/ObjectPage/overrides/IntentBasedNavigation.js +4 -3
- package/src/sap/fe/templates/ObjectPage/overrides/IntentBasedNavigation.ts +4 -4
- package/src/sap/fe/templates/ObjectPage/overrides/ViewState.js +93 -17
- package/src/sap/fe/templates/ObjectPage/overrides/ViewState.ts +108 -22
- package/src/sap/fe/templates/ObjectPage/view/fragments/EmphasizedFirstHeaderAction.fragment.xml +1 -0
- package/src/sap/fe/templates/ObjectPage/view/fragments/ExpandedHeading.fragment.xml +4 -4
- package/src/sap/fe/templates/ObjectPage/view/fragments/Heading.fragment.xml +4 -4
- package/src/sap/fe/templates/ObjectPage/view/fragments/ObjectPageHeaderAddress.fragment.xml +1 -1
- package/src/sap/fe/templates/ObjectPage/view/fragments/ObjectPageHeaderContact.fragment.xml +1 -1
- package/src/sap/fe/templates/ObjectPage/view/fragments/ObjectPageHeaderForm.fragment.xml +1 -0
- package/src/sap/fe/templates/library.js +1 -1
- package/src/sap/fe/templates/messagebundle_no.properties +1 -1
- package/src/sap/fe/templates/messagebundle_uk.properties +1 -1
|
@@ -48,6 +48,12 @@ class ObjectPageExtensionAPI extends ExtensionAPI {
|
|
|
48
48
|
*/
|
|
49
49
|
private customMessageStripId?: string;
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Flag to prevent concurrent navigateToSubSection calls.
|
|
53
|
+
* Set to true when navigation starts, reset after navigation completes (including polling).
|
|
54
|
+
*/
|
|
55
|
+
private isNavigatingToSubSection = false;
|
|
56
|
+
|
|
51
57
|
/**
|
|
52
58
|
* Refreshes either the whole object page or only parts of it.
|
|
53
59
|
* @param [vPath] Path or array of paths referring to entities or properties to be refreshed.
|
|
@@ -505,70 +511,177 @@ class ObjectPageExtensionAPI extends ExtensionAPI {
|
|
|
505
511
|
MessageBox.error(sTitle);
|
|
506
512
|
}
|
|
507
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Navigate to the first section of the object page.
|
|
516
|
+
* Used as a fallback when the target section is not found or invalid.
|
|
517
|
+
* @param objectPageLayout The ObjectPageLayout control to navigate within
|
|
518
|
+
*/
|
|
519
|
+
private navigateToFirstSection(objectPageLayout: ObjectPageLayout): void {
|
|
520
|
+
const sections = objectPageLayout.getSections();
|
|
521
|
+
if (!sections || sections.length === 0) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const firstSection = sections[0];
|
|
526
|
+
const subSections = firstSection.getSubSections();
|
|
527
|
+
if (!subSections || subSections.length === 0) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const firstSubSection = subSections[0];
|
|
532
|
+
const subSectionFullId = firstSubSection.getId();
|
|
533
|
+
|
|
534
|
+
if (!subSectionFullId) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
objectPageLayout.setSelectedSection(subSectionFullId);
|
|
539
|
+
objectPageLayout.fireNavigate({
|
|
540
|
+
section: firstSection,
|
|
541
|
+
subSection: firstSubSection
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
|
|
508
545
|
/**
|
|
509
546
|
* Navigate to a specific section or subsection within the current page.
|
|
510
547
|
* Works with Object Page layouts and other section-based layouts.
|
|
548
|
+
* If the target section is not found or invalid, the app automatically falls back to the first available section.
|
|
511
549
|
* @param sectionOrSubSectionId The ID of the target section or subsection (without a view prefix, for example, "fe::FacetSection::TravelData" or "fe::SubSection::Details")
|
|
512
550
|
* @public
|
|
513
551
|
*/
|
|
514
552
|
navigateToSubSection(sectionOrSubSectionId: string): void {
|
|
553
|
+
// Guard against concurrent navigation calls to prevent infinite loops
|
|
554
|
+
// from multiple polling mechanisms (ViewState.apply and ObjectPageController._navigateToTargetSection)
|
|
555
|
+
if (this.isNavigatingToSubSection) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
this.isNavigatingToSubSection = true;
|
|
559
|
+
|
|
560
|
+
// Helper to reset navigation flag after a delay
|
|
561
|
+
const resetNavigationFlag = (delayMs: number): void => {
|
|
562
|
+
setTimeout(() => {
|
|
563
|
+
this.isNavigatingToSubSection = false;
|
|
564
|
+
}, delayMs);
|
|
565
|
+
};
|
|
566
|
+
|
|
515
567
|
try {
|
|
516
568
|
// Find the Object Page Layout control
|
|
517
569
|
const objectPageLayout = this._view.getContent()[0] as ObjectPageLayout | undefined;
|
|
518
570
|
|
|
519
|
-
if (!objectPageLayout) {
|
|
520
|
-
|
|
571
|
+
if (!objectPageLayout || !objectPageLayout.getDomRef()) {
|
|
572
|
+
// ObjectPageLayout not available or destroyed - silently return during navigation transitions
|
|
573
|
+
// This is expected when ViewState.apply runs on a view being navigated away from
|
|
574
|
+
this.isNavigatingToSubSection = false;
|
|
521
575
|
return;
|
|
522
576
|
}
|
|
523
577
|
|
|
524
578
|
if (!sectionOrSubSectionId) {
|
|
525
|
-
this.
|
|
579
|
+
this.navigateToFirstSection(objectPageLayout);
|
|
580
|
+
resetNavigationFlag(100);
|
|
526
581
|
return;
|
|
527
582
|
}
|
|
528
583
|
|
|
529
584
|
const control = this._view.byId(sectionOrSubSectionId);
|
|
530
585
|
|
|
531
|
-
if (!control) {
|
|
586
|
+
if (!control || !(control as Control).getVisible()) {
|
|
587
|
+
this.navigateToFirstSection(objectPageLayout);
|
|
532
588
|
this.showNavigationError();
|
|
589
|
+
resetNavigationFlag(100);
|
|
533
590
|
return;
|
|
534
591
|
}
|
|
535
592
|
|
|
536
593
|
let targetSubSection: ObjectPageSubSection | undefined;
|
|
594
|
+
let targetSection: ObjectPageSection | undefined;
|
|
595
|
+
let isNavigatingToSection = false; // Track if original target was a Section (not SubSection)
|
|
537
596
|
|
|
538
597
|
// Check if control is a SubSection or Section
|
|
539
598
|
if (control.isA<ObjectPageSubSection>("sap.uxap.ObjectPageSubSection")) {
|
|
540
599
|
targetSubSection = control;
|
|
541
600
|
} else if (control.isA<ObjectPageSection>("sap.uxap.ObjectPageSection")) {
|
|
542
|
-
|
|
601
|
+
targetSection = control;
|
|
602
|
+
isNavigatingToSection = true;
|
|
603
|
+
// If it's a section, get the first subsection (if available)
|
|
543
604
|
const subSections = control.getSubSections();
|
|
544
605
|
targetSubSection = subSections.length > 0 ? subSections[0] : undefined;
|
|
545
606
|
}
|
|
546
607
|
|
|
547
|
-
// Validate subsection
|
|
548
|
-
|
|
608
|
+
// Validate we have either a section or subsection
|
|
609
|
+
const hasValidTarget = targetSubSection || targetSection;
|
|
610
|
+
if (!hasValidTarget || (targetSubSection && !targetSubSection.getVisible())) {
|
|
611
|
+
this.navigateToFirstSection(objectPageLayout);
|
|
549
612
|
this.showNavigationError();
|
|
613
|
+
resetNavigationFlag(100);
|
|
550
614
|
return;
|
|
551
615
|
}
|
|
552
616
|
|
|
553
|
-
//
|
|
554
|
-
|
|
617
|
+
// If we have a section but no subsection (lazy loading scenario), scroll directly to the section
|
|
618
|
+
if (targetSection && !targetSubSection) {
|
|
619
|
+
const sectionFullId = targetSection.getId();
|
|
620
|
+
objectPageLayout.scrollToSection(sectionFullId, 0);
|
|
621
|
+
resetNavigationFlag(100);
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
555
624
|
|
|
556
|
-
|
|
557
|
-
|
|
625
|
+
// At this point, targetSubSection is guaranteed to be defined
|
|
626
|
+
// (we've already returned if it was undefined with a valid targetSection)
|
|
627
|
+
if (!targetSubSection) {
|
|
628
|
+
// This should never happen, but satisfies TypeScript
|
|
629
|
+
this.isNavigatingToSubSection = false;
|
|
558
630
|
return;
|
|
559
631
|
}
|
|
560
632
|
|
|
561
|
-
//
|
|
562
|
-
|
|
633
|
+
// Note: we intentionally do not check getVisible() here.
|
|
634
|
+
// When navigating to a subsection in an inactive IconTabBar tab, the subsection is not yet visible.
|
|
635
|
+
// setSelectedSection will activate the parent section and make the subsection visible.
|
|
636
|
+
|
|
637
|
+
// Get the full subsection ID (including view prefix)
|
|
638
|
+
const subSectionFullId = targetSubSection.getId();
|
|
639
|
+
|
|
640
|
+
if (!subSectionFullId) {
|
|
641
|
+
this.isNavigatingToSubSection = false;
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
563
644
|
|
|
564
|
-
// Trigger iApp state change by firing navigate event
|
|
565
645
|
const parentSection = targetSubSection.getParent() as ObjectPageSection;
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
646
|
+
const parentSectionFullId = parentSection.getId();
|
|
647
|
+
const isParentSectionSelected = objectPageLayout.getSelectedSection() === parentSectionFullId;
|
|
648
|
+
|
|
649
|
+
if (!isParentSectionSelected && !isNavigatingToSection) {
|
|
650
|
+
// When navigating to a subsection in an inactive section, we must first activate
|
|
651
|
+
// the parent section, then wait for subsection to be ready before scrolling to it
|
|
652
|
+
objectPageLayout.scrollToSection(parentSectionFullId, 0);
|
|
653
|
+
|
|
654
|
+
// Poll for subsection DOM to be ready after parent section activation
|
|
655
|
+
// Related: helpers/SectionNavigationHelper.ts (used by ViewState.apply and ObjectPageController.navigateToTargetSection)
|
|
656
|
+
// This polling differs: checks DOM readiness (binary), not section ID stability
|
|
657
|
+
let attempts = 0;
|
|
658
|
+
const maxAttempts = 10;
|
|
659
|
+
const checkSubsectionReady = (): void => {
|
|
660
|
+
attempts++;
|
|
661
|
+
const subSectionDom = targetSubSection.getDomRef();
|
|
662
|
+
if (subSectionDom) {
|
|
663
|
+
// Subsection is ready, scroll to it
|
|
664
|
+
objectPageLayout.scrollToSection(subSectionFullId, 0);
|
|
665
|
+
resetNavigationFlag(100);
|
|
666
|
+
} else if (attempts < maxAttempts) {
|
|
667
|
+
// Not ready yet, check again
|
|
668
|
+
setTimeout(checkSubsectionReady, 50);
|
|
669
|
+
} else {
|
|
670
|
+
// Timeout - try scrolling anyway
|
|
671
|
+
objectPageLayout.scrollToSection(subSectionFullId, 0);
|
|
672
|
+
resetNavigationFlag(100);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
// Start checking after 100ms initial delay
|
|
676
|
+
setTimeout(checkSubsectionReady, 100);
|
|
677
|
+
} else {
|
|
678
|
+
// Parent section already selected or navigating to section - scroll directly
|
|
679
|
+
const scrollTarget = isNavigatingToSection ? parentSectionFullId : subSectionFullId;
|
|
680
|
+
objectPageLayout.scrollToSection(scrollTarget, 0);
|
|
681
|
+
resetNavigationFlag(100);
|
|
682
|
+
}
|
|
570
683
|
} catch (error) {
|
|
571
|
-
|
|
684
|
+
this.isNavigatingToSubSection = false;
|
|
572
685
|
}
|
|
573
686
|
}
|
|
574
687
|
}
|