Merge pull request #6510 from mempool/mononaut/cluster-frontend-mobile-fixes

This commit is contained in:
wiz 2026-05-29 19:16:37 +09:00 committed by GitHub
commit 6ff86a34bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 216 additions and 93 deletions

View file

@ -48,10 +48,12 @@
[class.inactive]="outline.chunkIndex !== effectiveActiveChunk"
[attr.d]="outline.path"
[ngbTooltip]="chunkLabelTooltip"
[disableTooltip]="isMobile"
container="body"
placement="top"
(mouseenter)="onChunkEnter(outline.chunkIndex)"
(mouseleave)="onChunkLeave()" />
(mouseleave)="onChunkLeave()"
(click)="onChunkClick(outline.chunkIndex, $event)" />
<text *ngFor="let outline of chunkOutlines; trackBy: trackByChunkIndex"
class="chunk-label"
@ -59,10 +61,12 @@
[attr.x]="outline.labelX" [attr.y]="outline.labelY"
text-anchor="middle"
[ngbTooltip]="chunkLabelTooltip"
[disableTooltip]="isMobile"
container="body"
placement="top"
(mouseenter)="onChunkEnter(outline.chunkIndex)"
(mouseleave)="onChunkLeave()">
(mouseleave)="onChunkLeave()"
(click)="onChunkClick(outline.chunkIndex, $event)">
{{ outline.feerate | feeRounding }} sat/vB
</text>
</ng-container>
@ -76,7 +80,8 @@
stroke-width="12"
(mouseenter)="onEdgeEnter(i, $event)"
(mousemove)="onEdgeMove($event)"
(mouseleave)="onEdgeLeave()" />
(mouseleave)="onEdgeLeave()"
(click)="onEdgeClick(i, $event)" />
<path class="edge-line"
[class.highlighted]="edge.highlighted"
[class.ancestor]="edge.highlightKind === 'ancestor'"
@ -96,7 +101,7 @@
(mouseenter)="onNodeEnter(node, $event)"
(mousemove)="onNodeMove($event)"
(mouseleave)="onNodeLeave()"
(click)="onNodeClick(node)">
(click)="onNodeClick(node, $event)">
<rect class="node-rect"
[class.current]="node.isCurrent"
[class.hovered]="node.hovered"
@ -120,7 +125,7 @@
<div #tooltip
class="cluster-tooltip"
*ngIf="hoverNode || hoverEdge"
*ngIf="!isMobile && (hoverNode || hoverEdge)"
[style.left.px]="tooltipPosition.x"
[style.top.px]="tooltipPosition.y">
<ng-container *ngIf="hoverNode">
@ -154,3 +159,39 @@
<div><span class="swatch descendant"></span><span i18n="cluster.child|child">child</span></div>
</div>
</div>
<div
class="cluster-mobile-panel"
*ngIf="isMobile && (hoverNode || hoverEdge)"
(click)="$event.stopPropagation()">
<ng-container *ngIf="hoverNode">
<div class="tx-id-row">
<a [routerLink]="['/tx/' | relativeUrl, hoverNode.tx.txid]">{{ hoverNode.tx.txid | shortenString }}</a>
<span class="this-tx-badge" *ngIf="hoverNode.isCurrent" i18n="cluster.this-transaction|this transaction">this transaction</span>
</div>
<div class="tooltip-body">
<table class="stats">
<tr>
<th i18n="transaction.fee|Transaction fee">Fee</th>
<td>{{ hoverNode.tx.fee | number }} <span class="unit" i18n="shared.sats">sats</span></td>
</tr>
<tr>
<th i18n="transaction.vsize|Virtual size">Size</th>
<td><span [innerHTML]="hoverNode.tx.weight / 4 | vbytes: 2"></span></td>
</tr>
<tr>
<th i18n="transaction.fee-rate|Transaction fee rate">Fee rate</th>
<td>{{ hoverNode.feerate | feeRounding }} <span class="unit">sat/vB</span></td>
</tr>
</table>
<div class="legend">
<div><span class="swatch ancestor"></span><span i18n="cluster.parents|parents">parents</span></div>
<div><span class="swatch descendant"></span><span i18n="cluster.children|children">children</span></div>
</div>
</div>
</ng-container>
<div class="legend edge-legend" *ngIf="!hoverNode && hoverEdge">
<div><span class="swatch ancestor"></span><span i18n="cluster.parent|parent">parent</span></div>
<div><span class="swatch descendant"></span><span i18n="cluster.child|child">child</span></div>
</div>
</div>

