Przeglądaj źródła

Initially move to baron scrollbar

Alexander Zobnin 7 lat temu
rodzic
commit
77d2ee9add

+ 1 - 0
package.json

@@ -136,6 +136,7 @@
     "angular-route": "^1.6.6",
     "angular-sanitize": "^1.6.6",
     "babel-polyfill": "^6.26.0",
+    "baron": "^3.0.3",
     "brace": "^0.10.0",
     "classnames": "^2.2.5",
     "clipboard": "^1.7.1",

+ 21 - 10
public/app/core/components/ScrollBar/ScrollBar.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import PerfectScrollbar from 'perfect-scrollbar';
+import baron from 'baron';
 
 export interface Props {
   children: any;
@@ -8,31 +8,36 @@ export interface Props {
 
 export default class ScrollBar extends React.Component<Props, any> {
   private container: any;
-  private ps: PerfectScrollbar;
+  private scrollbar: baron;
 
   constructor(props) {
     super(props);
   }
 
   componentDidMount() {
-    this.ps = new PerfectScrollbar(this.container, {
-      wheelPropagation: true,
+    this.scrollbar = baron({
+      root: this.container.parentElement,
+      scroller: this.container,
+      bar: '.baron__bar',
+      barOnCls: '_scrollbar',
+      scrollingCls: '_scrolling',
+      track: '.baron__track',
     });
   }
 
   componentDidUpdate() {
-    this.ps.update();
+    this.scrollbar.update();
   }
 
   componentWillUnmount() {
-    this.ps.destroy();
+    this.scrollbar.dispose();
   }
 
   // methods can be invoked by outside
   setScrollTop(top) {
     if (this.container) {
       this.container.scrollTop = top;
-      this.ps.update();
+      this.scrollbar.update();
 
       return true;
     }
@@ -42,7 +47,7 @@ export default class ScrollBar extends React.Component<Props, any> {
   setScrollLeft(left) {
     if (this.container) {
       this.container.scrollLeft = left;
-      this.ps.update();
+      this.scrollbar.update();
 
       return true;
     }
@@ -55,8 +60,14 @@ export default class ScrollBar extends React.Component<Props, any> {
 
   render() {
     return (
-      <div className={this.props.className} ref={this.handleRef}>
-        {this.props.children}
+      <div className="baron baron__root baron__clipper">
+        <div className={this.props.className + ' baron__scroller'} ref={this.handleRef}>
+          {this.props.children}
+        </div>
+
+        <div className="baron__track">
+          <div className="baron__bar" />
+        </div>
       </div>
     );
   }

+ 32 - 5
public/app/core/components/scroll/scroll.ts

@@ -1,15 +1,41 @@
-import PerfectScrollbar from 'perfect-scrollbar';
+import $ from 'jquery';
+import baron from 'baron';
 import coreModule from 'app/core/core_module';
 import appEvents from 'app/core/app_events';
 
+const scrollBarHTML = `
+<div class="baron__track">
+  <div class="baron__bar"></div>
+</div>
+`;
+
+const scrollRootClass = 'baron baron__root';
+const scrollerClass = 'baron__scroller';
+
 export function geminiScrollbar() {
   return {
     restrict: 'A',
     link: function(scope, elem, attrs) {
-      let scrollbar = new PerfectScrollbar(elem[0], {
-        wheelPropagation: true,
-        wheelSpeed: 3,
+      let scrollRoot = elem.parent();
+      let scroller = elem;
+
+      if (attrs.grafanaScrollbar && attrs.grafanaScrollbar === 'scrollonroot') {
+        scrollRoot = scroller;
+      }
+
+      scrollRoot.addClass(scrollRootClass);
+      $(scrollBarHTML).appendTo(scrollRoot);
+      elem.addClass(scrollerClass);
+
+      let scrollbar = baron({
+        root: scrollRoot[0],
+        scroller: scroller[0],
+        bar: '.baron__bar',
+        barOnCls: '_scrollbar',
+        scrollingCls: '_scrolling',
+        track: '.baron__track',
       });
+
       let lastPos = 0;
 
       appEvents.on(
@@ -37,7 +63,8 @@ export function geminiScrollbar() {
       });
 
       scope.$on('$destroy', () => {
-        scrollbar.destroy();
+        // scrollbar.destroy();
+        scrollbar.dispose();
       });
     },
   };

+ 2 - 0
public/app/core/components/search/search.html

@@ -19,6 +19,7 @@
 
 	<div class="search-dropdown">
     <div class="search-dropdown__col_1">
+      <div class="search-results-scroller">
         <div class="search-results-container" grafana-scrollbar>
           <h6 ng-show="!ctrl.isLoading && ctrl.results.length === 0">No dashboards matching your query were found.</h6>
           <dashboard-search-results
@@ -27,6 +28,7 @@
             on-folder-expanding="ctrl.folderExpanding()"
             on-folder-expanded="ctrl.folderExpanded($folder)" />
         </div>
+      </div>
     </div>
 
     <div class="search-dropdown__col_2">

+ 27 - 4
public/app/features/panel/panel_directive.ts

@@ -1,6 +1,7 @@
 import angular from 'angular';
+import $ from 'jquery';
 import Drop from 'tether-drop';
-import PerfectScrollbar from 'perfect-scrollbar';
+import baron from 'baron';
 
 var module = angular.module('grafana.directives');
 
@@ -86,6 +87,9 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
 
       function panelHeightUpdated() {
         panelContent.css({ height: ctrl.height + 'px' });
+      }
+
+      function resizeScrollableContent() {
         if (panelScrollbar) {
           panelScrollbar.update();
         }
@@ -100,8 +104,26 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
       // update scrollbar after mounting
       ctrl.events.on('component-did-mount', () => {
         if (ctrl.__proto__.constructor.scrollable) {
-          panelScrollbar = new PerfectScrollbar(panelContent[0], {
-            wheelPropagation: true,
+          const scrollRootClass = 'baron baron__root baron__clipper panel-content--scrollable';
+          const scrollerClass = 'baron__scroller';
+          const scrollBarHTML = `
+            <div class="baron__track">
+              <div class="baron__bar"></div>
+            </div>
+          `;
+
+          let scrollRoot = panelContent;
+          let scroller = panelContent.find(':first-child').find(':first-child');
+          scrollRoot.addClass(scrollRootClass);
+          $(scrollBarHTML).appendTo(scrollRoot);
+          scroller.addClass(scrollerClass);
+
+          panelScrollbar = baron({
+            root: scrollRoot[0],
+            scroller: scroller[0],
+            bar: '.baron__bar',
+            barOnCls: '_scrollbar',
+            scrollingCls: '_scrolling',
           });
         }
       });
@@ -110,6 +132,7 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
         ctrl.calculatePanelHeight();
         panelHeightUpdated();
         $timeout(() => {
+          resizeScrollableContent();
           ctrl.render();
         });
       });
@@ -199,7 +222,7 @@ module.directive('grafanaPanel', function($rootScope, $document, $timeout) {
         }
 
         if (panelScrollbar) {
-          panelScrollbar.update();
+          panelScrollbar.dispose();
         }
       });
     },

+ 12 - 10
public/app/partials/dashboard.html

@@ -1,18 +1,20 @@
 <div dash-class ng-if="ctrl.dashboard">
 	<dashnav dashboard="ctrl.dashboard"></dashnav>
 
-	<div class="scroll-canvas scroll-canvas--dashboard" grafana-scrollbar>
-		<dashboard-settings dashboard="ctrl.dashboard"
-											  ng-if="ctrl.dashboardViewState.state.editview"
-												class="dashboard-settings">
-		</dashboard-settings>
+	<div class="scroll-canvas scroll-canvas--dashboard">
+		<div grafana-scrollbar>
+			<dashboard-settings dashboard="ctrl.dashboard"
+													ng-if="ctrl.dashboardViewState.state.editview"
+													class="dashboard-settings">
+			</dashboard-settings>
 
-		<div class="dashboard-container">
-			<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
-			</dashboard-submenu>
+			<div class="dashboard-container">
+				<dashboard-submenu ng-if="ctrl.dashboard.meta.submenuEnabled" dashboard="ctrl.dashboard">
+				</dashboard-submenu>
 
-			<dashboard-grid get-panel-container="ctrl.getPanelContainer">
-			</dashboard-grid>
+				<dashboard-grid get-panel-container="ctrl.getPanelContainer">
+				</dashboard-grid>
+			</div>
 		</div>
 	</div>
 </div>

+ 39 - 9
public/app/plugins/panel/graph/legend.ts

@@ -1,7 +1,7 @@
 import angular from 'angular';
 import _ from 'lodash';
 import $ from 'jquery';
-import PerfectScrollbar from 'perfect-scrollbar';
+import baron from 'baron';
 
 var module = angular.module('grafana.directives');
 
@@ -250,23 +250,53 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
       }
 
       function addScrollbar() {
-        const scrollbarOptions = {
-          // Number of pixels the content height can surpass the container height without enabling the scroll bar.
-          scrollYMarginOffset: 2,
-          suppressScrollX: true,
-          wheelPropagation: true,
+        const scrollRootClass = 'baron baron__root';
+        const scrollerClass = 'baron__scroller';
+        const scrollBarHTML = `
+          <div class="baron__track">
+            <div class="baron__bar"></div>
+          </div>
+        `;
+
+        let scrollRoot = elem.parent();
+        // let scroller = elem.find(':first-child').first();
+        let scroller = elem;
+
+        // clear existing scroll bar track to prevent duplication
+        elem
+          .parent()
+          .find('.baron__track')
+          .remove();
+
+        scrollRoot.addClass(scrollRootClass);
+        $(scrollBarHTML).appendTo(scrollRoot);
+        scroller.addClass(scrollerClass);
+
+        // Fix .graph-legend-content max-height
+        // Couldn't find how to do it via CSS
+        const legendHeight = scrollRoot.height();
+        elem.css('max-height', legendHeight);
+
+        let scrollbarParams = {
+          root: scrollRoot[0],
+          scroller: scroller[0],
+          bar: '.baron__bar',
+          track: '.baron__track',
+          barOnCls: '_scrollbar',
+          scrollingCls: '_scrolling',
         };
 
         if (!legendScrollbar) {
-          legendScrollbar = new PerfectScrollbar(elem[0], scrollbarOptions);
+          legendScrollbar = baron(scrollbarParams);
         } else {
-          legendScrollbar.update();
+          destroyScrollbar();
+          legendScrollbar = baron(scrollbarParams);
         }
       }
 
       function destroyScrollbar() {
         if (legendScrollbar) {
-          legendScrollbar.destroy();
+          legendScrollbar.dispose();
           legendScrollbar = undefined;
         }
       }

+ 3 - 1
public/app/plugins/panel/graph/template.ts

@@ -3,7 +3,9 @@ var template = `
   <div class="graph-panel__chart" grafana-graph ng-dblclick="ctrl.zoomOut()">
   </div>
 
-  <div class="graph-legend" graph-legend></div>
+  <div class="graph-legend">
+    <div class="graph-legend-content" graph-legend></div>
+  </div>
 </div>
 `;
 

+ 4 - 1
public/sass/components/_panel_add_panel.scss

@@ -1,5 +1,9 @@
 .add-panel {
   height: 100%;
+
+  .baron__root {
+    height: calc(100% - 43px);
+  }
 }
 
 .add-panel__header {
@@ -39,7 +43,6 @@
   flex-direction: row;
   flex-wrap: wrap;
   overflow: auto;
-  height: calc(100% - 43px);
   align-content: flex-start;
   justify-content: space-around;
   position: relative;

+ 6 - 1
public/sass/components/_panel_graph.scss

@@ -53,7 +53,7 @@
   max-height: 30%;
   margin: 0;
   text-align: center;
-  padding-top: 6px;
+  // padding-top: 6px;
   position: relative;
 
   .popover-content {
@@ -61,6 +61,11 @@
   }
 }
 
+.graph-legend-content {
+  position: relative;
+  padding-top: 6px;
+}
+
 .graph-legend-icon {
   position: relative;
   padding-right: 4px;

+ 120 - 6
public/sass/components/_scrollbar.scss

@@ -9,6 +9,11 @@
   -ms-touch-action: auto;
 }
 
+// ._scrollbar {
+//   overflow-x: hidden !important;
+//   overflow-y: auto;
+// }
+
 /*
  * Scrollbar rail styles
  */
@@ -104,13 +109,19 @@
 // Srollbars
 //
 
-::-webkit-scrollbar {
-  width: 8px;
-  height: 8px;
-}
+// ::-webkit-scrollbar {
+//   width: 8px;
+//   height: 8px;
+// }
+
+// ::-webkit-scrollbar:hover {
+//   height: 8px;
+// }
 
-::-webkit-scrollbar:hover {
-  height: 8px;
+::-webkit-scrollbar {
+  // Hide system scrollbar (Mac OS X)
+  width: 0;
+  height: 0;
 }
 
 ::-webkit-scrollbar-button:start:decrement,
@@ -172,3 +183,106 @@
   border-top: 1px solid $scrollbarBorder;
   border-left: 1px solid $scrollbarBorder;
 }
+
+// Baron styles
+
+.baron {
+  display: inline-block;
+  overflow: hidden;
+}
+
+.baron__clipper {
+  position: relative;
+  overflow: hidden;
+  height: 100%;
+}
+
+.baron__scroller {
+  overflow-y: scroll;
+  -ms-overflow-style: none;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+  margin: 0;
+  border: 0;
+  padding: 0;
+  width: 100%;
+  height: 100%;
+  -webkit-overflow-scrolling: touch;
+  /* remove line to customize scrollbar in iOs */
+}
+
+.baron__scroller::-webkit-scrollbar {
+  width: 0;
+  height: 0;
+}
+
+.baron__track {
+  display: none;
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+}
+
+.baron._scrollbar .baron__track {
+  display: block;
+}
+
+.baron__free {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  right: 0;
+}
+
+.baron__bar {
+  display: none;
+  position: absolute;
+  right: 0;
+  z-index: 1;
+  // width: 10px;
+  background: #999;
+
+  // height: 15px;
+  width: 15px;
+  transition: background-color 0.2s linear, opacity 0.2s linear;
+  opacity: 0;
+}
+
+.baron._scrollbar .baron__bar {
+  display: block;
+
+  @include gradient-vertical($scrollbarBackground, $scrollbarBackground2);
+  border-radius: 6px;
+  width: 6px;
+  /* there must be 'right' for ps__thumb-y */
+  right: 0px;
+  /* please don't change 'position' */
+  position: absolute;
+
+  // background-color: transparent;
+  // opacity: 0.6;
+
+  &:hover,
+  &:focus {
+    // background-color: transparent;
+    opacity: 0.9;
+  }
+}
+
+.baron._scrolling > .baron__track .baron__bar {
+  opacity: 0.6;
+}
+
+.baron__control {
+  display: none;
+}
+
+.baron.panel-content--scrollable {
+  // Width needs to be set to prevent content width issues
+  width: 100%;
+
+  .baron__scroller {
+    padding-top: 1px;
+  }
+}

+ 7 - 0
public/sass/components/_search.scss

@@ -61,6 +61,8 @@
   display: flex;
   flex-direction: column;
   flex-grow: 1;
+
+  // overflow-y: scroll;
 }
 
 .search-dropdown__col_2 {
@@ -99,6 +101,11 @@
   }
 }
 
+.search-results-scroller {
+  position: relative;
+  height: 100%;
+}
+
 .search-results-container {
   height: 100%;
   display: block;

+ 2 - 1
public/views/index.template.html

@@ -16,7 +16,7 @@
   <link rel="icon" type="image/png" href="public/img/fav32.png">
   <link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28">
   <link rel="apple-touch-icon" href="public/img/fav32.png">
-  
+
 </head>
 
 <body ng-cloak class="theme-[[ .Theme ]]">
@@ -40,6 +40,7 @@
     </div>
 
     <div class="main-view">
+      <!-- Not sure do we really need grafana-scrollbar here? -->
       <div class="scroll-canvas" grafana-scrollbar>
         <div ng-view></div>