]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-18670 Drop scrollToElement helper function in favor of native browser scroll...
author7PH <benjamin.raymond@sonarsource.com>
Wed, 3 May 2023 11:56:07 +0000 (13:56 +0200)
committersonartech <sonartech@sonarsource.com>
Wed, 3 May 2023 20:02:58 +0000 (20:02 +0000)
16 files changed:
server/sonar-web/src/main/js/app/components/global-search/GlobalSearch.tsx
server/sonar-web/src/main/js/apps/component-measures/components/__tests__/MeasureContent-test.tsx
server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx
server/sonar-web/src/main/js/apps/issues/__tests__/utils-test.ts
server/sonar-web/src/main/js/apps/issues/crossComponentSourceViewer/__tests__/SnippetViewer-test.tsx
server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx
server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisListRenderer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotPrimaryLocationBox.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSnippetContainerRenderer.tsx
server/sonar-web/src/main/js/apps/settings/components/SettingsSearchRenderer.tsx
server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
server/sonar-web/src/main/js/components/workspace/WorkspaceComponentViewer.tsx
server/sonar-web/src/main/js/helpers/__tests__/scrolling-test.ts [deleted file]
server/sonar-web/src/main/js/helpers/mocks/security-hotspots.ts
server/sonar-web/src/main/js/helpers/scrolling.ts [deleted file]

index 131c63ce23cba6ac168f10013743cca154067e2c..beda11b6f7d45fa6d715f854ce3df3aa02c04a88 100644 (file)
@@ -20,9 +20,9 @@
 
 import {
   DropdownMenu,
+  INTERACTIVE_TOOLTIP_DELAY,
   InputSearch,
   InteractiveIcon,
-  INTERACTIVE_TOOLTIP_DELAY,
   MenuSearchIcon,
   Popup,
   PopupZLevel,
@@ -40,7 +40,6 @@ import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getKeyboardShortcutEnabled } from '../../../helpers/preferences';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { getComponentOverviewUrl } from '../../../helpers/urls';
 import { ComponentQualifier } from '../../../types/component';
 import { Dict } from '../../../types/types';