View file

@ -144,17 +144,14 @@
font-weight: 700;
}
.cluster-tooltip {
position: absolute;
.cluster-tooltip,
.cluster-mobile-panel {
background: color-mix(in srgb, var(--active-bg) 95%, transparent);
border-radius: 4px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.5);
color: var(--tooltip-grey);
padding: 8px 12px;
text-align: left;
pointer-events: none;
max-width: 360px;
white-space: nowrap;
.tx-id-row {
display: flex;
@ -225,3 +222,15 @@
&.descendant { background: var(--cluster-descendant-color); }
}
}
.cluster-tooltip {
position: absolute;
pointer-events: none;
max-width: 360px;
white-space: nowrap;
}
.cluster-mobile-panel {
margin-top: 8px;
white-space: normal;
}

View file

@ -22,6 +22,7 @@ export class ClusterDiagramComponent implements OnChanges, AfterViewInit, OnDest
@Input() cluster: { txs: CpfpClusterTx[]; chunks: CpfpClusterChunk[]; chunkIndex: number };
@Input() txid: string;
@Input() preview = false;
@Input() isMobile = false;
@ViewChild('graphContainer', { static: true }) graphContainer: ElementRef;
@ViewChild('tooltip') tooltipElement: ElementRef;
@ -125,8 +126,17 @@ export class ClusterDiagramComponent implements OnChanges, AfterViewInit, OnDest
}
onNodeEnter(node: RenderedNode, event: MouseEvent): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.applyNodeHighlight(node);
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
private applyNodeHighlight(node: RenderedNode): void {
this.hoverNode = node;
this.hoverEdge = null;
this.hoverChunkIndex = null;
this.applyEffectiveChunk();
this.clearHighlights();
node.hovered = true;
for (const edge of this.edges) {
@ -140,58 +150,63 @@ export class ClusterDiagramComponent implements OnChanges, AfterViewInit, OnDest
edge.highlightKind = 'ancestor';
}
}
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
onNodeMove(event: MouseEvent): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
onNodeLeave(): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.hoverNode = null;
this.clearHighlights();
this.cd.markForCheck();
}
onEdgeEnter(edgeIndex: number, event: MouseEvent): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.applyEdgeHighlight(edgeIndex);
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
private applyEdgeHighlight(edgeIndex: number): void {
this.clearHighlights();
this.hoverNode = null;
this.hoverChunkIndex = null;
this.applyEffectiveChunk();
const edge = this.edges[edgeIndex];
edge.highlighted = true;
edge.highlightKind = 'direct';
this.nodes[edge.parentIndex].relation = 'ancestor';
this.nodes[edge.childIndex].relation = 'descendant';
this.hoverEdge = edge;
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
onEdgeMove(event: MouseEvent): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.updateTooltipPosition(event);
this.cd.markForCheck();
}
onEdgeLeave(): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.hoverEdge = null;
this.clearHighlights();
this.cd.markForCheck();
}
onChunkEnter(chunkIndex: number): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.hoverChunkIndex = chunkIndex;
this.applyEffectiveChunk();
this.cd.markForCheck();
}
onChunkLeave(): void {
if (this.preview) { return; }
if (this.preview || this.isMobile) { return; }
this.hoverChunkIndex = null;
this.applyEffectiveChunk();
this.cd.markForCheck();
@ -212,13 +227,61 @@ export class ClusterDiagramComponent implements OnChanges, AfterViewInit, OnDest
}
}
onNodeClick(node: RenderedNode): void {
onNodeClick(node: RenderedNode, event: MouseEvent): void {
if (this.preview) { return; }
if (this.isMobile) {
event.stopPropagation();
if (this.hoverNode?.index === node.index) {
this.clearMobileSelection();
} else {
this.applyNodeHighlight(node);
this.cd.markForCheck();
}
return;
}
const network = this.stateService.network;
const prefix = network && network !== 'mainnet' ? `/${network}` : '';
this.router.navigate([prefix + '/tx/', node.tx.txid]);
}
onEdgeClick(edgeIndex: number, event: MouseEvent): void {
if (this.preview || !this.isMobile) { return; }
event.stopPropagation();
const edge = this.edges[edgeIndex];
if (this.hoverEdge === edge) {
this.clearMobileSelection();
} else {
this.applyEdgeHighlight(edgeIndex);
this.cd.markForCheck();
}
}
onChunkClick(chunkIndex: number, event: MouseEvent): void {
if (this.preview || !this.isMobile) { return; }
event.stopPropagation();
this.hoverNode = null;
this.hoverEdge = null;
this.clearHighlights();
this.hoverChunkIndex = chunkIndex;
this.applyEffectiveChunk();
this.cd.markForCheck();
}
@HostListener('click')
onBackgroundClick(): void {
if (this.preview || !this.isMobile) { return; }
this.clearMobileSelection();
}
private clearMobileSelection(): void {
this.hoverNode = null;
this.hoverEdge = null;
this.hoverChunkIndex = null;
this.clearHighlights();
this.applyEffectiveChunk();
this.cd.markForCheck();
}
private clearHighlights(): void {
for (const node of this.nodes) {
node.hovered = false;

View file

@ -121,6 +121,7 @@ const PREVIEW_DIMENSIONS: RenderDimensions = {
};
const PREVIEW_VIEWPORT_HEIGHT = 48;
const PREVIEW_SAFE_INSET = 16;
const OUTLINE_PAD = 6;
export function renderLayout(layout: GridLayout, params: RenderParams): RenderResult {
@ -175,7 +176,7 @@ export function renderLayout(layout: GridLayout, params: RenderParams): RenderRe
let cellW: number;
if (params.preview) {
const activeCols = activeChunkColCount(layout, params.activeChunkIndex);
const denom = Math.max(1, activeCols);
const denom = Math.max(1, activeCols + 1);
cellW = Math.max(dim.minCellW, Math.min(dim.maxCellW,
(params.containerWidth - dim.marginX * 2) / denom));
} else if (layout.cols > 0) {
@ -222,15 +223,21 @@ export function renderLayout(layout: GridLayout, params: RenderParams): RenderRe
activeMaxY = Math.max(activeMaxY, n.rectY + n.height);
}
}
const pad = dim.marginX;
const pad = dim.marginX + PREVIEW_SAFE_INSET;
const chunkFits = isFinite(activeMinX) && (activeMaxX - activeMinX) + 2 * pad <= vbWidth;
const vbX = chunkFits
let vbX = chunkFits
? (activeMinX + activeMaxX) / 2 - vbWidth / 2
: selected.x - vbWidth / 2;
if (!chunkFits && isFinite(activeMinX)) {
vbX = Math.max(activeMinX - pad, Math.min(activeMaxX + pad - vbWidth, vbX));
}
const chunkFitsVertically = isFinite(activeMinY) && (activeMaxY - activeMinY) + 2 * dim.marginY <= vbHeight;
const vbY = chunkFitsVertically
let vbY = chunkFitsVertically
? (activeMinY + activeMaxY) / 2 - vbHeight / 2
: selected.y - vbHeight / 2;
if (!chunkFitsVertically && isFinite(activeMinY)) {
vbY = Math.max(activeMinY - dim.marginY, Math.min(activeMaxY + dim.marginY - vbHeight, vbY));
}
return {
nodes, edges, chunkOutlines,

View file

@ -248,13 +248,14 @@
<ng-template #clusterPreviewButton let-cluster="cluster" let-txid="txid">
<div class="cluster-preview-inline" role="button" tabindex="0"
[ngbTooltip]="clusterPreviewTooltip"
[disableTooltip]="isMobile"
placement="bottom"
tooltipClass="cluster-preview-ngb-tooltip"
container="body"
(click)="toggleCpfp()"
(keydown.enter)="toggleCpfp()"
(keydown.space)="toggleCpfp(); $event.preventDefault()">
<app-cluster-diagram class="cluster-preview-diagram" [cluster]="cluster" [txid]="txid" [preview]="true"></app-cluster-diagram>
<app-cluster-diagram class="cluster-preview-diagram" [cluster]="cluster" [txid]="txid" [preview]="true" [isMobile]="isMobile"></app-cluster-diagram>
<fa-icon class="cluster-preview-expand" [icon]="['fas', cpfpMode ? 'compress' : 'expand']" [fixedWidth]="true"></fa-icon>
</div>
<ng-template #clusterPreviewTooltip>

View file

@ -104,7 +104,7 @@
<ng-container *ngIf="cpfpInfo?.cluster; else legacyCpfpRaw">
<div class="box">
<app-cluster-diagram
[cluster]="cpfpInfo.cluster" [txid]="transaction.txid">
[cluster]="cpfpInfo.cluster" [txid]="transaction.txid" [isMobile]="isMobile">
</app-cluster-diagram>
</div>
</ng-container>
@ -248,4 +248,4 @@
</h3>
</div>
}
</div>
</div>

View file

@ -90,7 +90,7 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
this.seoService.setTitle($localize`:@@d7f92e6fe26fba6fff568cbdae5db4a5c8c6a55c:Preview Transaction`);
this.seoService.setDescription($localize`:@@meta.description.preview-tx:Preview a transaction to the Bitcoin${seoDescriptionNetwork(this.stateService.network)} network using the transaction's raw hex data.`);
this.websocketService.want(['blocks', 'mempool-blocks']);
this.cpfpMode = this.isCpfpParamEnabled(this.route.snapshot.queryParams['cpfp']);
this.cpfpMode = this.route.snapshot.queryParams['cpfp'] === 'true';
this.pushTxForm = this.formBuilder.group({
txRaw: ['', Validators.required],
});
@ -380,10 +380,6 @@ export class TransactionRawComponent implements OnInit, OnDestroy {
}
}
private isCpfpParamEnabled(cpfpParam: string | undefined): boolean {
return cpfpParam === 'true' || cpfpParam === 'advanced' || cpfpParam === 'simple';
}
setupGraph() {
this.maxInOut = Math.min(this.inOutLimit, Math.max(this.transaction?.vin?.length || 1, this.transaction?.vout?.length + 1 || 1));
this.graphHeight = this.graphExpanded ? this.maxInOut * 15 : Math.min(360, this.maxInOut * 80);

View file

@ -82,7 +82,6 @@
<!-- CPFP Details -->
<ng-container *ngIf="cpfpMode && hasCpfp">
<span id="cluster" #cluster class="anchor"></span>
<br>
<div class="title float-start">
<h2 *ngIf="cpfpInfo?.cluster && !isAcceleration" i18n="transaction.cluster|Cluster">Cluster</h2>
@ -93,7 +92,7 @@
<ng-container *ngIf="cpfpInfo?.cluster && !isAcceleration; else legacyCpfp">
<div class="box">
<app-cluster-diagram
[cluster]="cpfpInfo.cluster" [txid]="tx.txid">
[cluster]="cpfpInfo.cluster" [txid]="tx.txid" [isMobile]="isMobile">
</app-cluster-diagram>
</div>
</ng-container>
@ -394,4 +393,4 @@
</ng-template>
</ng-template>
</div>
</div>

View file

@ -173,6 +173,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
graphContainer: ElementRef;
private txList: TransactionsListComponent;
private fragmentAnchor: string | null = null;
private scrolledFragmentAnchor: string | null = null;
private firstFragmentScroll = true;
@ViewChild('txList')
set txListSetter(component: TransactionsListComponent | undefined) {
@ -197,13 +200,6 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
}
@ViewChild('cluster')
set clusterAnchor(element: ElementRef | null | undefined) {
if (element) {
setTimeout(() => { this.applyFragment(); }, 0);
}
}
constructor(
private route: ActivatedRoute,
private router: Router,
@ -228,7 +224,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
ngOnInit() {
this.enterpriseService.page();
this.isDetailsOpen = this.route.snapshot.queryParams['showDetails'] === 'true';
this.cpfpMode = this.isCpfpParamEnabled(this.route.snapshot.queryParams['cpfp']);
this.cpfpMode = this.route.snapshot.queryParams['cpfp'] === 'true';
const urlParams = new URLSearchParams(window.location.search);
this.forceAccelerationSummary = !!urlParams.get('cash_request_id');
@ -609,7 +605,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
this.router.navigate([this.relativeUrlPipe.transform('/tx'), this.txId], {
queryParamsHandling: 'merge',
fragment: this.fragmentParams.toString(),
fragment: this.formatFragment(this.fragmentParams),
});
} else {
this.txId = urlMatch[0];
@ -620,7 +616,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.fragmentParams.delete('vin');
this.router.navigate([this.relativeUrlPipe.transform('/tx'), this.txId], {
queryParamsHandling: 'merge',
fragment: this.fragmentParams.toString(),
fragment: this.formatFragment(this.fragmentParams),
});
}
}
@ -630,7 +626,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
if (window.innerWidth <= 767.98) {
this.router.navigate([this.relativeUrlPipe.transform('/tx'), this.txId], {
queryParamsHandling: 'merge',
preserveFragment: true,
fragment: this.formatFragment(this.fragmentParams, this.fragmentAnchor),
queryParams: { mode: 'details' },
replaceUrl: true,
});
@ -888,7 +884,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
relativeTo: this.route,
queryParams: { showDetails: this.isDetailsOpen ? 'true' : null },
queryParamsHandling: 'merge',
preserveFragment: true,
fragment: this.formatFragment(this.fragmentParams),
replaceUrl: true,
});
this.txList?.setDetailsOpen(this.isDetailsOpen);
@ -1081,6 +1077,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
resetTransaction() {
this.firstLoad = false;
this.firstFragmentScroll = this.fragmentAnchor !== null;
this.scrolledFragmentAnchor = null;
this.gotInitialPosition = false;
this.error = undefined;
this.tx = null;
@ -1108,7 +1106,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.auditStatus = null;
this.accelerationPositions = null;
this.isDetailsOpen = this.route.snapshot.queryParams['showDetails'] === 'true';
this.cpfpMode = this.isCpfpParamEnabled(this.route.snapshot.queryParams['cpfp']);
this.cpfpMode = this.route.snapshot.queryParams['cpfp'] === 'true';
document.body.scrollTo(0, 0);
this.isAcceleration = false;
this.isAccelerated$.next(this.isAcceleration);
@ -1128,41 +1126,26 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
toggleCpfp() {
this.cpfpMode = !this.cpfpMode;
if (this.cpfpInfo?.cluster) {
this.router.navigate([], {
relativeTo: this.route,
queryParams: { cpfp: this.cpfpMode ? 'true' : null },
queryParamsHandling: 'merge',
fragment: this.getCpfpFragment(),
replaceUrl: true,
});
} else {
this.router.navigate([], {
relativeTo: this.route,
queryParams: { cpfp: this.cpfpMode ? 'simple' : null },
queryParamsHandling: 'merge',
preserveFragment: true,
replaceUrl: true,
});
}
this.router.navigate([], {
relativeTo: this.route,
queryParams: { cpfp: this.cpfpMode ? 'true' : null },
queryParamsHandling: 'merge',
fragment: this.formatFragment(this.fragmentParams),
replaceUrl: true,
});
}
private isCpfpParamEnabled(cpfpParam: string | undefined): boolean {
return cpfpParam === 'true' || cpfpParam === 'advanced' || cpfpParam === 'simple';
}
private getCpfpFragment(): string | null {
const currentParams = new URLSearchParams(this.fragmentParams?.toString() || this.route.snapshot.fragment || '');
const fragmentParams = new URLSearchParams();
if (this.cpfpMode) {
fragmentParams.set('cluster', '');
}
for (const [key, value] of currentParams.entries()) {
if (key !== 'cluster') {
fragmentParams.set(key, value);
private formatFragment(fragmentParams: URLSearchParams, anchor: string | null = null): string | null {
const params = new URLSearchParams(fragmentParams.toString());
for (const [key, value] of Array.from(params.entries())) {
if (value === '') {
params.delete(key);
}
}
return fragmentParams.toString() || null;
if (anchor) {
params.set(anchor, '');
}
return params.toString() || null;
}
toggleGraph() {
@ -1172,7 +1155,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
relativeTo: this.route,
queryParams: { showFlow: showFlow },
queryParamsHandling: 'merge',
fragment: 'flow'
fragment: this.formatFragment(this.fragmentParams, showFlow ? 'flow' : null)
});
}
@ -1192,11 +1175,12 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
// simulate normal anchor fragment behavior
applyFragment(): void {
const anchor = Array.from(this.fragmentParams.entries()).find(([frag, value]) => value === '');
if (anchor?.length) {
const anchorElement = document.getElementById(anchor[0]);
if (this.fragmentAnchor && this.scrolledFragmentAnchor !== this.fragmentAnchor) {
const anchorElement = document.getElementById(this.fragmentAnchor);
if (anchorElement) {
anchorElement.scrollIntoView({ behavior: 'smooth' });
anchorElement.scrollIntoView({ behavior: this.firstFragmentScroll ? 'auto' : 'smooth' });
this.firstFragmentScroll = false;
this.scrolledFragmentAnchor = this.fragmentAnchor;
}
}
}
@ -1205,12 +1189,35 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
this.fragmentParams = new URLSearchParams(fragment || '');
const vin = parseInt(this.fragmentParams.get('vin'), 10);
const vout = parseInt(this.fragmentParams.get('vout'), 10);
this.inputIndex = (!isNaN(vin) && vin >= 0) ? vin : null;
this.outputIndex = (!isNaN(vout) && vout >= 0) ? vout : null;
const inputIndex = (!isNaN(vin) && vin >= 0) ? vin : null;
const outputIndex = (!isNaN(vout) && vout >= 0) ? vout : null;
const selectionChanged = inputIndex !== this.inputIndex || outputIndex !== this.outputIndex;
const anchor = Array.from(this.fragmentParams.entries()).find(([, value]) => value === '')?.[0] || null;
this.inputIndex = inputIndex;
this.outputIndex = outputIndex;
if (this.fragmentParams.has('accelerate')) {
this.forceAccelerationSummary = true;
}
setTimeout(() => { this.applyFragment(); }, 0);
if (!anchor && !this.fragmentAnchor) {
this.firstFragmentScroll = false;
}
if (selectionChanged && anchor) {
this.scrolledFragmentAnchor = null;
}
if (anchor !== this.fragmentAnchor) {
this.fragmentAnchor = anchor;
this.scrolledFragmentAnchor = null;
if (!this.fragmentAnchor) {
this.firstFragmentScroll = false;
}
}
if (this.scrolledFragmentAnchor !== this.fragmentAnchor) {
if (this.fragmentAnchor) {
setTimeout(() => { this.applyFragment(); }, 0);
} else {
this.firstFragmentScroll = false;
}
}
}
setHasAccelerationDetails(hasDetails: boolean): void {
@ -1237,20 +1244,20 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
}
onAccelerationCompleted(): void {
this.router.navigate([], { fragment: null, queryParamsHandling: 'merge' });
this.router.navigate([], { fragment: this.formatFragment(this.fragmentParams), queryParamsHandling: 'merge' });
this.accelerationFlowCompleted = true;
this.forceAccelerationSummary = false;
}
closeAccelerator(): void {
this.router.navigate([], { fragment: null, queryParamsHandling: 'merge' });
this.router.navigate([], { fragment: this.formatFragment(this.fragmentParams), queryParamsHandling: 'merge' });
this.hideAccelerationSummary = true;
this.forceAccelerationSummary = false;
this.storageService.setValue('hide-accelerator-pref', 'true');
}
openAccelerator(): void {
this.router.navigate([], { fragment: 'accelerate', queryParamsHandling: 'merge' });
this.router.navigate([], { fragment: this.formatFragment(this.fragmentParams, 'accelerate'), queryParamsHandling: 'merge' });
this.accelerationFlowCompleted = false;
this.hideAccelerationSummary = false;
this.storageService.setValue('hide-accelerator-pref', 'false');