 aba209e999
			
		
	
	aba209e999
	
	
	
		
			
			Summary: Ref T12733. In the longer run I'd like to just push this out from the edge, but that currently gets us into trouble since we start bumping into content. On my system, the trackpad scrollbar also expands in size when moused over, so the minimum number of pixels we need to push it out is approximatley 15px. This hits body content and the persistent chat. For now, just disable this element on trackpad systems. Test Plan: Disconnected all USB peripherals, quit and relaunched Safari, saw no objective list. Reconnected mouse, relaunched Safari, saw objective list. Reviewers: chad Reviewed By: chad Maniphest Tasks: T12733 Differential Revision: https://secure.phabricator.com/D17974
		
			
				
	
	
		
			146 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @provides phabricator-scroll-objective-list
 | |
|  * @requires javelin-dom
 | |
|  *           javelin-util
 | |
|  *           javelin-stratcom
 | |
|  *           javelin-install
 | |
|  *           javelin-workflow
 | |
|  *           javelin-scrollbar
 | |
|  *           phabricator-scroll-objective
 | |
|  * @javelin
 | |
|  */
 | |
| 
 | |
| 
 | |
| JX.install('ScrollObjectiveList', {
 | |
| 
 | |
|   construct : function() {
 | |
|     this._objectives = [];
 | |
| 
 | |
|     var onresize = JX.bind(this, this._dirty);
 | |
|     JX.Stratcom.listen('resize', null, onresize);
 | |
|   },
 | |
| 
 | |
|   members: {
 | |
|     _objectives: null,
 | |
|     _visible: false,
 | |
|     _trigger: null,
 | |
| 
 | |
|     newObjective: function() {
 | |
|       var objective = new JX.ScrollObjective()
 | |
|         .setObjectiveList(this);
 | |
| 
 | |
|       this._objectives.push(objective);
 | |
|       this._getNode().appendChild(objective.getNode());
 | |
| 
 | |
|       this._dirty();
 | |
| 
 | |
|       return objective;
 | |
|     },
 | |
| 
 | |
|     show: function() {
 | |
|       this._visible = true;
 | |
|       this._dirty();
 | |
|       return this;
 | |
|     },
 | |
| 
 | |
|     hide: function() {
 | |
|       this._visible = false;
 | |
|       this._dirty();
 | |
|       return this;
 | |
|     },
 | |
| 
 | |
|     _getNode: function() {
 | |
|       if (!this._node) {
 | |
|         var node = new JX.$N('div', {className: 'scroll-objective-list'});
 | |
|         this._node = node;
 | |
|       }
 | |
|       return this._node;
 | |
|     },
 | |
| 
 | |
|     _dirty: function() {
 | |
|       if (this._trigger !== null) {
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       this._trigger = setTimeout(JX.bind(this, this._redraw), 0);
 | |
|     },
 | |
| 
 | |
|     _redraw: function() {
 | |
|       this._trigger = null;
 | |
| 
 | |
|       var node = this._getNode();
 | |
| 
 | |
|       var is_visible =
 | |
|         (this._visible) &&
 | |
|         (JX.Device.getDevice() == 'desktop') &&
 | |
|         (this._objectives.length);
 | |
| 
 | |
|       if (!is_visible) {
 | |
|         JX.DOM.remove(node);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       document.body.appendChild(node);
 | |
| 
 | |
|       // If we're on OSX without a mouse or some other system with zero-width
 | |
|       // trackpad-style scrollbars, adjust the display appropriately.
 | |
|       var aesthetic = (JX.Scrollbar.getScrollbarControlWidth() === 0);
 | |
|       JX.DOM.alterClass(node, 'has-aesthetic-scrollbar', aesthetic);
 | |
| 
 | |
|       var d = JX.Vector.getDocument();
 | |
| 
 | |
|       var list_dimensions = JX.Vector.getDim(node);
 | |
|       var icon_height = 16;
 | |
|       var list_y = (list_dimensions.y - icon_height);
 | |
| 
 | |
|       var ii;
 | |
|       var offset;
 | |
| 
 | |
|       // First, build a list of all the items we're going to show.
 | |
|       var items = [];
 | |
|       for (ii = 0; ii < this._objectives.length; ii++) {
 | |
|         var objective = this._objectives[ii];
 | |
|         var objective_node = objective.getNode();
 | |
| 
 | |
|         var anchor = objective.getAnchor();
 | |
|         if (!anchor || !objective.isVisible()) {
 | |
|           JX.DOM.remove(objective_node);
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         offset = (JX.$V(anchor).y / d.y) * (list_y);
 | |
| 
 | |
|         items.push({
 | |
|           offset: offset,
 | |
|           node: objective_node
 | |
|         });
 | |
|       }
 | |
| 
 | |
|       // Now, sort it from top to bottom.
 | |
|       items.sort(function(u, v) {
 | |
|         return u.offset - v.offset;
 | |
|       });
 | |
| 
 | |
|       // Lay out the items in the objective list, leaving a minimum amount
 | |
|       // of space between them so they do not overlap.
 | |
|       var min = null;
 | |
|       for (ii = 0; ii < items.length; ii++) {
 | |
|         var item = items[ii];
 | |
| 
 | |
|         offset = item.offset;
 | |
| 
 | |
|         if (min !== null) {
 | |
|           offset = Math.max(offset, min);
 | |
|         }
 | |
|         min = offset + 15;
 | |
| 
 | |
|         item.node.style.top = offset + 'px';
 | |
|         node.appendChild(item.node);
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
| });
 |