@@ -279,11 +278,9 @@ export class GlobalSearch extends React.PureComponent<Props, State> {
       const node = this.nodes[this.state.selected];
 
       if (node && this.node) {
-        // using scrollIntoView here is creating some weird scroll behaviour when scrolling
-        scrollToElement(node, {
-          topOffset: 30,
-          bottomOffset: 30,
-          parent: this.node,
+        node.scrollIntoView({
+          block: 'center',
+          behavior: 'smooth',
         });
       }
     }
index feb557ff0421c79986d145edfa6c6577181b85a0..987dd463d0e27c36146ad0024737e73504849ab0 100644 (file)
@@ -25,10 +25,6 @@ import { mockRouter } from '../../../../helpers/testMocks';
 import { waitAndUpdate } from '../../../../helpers/testUtils';
 import MeasureContent from '../MeasureContent';
 
-jest.mock('../../../../helpers/scrolling', () => ({
-  scrollToElement: jest.fn(),
-}));
-
 jest.mock('../../../../api/components', () => {
   const { mockComponentMeasure } = jest.requireActual('../../../../helpers/mocks/component');
   return {
index 22c70815a62aeb3c005c61b81cce8b489cfe8d0a..a909faf1575520b991f86a6af57790add55d3829 100644 (file)
  */
 import { throttle } from 'lodash';
 import * as React from 'react';
-import { Button } from '../../../components/controls/buttons';
 import ListFooter from '../../../components/controls/ListFooter';
+import { Button } from '../../../components/controls/buttons';
 import { Alert } from '../../../components/ui/Alert';
 import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { formatMeasure, isDiffMetric, isPeriodBestValue } from '../../../helpers/measures';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { BranchLike } from '../../../types/branch-like';
 import { MeasurePageView } from '../../../types/measures';
 import {
@@ -160,12 +159,10 @@ export default class FilesView extends React.PureComponent<Props, State> {
   };
 
   scrollToElement = () => {
-    if (this.listContainer) {
-      const elem = this.listContainer.getElementsByClassName('selected')[0];
-      if (elem) {
-        scrollToElement(elem, { topOffset: 215, bottomOffset: 100 });
-      }
-    }
+    this.listContainer?.getElementsByClassName('selected')[0]?.scrollIntoView({
+      block: 'center',
+      behavior: 'smooth',
+    });
   };
 
   render() {
index 9598f11890493a63d89f7efdc0d25a8b08b3218d..50d36594ac6c1a0933e3dcdad62f2301467cf04f 100644 (file)
@@ -25,10 +25,6 @@ import {
   shouldOpenStandardsFacet,
 } from '../utils';
 
-jest.mock('../../../helpers/scrolling', () => ({
-  scrollToElement: jest.fn(),
-}));
-
 beforeEach(() => {
   jest.clearAllMocks();
 });
index 16fe5128a637b3026dd5c828cd732c0b16f46ae1..71915f77d7a87b9f88612e2d8df7d3074752e18c 100644 (file)
@@ -26,10 +26,6 @@ import { mockIssue } from '../../../../helpers/testMocks';
 import { renderComponent } from '../../../../helpers/testReactTestingUtils';
 import SnippetViewer from '../SnippetViewer';
 
-jest.mock('../../../../helpers/scrolling', () => ({
-  scrollHorizontally: jest.fn(),
-}));
-
 beforeEach(() => {
   jest.clearAllMocks();
 });
index 864000e8f1e0ab829ad630f068bb194dd661e1df..5ed0f7692b7b04d9befde9ba0369e787bfa03884 100644 (file)
@@ -22,7 +22,6 @@ import { throttle } from 'lodash';
 import * as React from 'react';
 import { getProjectActivity } from '../../../api/projectActivity';
 import { parseDate, toShortNotSoISOString } from '../../../helpers/dates';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { Analysis, ParsedAnalysis } from '../../../types/project-activity';
 import { Dict } from '../../../types/types';
 import BranchAnalysisListRenderer from './BranchAnalysisListRenderer';
@@ -46,7 +45,6 @@ const STICKY_BADGE_SCROLL_OFFSET = 10;
 export default class BranchAnalysisList extends React.PureComponent<Props, State> {
   mounted = false;
   badges: Dict<HTMLDivElement> = {};
-  scrollableNode?: HTMLDivElement;
   state: State = {
     analyses: [],
     loading: true,
@@ -69,10 +67,10 @@ export default class BranchAnalysisList extends React.PureComponent<Props, State
   }
 
   scrollToSelected() {
-    const selectedNode = document.querySelector('.branch-analysis.selected');
-    if (this.scrollableNode && selectedNode) {
-      scrollToElement(selectedNode, { parent: this.scrollableNode, bottomOffset: 40 });
-    }
+    document.querySelector('.branch-analysis.selected')?.scrollIntoView({
+      block: 'center',
+      behavior: 'smooth',
+    });
   }
 
   fetchAnalyses(initial = false) {
@@ -150,9 +148,6 @@ export default class BranchAnalysisList extends React.PureComponent<Props, State
         onSelectAnalysis={onSelectAnalysis}
         range={range}
         registerBadgeNode={this.registerBadgeNode}
-        registerScrollableNode={(el) => {
-          this.scrollableNode = el;
-        }}
         selectedAnalysisKey={analysis}
         shouldStick={this.shouldStick}
       />
index 79425097aef6d3a056ec75ec4200327da44f7e0c..8bb4bf17c76b52a647e16de39bc7c76fff0bbdae 100644 (file)
@@ -40,7 +40,6 @@ export interface BranchAnalysisListRendererProps {
   onSelectAnalysis: (analysis: ParsedAnalysis) => void;
   range: number;
   registerBadgeNode: (version: string) => (el: HTMLDivElement) => void;
-  registerScrollableNode: (el: HTMLDivElement) => void;
   selectedAnalysisKey: string;
   shouldStick: (version: string) => boolean;
 }
@@ -138,11 +137,7 @@ function BranchAnalysisListRenderer(
         />
       </div>
       <div className="branch-analysis-list-wrapper">
-        <div
-          className="bordered branch-analysis-list"
-          onScroll={props.handleScroll}
-          ref={props.registerScrollableNode}
-        >
+        <div className="bordered branch-analysis-list" onScroll={props.handleScroll}>
           <DeferredSpinner className="big-spacer-top" loading={loading} />
 
           {!loading && !hasFilteredData ? (
index 1db2708e3ba73de09f46b059c51ae64cd1cec73b..580f7592375f42707c29d9a6684d6521f2b03475 100644 (file)
@@ -25,7 +25,6 @@ import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import DeferredSpinner from '../../components/ui/DeferredSpinner';
 import { isBranch } from '../../helpers/branch-like';
 import { translate } from '../../helpers/l10n';
-import { scrollToElement } from '../../helpers/scrolling';
 import { BranchLike } from '../../types/branch-like';
 import { SecurityStandard, Standards } from '../../types/security';
 import { HotspotFilters, HotspotStatusFilter, RawHotspot } from '../../types/security-hotspots';
@@ -90,12 +89,16 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
   const scrollableRef = React.useRef(null);
 
   React.useEffect(() => {
-    const parent = scrollableRef.current;
-    const element =
-      selectedHotspot && document.querySelector(`[data-hotspot-key="${selectedHotspot.key}"]`);
-    if (parent && element) {
-      scrollToElement(element, { parent, smooth: true, topOffset: 100, bottomOffset: 100 });
+    if (!selectedHotspot) {
+      return;
     }
+    // Wait for next tick, in case newly selected hotspot is not yet expanded
+    setTimeout(() => {
+      document.querySelector(`[data-hotspot-key="${selectedHotspot.key}"]`)?.scrollIntoView({
+        block: 'center',
+        behavior: 'smooth',
+      });
+    });
   }, [selectedHotspot]);
 
   return (
index b0750860495e92e5d42f6bd021cbc002e8b52968..975fa64fb534d09712a86719f3a1e35077a59b30 100644 (file)
@@ -27,11 +27,14 @@ import { Hotspot } from '../../../types/security-hotspots';
 import { CurrentUser, isLoggedIn } from '../../../types/users';
 import './HotspotPrimaryLocationBox.css';
 
+const SCROLL_DELAY = 100;
+const SCROLL_TOP_OFFSET = 100; // 5 lines above
+const SCROLL_BOTTOM_OFFSET = 28; // 1 line below + margin
+
 export interface HotspotPrimaryLocationBoxProps {
   hotspot: Hotspot;
   onCommentClick: () => void;
   currentUser: CurrentUser;
-  scroll: (element: HTMLElement, offset?: number) => void;
   secondaryLocationSelected: boolean;
 }
 
@@ -41,11 +44,16 @@ export function HotspotPrimaryLocationBox(props: HotspotPrimaryLocationBoxProps)
   const locationRef = React.useRef<HTMLDivElement>(null);
 
   React.useEffect(() => {
-    const { current } = locationRef;
-    if (current && !secondaryLocationSelected) {
-      props.scroll(current);
+    if (locationRef.current && !secondaryLocationSelected) {
+      // We need this delay to let the parent resize itself before scrolling
+      setTimeout(() => {
+        locationRef.current?.scrollIntoView({
+          block: 'nearest',
+          behavior: 'smooth',
+        });
+      }, SCROLL_DELAY);
     }
-  });
+  }, [locationRef, secondaryLocationSelected]);
 
   return (
     <div
@@ -54,6 +62,10 @@ export function HotspotPrimaryLocationBox(props: HotspotPrimaryLocationBoxProps)
         'display-flex-space-between display-flex-center padded-top padded-bottom big-padded-left big-padded-right',
         `hotspot-risk-exposure-${hotspot.rule.vulnerabilityProbability}`
       )}
+      style={{
+        scrollMarginTop: `${SCROLL_TOP_OFFSET}px`,
+        scrollMarginBottom: `${SCROLL_BOTTOM_OFFSET}px`,
+      }}
       ref={locationRef}
     >
       <div className="text-bold">
index 6da6418b9b87babf4c8c15d03f761fec68ec000e..fbdc9e0062c35a74bacddfef9b33e406162be08d 100644 (file)
@@ -20,7 +20,6 @@
 import * as React from 'react';
 import DeferredSpinner from '../../../components/ui/DeferredSpinner';
 import { translate } from '../../../helpers/l10n';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { BranchLike } from '../../../types/branch-like';
 import { Hotspot } from '../../../types/security-hotspots';
 import {
@@ -53,30 +52,8 @@ export interface HotspotSnippetContainerRendererProps {
 }
 
 const noop = () => undefined;
-const SCROLL_DELAY = 100;
 const EXPAND_ANIMATION_SPEED = 200;
 
-const TOP_OFFSET = 100; // 5 lines above
-const BOTTOM_OFFSET = 28; // 1 line below + margin
-
-/* Exported for testing */
-export function getScrollHandler(scrollableRef: React.RefObject<HTMLDivElement>) {
-  return (element: Element, offset?: number, smooth = true) => {
-    /* We need this delay to let the parent resize itself before scrolling */
-    setTimeout(() => {
-      const parent = scrollableRef.current;
-      if (parent) {
-        scrollToElement(element, {
-          parent,
-          topOffset: offset ?? TOP_OFFSET,
-          bottomOffset: offset ?? BOTTOM_OFFSET,
-          smooth,
-        });
-      }
-    }, SCROLL_DELAY);
-  };
-}
-
 /* Exported for testing */
 export async function animateExpansion(
   scrollableRef: React.RefObject<HTMLDivElement>,
@@ -154,7 +131,6 @@ export default function HotspotSnippetContainerRenderer(
       <HotspotPrimaryLocationBox
         hotspot={hotspot}
         onCommentClick={props.onCommentButtonClick}
-        scroll={getScrollHandler(scrollableRef)}
         secondaryLocationSelected={secondaryLocationSelected}
       />
     ),
index c1cfa10fca947972fd7adec76f7000adb5c8b1e0..238ba20eed385629757b2754b64eb0c75c24aec1 100644 (file)
@@ -24,7 +24,6 @@ import { DropdownOverlay } from '../../../components/controls/Dropdown';
 import OutsideClickHandler from '../../../components/controls/OutsideClickHandler';
 import SearchBox from '../../../components/controls/SearchBox';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { ExtendedSettingDefinition } from '../../../types/settings';
 import { Component } from '../../../types/types';
 import { buildSettingLink, isRealSettingKey } from '../utils';
@@ -46,15 +45,10 @@ export interface SettingsSearchRendererProps {
 export default function SettingsSearchRenderer(props: SettingsSearchRendererProps) {
   const { className, component, results, searchQuery, selectedResult, showResults } = props;
 
-  const scrollableNodeRef = React.useRef(null);
   const selectedNodeRef = React.useRef<HTMLLIElement>(null);
 
   React.useEffect(() => {
-    const parent = scrollableNodeRef.current;
-    const selectedNode = selectedNodeRef.current;
-    if (selectedNode && parent) {
-      scrollToElement(selectedNode, { topOffset: 30, bottomOffset: 30, parent });
-    }
+    selectedNodeRef.current?.scrollIntoView({ block: 'center', behavior: 'smooth' });
   });
 
   return (
@@ -72,7 +66,6 @@ export default function SettingsSearchRenderer(props: SettingsSearchRendererProp
             <ul
               className="settings-search-results menu"
               title={translate('settings.search.results')}
-              ref={scrollableNodeRef}
             >
               {results && results.length > 0 ? (
                 results.map((r) => (
index 9ce6e41c7d2f3dff9af2492056a562cd0a510b0c..0392524410d3bbede09aac92edcde413670dc4cb 100644 (file)
@@ -29,15 +29,14 @@ import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
 import { translate } from '../../../helpers/l10n';
 import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages';
-import { scrollToElement } from '../../../helpers/scrolling';
 import { WebApi } from '../../../types/types';
 import '../styles/web-api.css';
 import {
+  Query,
   getActionKey,
   isDomainPathActive,
   parseQuery,
   parseVersion,
-  Query,
   serializeQuery,
 } from '../utils';
 import Domain from './Domain';
@@ -96,11 +95,9 @@ export class WebApiApp extends React.PureComponent<Props, State> {
   scrollToAction = () => {
     const splat = this.props.params.splat || '';
     const action = document.getElementById(splat);
-    if (action) {
-      scrollToElement(action, { topOffset: 20, bottomOffset: 20 });
-    } else {
-      window.scrollTo(0, 0);
-    }
+    action?.scrollIntoView({
+      block: 'center',
+    });
   };
 
   updateQuery = (newQuery: Partial<Query>) => {
index b37ff46faecbd6170080a3459f8f9256c0639cc6..f4552defa6aa902d4cce4302df0870747528190e 100644 (file)
@@ -22,13 +22,12 @@ import * as React from 'react';
 import { getParents } from '../../api/components';
 import withBranchStatusActions from '../../app/components/branch-status/withBranchStatusActions';
 import { isPullRequest } from '../../helpers/branch-like';
-import { scrollToElement } from '../../helpers/scrolling';
 import { BranchLike } from '../../types/branch-like';
 import { Issue, SourceViewerFile } from '../../types/types';
 import SourceViewer from '../SourceViewer/SourceViewer';
-import { ComponentDescriptor } from './context';
 import WorkspaceComponentTitle from './WorkspaceComponentTitle';
 import WorkspaceHeader, { Props as WorkspaceHeaderProps } from './WorkspaceHeader';
+import { ComponentDescriptor } from './context';
 
 export interface Props extends Omit<WorkspaceHeaderProps, 'children' | 'onClose'> {
   component: ComponentDescriptor;
@@ -78,12 +77,7 @@ export class WorkspaceComponentViewer extends React.PureComponent<Props> {
         `.source-line[data-line-number="${this.props.component.line}"]`
       );
       if (row) {
-        scrollToElement(row, {
-          smooth: false,
-          parent: this.container,
-          topOffset: 50,
-          bottomOffset: 50,
-        });
+        row.scrollIntoView({ block: 'center' });
       }
     }
   };
diff --git a/server/sonar-web/src/main/js/helpers/__tests__/scrolling-test.ts b/server/sonar-web/src/main/js/helpers/__tests__/scrolling-test.ts
deleted file mode 100644 (file)
index f9e938f..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-import { scrollToElement } from '../scrolling';
-
-beforeAll(() => {
-  jest.useFakeTimers();
-});
-
-afterAll(() => {
-  jest.runOnlyPendingTimers();
-  jest.useRealTimers();
-});
-
-describe('scrollToElement', () => {
-  it('should scroll parent up to element', () => {
-    const element = document.createElement('a');
-    element.getBoundingClientRect = mockGetBoundingClientRect({ top: 5, bottom: 20 });
-
-    const parent = document.createElement('div');
-    parent.getBoundingClientRect = mockGetBoundingClientRect({ height: 30, top: 15 });
-    parent.scrollTop = 10;
-    parent.scrollLeft = 12;
-    parent.appendChild(element);
-
-    document.body.appendChild(parent);
-    scrollToElement(element, { parent, smooth: false });
-
-    expect(parent.scrollTop).toEqual(0);
-    expect(parent.scrollLeft).toEqual(12);
-  });
-
-  it('should scroll parent down to element', () => {
-    const element = document.createElement('a');
-    element.getBoundingClientRect = mockGetBoundingClientRect({ top: 25, bottom: 50 });
-
-    const parent = document.createElement('div');
-    parent.getBoundingClientRect = mockGetBoundingClientRect({ height: 30, top: 15 });
-    parent.scrollTop = 10;
-    parent.scrollLeft = 12;
-    parent.appendChild(element);
-
-    document.body.appendChild(parent);
-    scrollToElement(element, { parent, smooth: false });
-
-    expect(parent.scrollTop).toEqual(15);
-    expect(parent.scrollLeft).toEqual(12);
-  });
-
-  it('should scroll window down to element', () => {
-    const element = document.createElement('a');
-    element.getBoundingClientRect = mockGetBoundingClientRect({ top: 840, bottom: 845 });
-
-    Object.defineProperty(window, 'innerHeight', { value: 400 });
-    window.scrollTo = jest.fn();
-
-    document.body.appendChild(element);
-
-    scrollToElement(element, { smooth: false });
-
-    expect(window.scrollTo).toHaveBeenCalledWith(0, 445);
-  });
-
-  it('should scroll window up to element', () => {
-    const element = document.createElement('a');
-    element.getBoundingClientRect = mockGetBoundingClientRect({ top: -10, bottom: 10 });
-
-    Object.defineProperty(window, 'innerHeight', { value: 50 });
-    window.scrollTo = jest.fn();
-
-    document.body.appendChild(element);
-
-    scrollToElement(element, { smooth: false });
-
-    expect(window.scrollTo).toHaveBeenCalledWith(0, -10);
-  });
-
-  it('should scroll window down to element smoothly', () => {
-    const element = document.createElement('a');
-    element.getBoundingClientRect = mockGetBoundingClientRect({ top: 840, bottom: 845 });
-
-    Object.defineProperty(window, 'innerHeight', { value: 400 });
-    window.scrollTo = jest.fn();
-
-    document.body.appendChild(element);
-
-    scrollToElement(element, {});
-
-    jest.runAllTimers();
-
-    expect(window.scrollTo).toHaveBeenCalledTimes(10);
-  });
-});
-
-const mockGetBoundingClientRect = (overrides: Partial<ClientRect>) => () =>
-  ({
-    bottom: 0,
-    height: 0,
-    left: 0,
-    right: 0,
-    top: 0,
-    width: 0,
-    ...overrides,
-  } as DOMRect);
index afc79f6c77f0d23f27c76670ea262876ee3e555b..946b1f79a24496d23d2813936de9704d645cfe74 100644 (file)
@@ -67,17 +67,17 @@ export function mockHotspot(overrides?: Partial<Hotspot>): Hotspot {
     creationDate: '2013-05-13T17:55:41+0200',
     flows: [{ locations: [mockFlowLocation()] }],
     key: '01fc972e-2a3c-433e-bcae-0bd7f88f5123',
-    line: 142,
+    line: 6,
     message: "'3' is a magic number.",
     project: mockHotspotComponent({ qualifier: ComponentQualifier.Project }),
     resolution: HotspotResolution.FIXED,
     rule: mockHotspotRule(),
     status: HotspotStatus.REVIEWED,
     textRange: {
-      startLine: 142,
-      endLine: 142,
-      startOffset: 26,
-      endOffset: 83,
+      startLine: 6,
+      endLine: 6,
+      startOffset: 3,
+      endOffset: 9,
     },
     updateDate: '2013-05-13T17:55:42+0200',
     users: [assigneeUser, authorUser],
diff --git a/server/sonar-web/src/main/js/helpers/scrolling.ts b/server/sonar-web/src/main/js/helpers/scrolling.ts
deleted file mode 100644 (file)
index 5edda86..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-const SCROLLING_DURATION = 100;
-const SCROLLING_INTERVAL = 10;
-const SCROLLING_STEPS = SCROLLING_DURATION / SCROLLING_INTERVAL;
-
-function isWindow(element: Element | Window): element is Window {
-  return element === window;
-}
-
-function getScroll(element: Element | Window) {
-  return isWindow(element)
-    ? { x: window.pageXOffset, y: window.pageYOffset }
-    : { x: element.scrollLeft, y: element.scrollTop };
-}
-
-function scrollElement(element: Element | Window, x: number, y: number): Promise<void> {
-  if (isWindow(element)) {
-    window.scrollTo(x, y);
-  } else {
-    element.scrollLeft = x;
-    element.scrollTop = y;
-  }
-  return Promise.resolve();
-}
-
-function smoothScroll(
-  target: number,
-  current: number,
-  scroll: (position: number) => void
-): Promise<void> {
-  const positiveDirection = target > current;
-  const step = Math.ceil(Math.abs(target - current) / SCROLLING_STEPS);
-  let stepsDone = 0;
-
-  return new Promise((resolve) => {
-    const interval = setInterval(() => {
-      if (current === target || SCROLLING_STEPS === stepsDone) {
-        clearInterval(interval);
-        resolve();
-      } else {
-        let goal;
-        if (positiveDirection) {
-          goal = Math.min(target, current + step);
-        } else {
-          goal = Math.max(target, current - step);
-        }
-        stepsDone++;
-        current = goal;
-        scroll(goal);
-      }
-    }, SCROLLING_INTERVAL);
-  });
-}
-
-function smoothScrollTop(parent: Element | Window, position: number) {
-  const scroll = getScroll(parent);
-  return smoothScroll(position, scroll.y, (position) => scrollElement(parent, scroll.x, position));
-}
-
-/**
- * @deprecated use scrollIntoView instead
- */
-export function scrollToElement(
-  element: Element,
-  options: {
-    topOffset?: number;
-    bottomOffset?: number;
-    parent?: Element;
-    smooth?: boolean;
-  }
-): void {
-  const opts = { topOffset: 0, bottomOffset: 0, parent: window, smooth: true, ...options };
-  const { parent } = opts;
-
-  const { top, bottom } = element.getBoundingClientRect();
-
-  const scroll = getScroll(parent);
-
-  const height: number = isWindow(parent)
-    ? window.innerHeight
-    : parent.getBoundingClientRect().height;
-
-  const parentTop = isWindow(parent) ? 0 : parent.getBoundingClientRect().top;
-
-  if (top - parentTop < opts.topOffset) {
-    const goal = scroll.y - opts.topOffset + top - parentTop;
-    if (opts.smooth) {
-      addToScrollQueue(smoothScrollTop, parent, goal);
-    } else {
-      addToScrollQueue(scrollElement, parent, scroll.x, goal);
-    }
-  }
-
-  if (bottom - parentTop > height - opts.bottomOffset) {
-    const goal = scroll.y + bottom - parentTop - height + opts.bottomOffset;
-    if (opts.smooth) {
-      addToScrollQueue(smoothScrollTop, parent, goal);
-    } else {
-      addToScrollQueue(scrollElement, parent, scroll.x, goal);
-    }
-  }
-}
-
-type ScrollFunction = (element: Element | Window, x: number, y?: number) => Promise<void>;
-
-interface ScrollQueueItem {
-  element: Element | Window;
-  fn: ScrollFunction;
-  x: number;
-  y?: number;
-}
-
-const queue: ScrollQueueItem[] = [];
-let queueRunning: boolean;
-
-function addToScrollQueue(
-  fn: ScrollFunction,
-  element: Element | Window,
-  x: number,
-  y?: number
-): void {
-  queue.push({ fn, element, x, y });
-  if (!queueRunning) {
-    processQueue();
-  }
-}
-
-function processQueue() {
-  if (queue.length > 0) {
-    queueRunning = true;
-    const { fn, element, x, y } = queue.shift()!;
-    fn(element, x, y).then(processQueue).catch(processQueue);
-  } else {
-    queueRunning = false;
-  }
-}