Home | History | Annotate | Download | only in base
      1 <!DOCTYPE html>
      2 <!--
      3 Copyright (c) 2014 The Chromium Authors. All rights reserved.
      4 Use of this source code is governed by a BSD-style license that can be
      5 found in the LICENSE file.
      6 -->
      7 
      8 <link rel="stylesheet" href="/ui/base/drag_handle.css">
      9 
     10 <link rel="import" href="/ui/base/ui.html">
     11 
     12 <script>
     13 'use strict';
     14 
     15 tr.exportTo('tr.ui.b', function() {
     16 
     17   /**
     18    * Detects when user clicks handle determines new height of container based
     19    * on user's vertical mouse move and resizes the target.
     20    * @constructor
     21    * @extends {HTMLDivElement}
     22    * You will need to set target to be the draggable element
     23    */
     24   var DragHandle = tr.ui.b.define('x-drag-handle');
     25 
     26   DragHandle.prototype = {
     27     __proto__: HTMLDivElement.prototype,
     28 
     29     decorate: function() {
     30       this.lastMousePos_ = 0;
     31       this.onMouseMove_ = this.onMouseMove_.bind(this);
     32       this.onMouseUp_ = this.onMouseUp_.bind(this);
     33       this.addEventListener('mousedown', this.onMouseDown_);
     34       this.target_ = undefined;
     35       this.horizontal = true;
     36       this.observer_ = new WebKitMutationObserver(
     37           this.didTargetMutate_.bind(this));
     38       this.targetSizesByModeKey_ = {};
     39     },
     40 
     41     get modeKey_() {
     42       return this.target_.className == '' ? '.' : this.target_.className;
     43     },
     44 
     45     get target() {
     46       return this.target_;
     47     },
     48 
     49     set target(target) {
     50       this.observer_.disconnect();
     51       this.target_ = target;
     52       if (!this.target_)
     53         return;
     54       this.observer_.observe(this.target_, {
     55         attributes: true,
     56         attributeFilter: ['class']
     57       });
     58     },
     59 
     60     get horizontal() {
     61       return this.horizontal_;
     62     },
     63 
     64     set horizontal(h) {
     65       this.horizontal_ = h;
     66       if (this.horizontal_)
     67         this.className = 'horizontal-drag-handle';
     68       else
     69         this.className = 'vertical-drag-handle';
     70     },
     71 
     72     get vertical() {
     73       return !this.horizontal_;
     74     },
     75 
     76     set vertical(v) {
     77       this.horizontal = !v;
     78     },
     79 
     80     forceMutationObserverFlush_: function() {
     81       var records = this.observer_.takeRecords();
     82       if (records.length)
     83         this.didTargetMutate_(records);
     84     },
     85 
     86     didTargetMutate_: function(e) {
     87       var modeSize = this.targetSizesByModeKey_[this.modeKey_];
     88       if (modeSize !== undefined) {
     89         this.setTargetSize_(modeSize);
     90         return;
     91       }
     92 
     93       // If we hadn't previously sized the target, then just remove any manual
     94       // sizing that we applied.
     95       this.target_.style[this.targetStyleKey_] = '';
     96     },
     97 
     98     get targetStyleKey_() {
     99       return this.horizontal_ ? 'height' : 'width';
    100     },
    101 
    102     getTargetSize_: function() {
    103       // If style is not set, start off with computed height.
    104       var targetStyleKey = this.targetStyleKey_;
    105       if (!this.target_.style[targetStyleKey]) {
    106         this.target_.style[targetStyleKey] =
    107             window.getComputedStyle(this.target_)[targetStyleKey];
    108       }
    109       var size = parseInt(this.target_.style[targetStyleKey]);
    110       this.targetSizesByModeKey_[this.modeKey_] = size;
    111       return size;
    112     },
    113 
    114     setTargetSize_: function(s) {
    115       this.target_.style[this.targetStyleKey_] = s + 'px';
    116       this.targetSizesByModeKey_[this.modeKey_] = s;
    117     },
    118 
    119     applyDelta_: function(delta) {
    120       // Apply new size to the container.
    121       var curSize = this.getTargetSize_();
    122       var newSize;
    123       if (this.target_ === this.nextElementSibling) {
    124         newSize = curSize + delta;
    125       } else {
    126         newSize = curSize - delta;
    127       }
    128       this.setTargetSize_(newSize);
    129     },
    130 
    131     onMouseMove_: function(e) {
    132       // Compute the difference in height position.
    133       var curMousePos = this.horizontal_ ? e.clientY : e.clientX;
    134       var delta = this.lastMousePos_ - curMousePos;
    135 
    136       this.applyDelta_(delta);
    137 
    138       this.lastMousePos_ = curMousePos;
    139       e.preventDefault();
    140       return true;
    141     },
    142 
    143     onMouseDown_: function(e) {
    144       if (!this.target_)
    145         return;
    146       this.forceMutationObserverFlush_();
    147       this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX;
    148       document.addEventListener('mousemove', this.onMouseMove_);
    149       document.addEventListener('mouseup', this.onMouseUp_);
    150       e.preventDefault();
    151       return true;
    152     },
    153 
    154     onMouseUp_: function(e) {
    155       document.removeEventListener('mousemove', this.onMouseMove_);
    156       document.removeEventListener('mouseup', this.onMouseUp_);
    157       e.preventDefault();
    158     }
    159   };
    160 
    161   return {
    162     DragHandle: DragHandle
    163   };
    164 });
    165 </script>
    166