1<!DOCTYPE html>
2<!--
3Copyright (c) 2014 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/ui/base/ui.html">
9
10<polymer-element name="tr-ui-b-drag-handle">
11  <template>
12    <style>
13    :host {
14      -webkit-user-select: none;
15      box-sizing: border-box;
16      display: block;
17    }
18
19    :host(.horizontal-drag-handle) {
20      background-image: -webkit-gradient(linear,
21                                         0 0, 0 100%,
22                                         from(#E5E5E5),
23                                         to(#D1D1D1));
24      border-bottom: 1px solid #8e8e8e;
25      border-top: 1px solid white;
26      cursor: ns-resize;
27      flex: 0 0 auto;
28      height: 7px;
29      position: relative;
30      z-index: 10;
31    }
32
33    :host(.vertical-drag-handle) {
34      background-image: -webkit-gradient(linear,
35                                         0 0, 100% 0,
36                                         from(#E5E5E5),
37                                         to(#D1D1D1));
38      border-left: 1px solid white;
39      border-right: 1px solid #8e8e8e;
40      cursor: ew-resize;
41      flex: 0 0 auto;
42      position: relative;
43      width: 7px;
44      z-index: 10;
45    }
46    </style>
47  </template>
48  <script>
49  'use strict';
50
51  Polymer({
52    __proto__: HTMLDivElement.prototype,
53
54    created: function() {
55      this.lastMousePos_ = 0;
56      this.onMouseMove_ = this.onMouseMove_.bind(this);
57      this.onMouseUp_ = this.onMouseUp_.bind(this);
58      this.addEventListener('mousedown', this.onMouseDown_);
59      this.target_ = undefined;
60      this.horizontal = true;
61      this.observer_ = new WebKitMutationObserver(
62          this.didTargetMutate_.bind(this));
63      this.targetSizesByModeKey_ = {};
64    },
65
66    get modeKey_() {
67      return this.target_.className == '' ? '.' : this.target_.className;
68    },
69
70    get target() {
71      return this.target_;
72    },
73
74    set target(target) {
75      this.observer_.disconnect();
76      this.target_ = target;
77      if (!this.target_)
78        return;
79      this.observer_.observe(this.target_, {
80        attributes: true,
81        attributeFilter: ['class']
82      });
83    },
84
85    get horizontal() {
86      return this.horizontal_;
87    },
88
89    set horizontal(h) {
90      this.horizontal_ = h;
91      if (this.horizontal_)
92        this.className = 'horizontal-drag-handle';
93      else
94        this.className = 'vertical-drag-handle';
95    },
96
97    get vertical() {
98      return !this.horizontal_;
99    },
100
101    set vertical(v) {
102      this.horizontal = !v;
103    },
104
105    forceMutationObserverFlush_: function() {
106      var records = this.observer_.takeRecords();
107      if (records.length)
108        this.didTargetMutate_(records);
109    },
110
111    didTargetMutate_: function(e) {
112      var modeSize = this.targetSizesByModeKey_[this.modeKey_];
113      if (modeSize !== undefined) {
114        this.setTargetSize_(modeSize);
115        return;
116      }
117
118      // If we hadn't previously sized the target, then just remove any manual
119      // sizing that we applied.
120      this.target_.style[this.targetStyleKey_] = '';
121    },
122
123    get targetStyleKey_() {
124      return this.horizontal_ ? 'height' : 'width';
125    },
126
127    getTargetSize_: function() {
128      // If style is not set, start off with computed height.
129      var targetStyleKey = this.targetStyleKey_;
130      if (!this.target_.style[targetStyleKey]) {
131        this.target_.style[targetStyleKey] =
132            window.getComputedStyle(this.target_)[targetStyleKey];
133      }
134      var size = parseInt(this.target_.style[targetStyleKey]);
135      this.targetSizesByModeKey_[this.modeKey_] = size;
136      return size;
137    },
138
139    setTargetSize_: function(s) {
140      this.target_.style[this.targetStyleKey_] = s + 'px';
141      this.targetSizesByModeKey_[this.modeKey_] = s;
142    },
143
144    applyDelta_: function(delta) {
145      // Apply new size to the container.
146      var curSize = this.getTargetSize_();
147      var newSize;
148      if (this.target_ === this.nextElementSibling) {
149        newSize = curSize + delta;
150      } else {
151        newSize = curSize - delta;
152      }
153      this.setTargetSize_(newSize);
154    },
155
156    onMouseMove_: function(e) {
157      // Compute the difference in height position.
158      var curMousePos = this.horizontal_ ? e.clientY : e.clientX;
159      var delta = this.lastMousePos_ - curMousePos;
160
161      this.applyDelta_(delta);
162
163      this.lastMousePos_ = curMousePos;
164      e.preventDefault();
165      return true;
166    },
167
168    onMouseDown_: function(e) {
169      if (!this.target_)
170        return;
171      this.forceMutationObserverFlush_();
172      this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX;
173      document.addEventListener('mousemove', this.onMouseMove_);
174      document.addEventListener('mouseup', this.onMouseUp_);
175      e.preventDefault();
176      return true;
177    },
178
179    onMouseUp_: function(e) {
180      document.removeEventListener('mousemove', this.onMouseMove_);
181      document.removeEventListener('mouseup', this.onMouseUp_);
182      e.preventDefault();
183    }
184  });
185  </script>
186</polymer-element>
187