browser/components/tabview/drag.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 // **********
michael@0 6 // Title: drag.js
michael@0 7
michael@0 8 // ----------
michael@0 9 // Variable: drag
michael@0 10 // The Drag that's currently in process.
michael@0 11 var drag = {
michael@0 12 info: null,
michael@0 13 zIndex: 100,
michael@0 14 lastMoveTime: 0
michael@0 15 };
michael@0 16
michael@0 17 //----------
michael@0 18 //Variable: resize
michael@0 19 //The resize (actually a Drag) that is currently in process
michael@0 20 var resize = {
michael@0 21 info: null,
michael@0 22 lastMoveTime: 0
michael@0 23 };
michael@0 24
michael@0 25 // ##########
michael@0 26 // Class: Drag (formerly DragInfo)
michael@0 27 // Helper class for dragging <Item>s
michael@0 28 //
michael@0 29 // ----------
michael@0 30 // Constructor: Drag
michael@0 31 // Called to create a Drag in response to an <Item> draggable "start" event.
michael@0 32 // Note that it is also used partially during <Item>'s resizable method as well.
michael@0 33 //
michael@0 34 // Parameters:
michael@0 35 // item - The <Item> being dragged
michael@0 36 // event - The DOM event that kicks off the drag
michael@0 37 function Drag(item, event) {
michael@0 38 Utils.assert(item && (item.isAnItem || item.isAFauxItem),
michael@0 39 'must be an item, or at least a faux item');
michael@0 40
michael@0 41 this.item = item;
michael@0 42 this.el = item.container;
michael@0 43 this.$el = iQ(this.el);
michael@0 44 this.parent = this.item.parent;
michael@0 45 this.startPosition = new Point(event.clientX, event.clientY);
michael@0 46 this.startTime = Date.now();
michael@0 47
michael@0 48 this.item.isDragging = true;
michael@0 49 this.item.setZ(999999);
michael@0 50
michael@0 51 this.safeWindowBounds = Items.getSafeWindowBounds();
michael@0 52
michael@0 53 Trenches.activateOthersTrenches(this.el);
michael@0 54 };
michael@0 55
michael@0 56 Drag.prototype = {
michael@0 57 // ----------
michael@0 58 // Function: toString
michael@0 59 // Prints [Drag (item)] for debug use
michael@0 60 toString: function Drag_toString() {
michael@0 61 return "[Drag (" + this.item + ")]";
michael@0 62 },
michael@0 63
michael@0 64 // ----------
michael@0 65 // Function: snapBounds
michael@0 66 // Adjusts the given bounds according to the currently active trenches. Used by <Drag.snap>
michael@0 67 //
michael@0 68 // Parameters:
michael@0 69 // bounds - (<Rect>) bounds
michael@0 70 // stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
michael@0 71 // and top right in RTL mode.
michael@0 72 // "topleft", "bottomleft", "topright", "bottomright"
michael@0 73 // assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
michael@0 74 // keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
michael@0 75 // proportionally or not
michael@0 76 // checkItemStatus - (boolean) make sure this is a valid item which should be snapped
michael@0 77 snapBounds: function Drag_snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, checkItemStatus) {
michael@0 78 if (!stationaryCorner)
michael@0 79 stationaryCorner = UI.rtl ? 'topright' : 'topleft';
michael@0 80 var update = false; // need to update
michael@0 81 var updateX = false;
michael@0 82 var updateY = false;
michael@0 83 var newRect;
michael@0 84 var snappedTrenches = {};
michael@0 85
michael@0 86 // OH SNAP!
michael@0 87
michael@0 88 // if we aren't holding down the meta key or have trenches disabled...
michael@0 89 if (!Keys.meta && !Trenches.disabled) {
michael@0 90 // snappable = true if we aren't a tab on top of something else, and
michael@0 91 // there's no active drop site...
michael@0 92 let snappable = !(this.item.isATabItem &&
michael@0 93 this.item.overlapsWithOtherItems()) &&
michael@0 94 !iQ(".acceptsDrop").length;
michael@0 95 if (!checkItemStatus || snappable) {
michael@0 96 newRect = Trenches.snap(bounds, stationaryCorner, assumeConstantSize,
michael@0 97 keepProportional);
michael@0 98 if (newRect) { // might be false if no changes were made
michael@0 99 update = true;
michael@0 100 snappedTrenches = newRect.snappedTrenches || {};
michael@0 101 bounds = newRect;
michael@0 102 }
michael@0 103 }
michael@0 104 }
michael@0 105
michael@0 106 // make sure the bounds are in the window.
michael@0 107 newRect = this.snapToEdge(bounds, stationaryCorner, assumeConstantSize,
michael@0 108 keepProportional);
michael@0 109 if (newRect) {
michael@0 110 update = true;
michael@0 111 bounds = newRect;
michael@0 112 Utils.extend(snappedTrenches, newRect.snappedTrenches);
michael@0 113 }
michael@0 114
michael@0 115 Trenches.hideGuides();
michael@0 116 for (var edge in snappedTrenches) {
michael@0 117 var trench = snappedTrenches[edge];
michael@0 118 if (typeof trench == 'object') {
michael@0 119 trench.showGuide = true;
michael@0 120 trench.show();
michael@0 121 }
michael@0 122 }
michael@0 123
michael@0 124 return update ? bounds : false;
michael@0 125 },
michael@0 126
michael@0 127 // ----------
michael@0 128 // Function: snap
michael@0 129 // Called when a drag or mousemove occurs. Set the bounds based on the mouse move first, then
michael@0 130 // call snap and it will adjust the item's bounds if appropriate. Also triggers the display of
michael@0 131 // trenches that it snapped to.
michael@0 132 //
michael@0 133 // Parameters:
michael@0 134 // stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
michael@0 135 // and top right in RTL mode.
michael@0 136 // "topleft", "bottomleft", "topright", "bottomright"
michael@0 137 // assumeConstantSize - (boolean) whether the bounds' dimensions are sacred or not.
michael@0 138 // keepProportional - (boolean) if assumeConstantSize is false, whether we should resize
michael@0 139 // proportionally or not
michael@0 140 snap: function Drag_snap(stationaryCorner, assumeConstantSize, keepProportional) {
michael@0 141 var bounds = this.item.getBounds();
michael@0 142 bounds = this.snapBounds(bounds, stationaryCorner, assumeConstantSize, keepProportional, true);
michael@0 143 if (bounds) {
michael@0 144 this.item.setBounds(bounds, true);
michael@0 145 return true;
michael@0 146 }
michael@0 147 return false;
michael@0 148 },
michael@0 149
michael@0 150 // --------
michael@0 151 // Function: snapToEdge
michael@0 152 // Returns a version of the bounds snapped to the edge if it is close enough. If not,
michael@0 153 // returns false. If <Keys.meta> is true, this function will simply enforce the
michael@0 154 // window edges.
michael@0 155 //
michael@0 156 // Parameters:
michael@0 157 // rect - (<Rect>) current bounds of the object
michael@0 158 // stationaryCorner - which corner is stationary? by default, the top left in LTR mode,
michael@0 159 // and top right in RTL mode.
michael@0 160 // "topleft", "bottomleft", "topright", "bottomright"
michael@0 161 // assumeConstantSize - (boolean) whether the rect's dimensions are sacred or not
michael@0 162 // keepProportional - (boolean) if we are allowed to change the rect's size, whether the
michael@0 163 // dimensions should scaled proportionally or not.
michael@0 164 snapToEdge: function Drag_snapToEdge(rect, stationaryCorner, assumeConstantSize, keepProportional) {
michael@0 165
michael@0 166 var swb = this.safeWindowBounds;
michael@0 167 var update = false;
michael@0 168 var updateX = false;
michael@0 169 var updateY = false;
michael@0 170 var snappedTrenches = {};
michael@0 171
michael@0 172 var snapRadius = (Keys.meta ? 0 : Trenches.defaultRadius);
michael@0 173 if (rect.left < swb.left + snapRadius ) {
michael@0 174 if (stationaryCorner.indexOf('right') > -1 && !assumeConstantSize)
michael@0 175 rect.width = rect.right - swb.left;
michael@0 176 rect.left = swb.left;
michael@0 177 update = true;
michael@0 178 updateX = true;
michael@0 179 snappedTrenches.left = 'edge';
michael@0 180 }
michael@0 181
michael@0 182 if (rect.right > swb.right - snapRadius) {
michael@0 183 if (updateX || !assumeConstantSize) {
michael@0 184 var newWidth = swb.right - rect.left;
michael@0 185 if (keepProportional)
michael@0 186 rect.height = rect.height * newWidth / rect.width;
michael@0 187 rect.width = newWidth;
michael@0 188 update = true;
michael@0 189 } else if (!updateX || !Trenches.preferLeft) {
michael@0 190 rect.left = swb.right - rect.width;
michael@0 191 update = true;
michael@0 192 }
michael@0 193 snappedTrenches.right = 'edge';
michael@0 194 delete snappedTrenches.left;
michael@0 195 }
michael@0 196 if (rect.top < swb.top + snapRadius) {
michael@0 197 if (stationaryCorner.indexOf('bottom') > -1 && !assumeConstantSize)
michael@0 198 rect.height = rect.bottom - swb.top;
michael@0 199 rect.top = swb.top;
michael@0 200 update = true;
michael@0 201 updateY = true;
michael@0 202 snappedTrenches.top = 'edge';
michael@0 203 }
michael@0 204 if (rect.bottom > swb.bottom - snapRadius) {
michael@0 205 if (updateY || !assumeConstantSize) {
michael@0 206 var newHeight = swb.bottom - rect.top;
michael@0 207 if (keepProportional)
michael@0 208 rect.width = rect.width * newHeight / rect.height;
michael@0 209 rect.height = newHeight;
michael@0 210 update = true;
michael@0 211 } else if (!updateY || !Trenches.preferTop) {
michael@0 212 rect.top = swb.bottom - rect.height;
michael@0 213 update = true;
michael@0 214 }
michael@0 215 snappedTrenches.top = 'edge';
michael@0 216 delete snappedTrenches.bottom;
michael@0 217 }
michael@0 218
michael@0 219 if (update) {
michael@0 220 rect.snappedTrenches = snappedTrenches;
michael@0 221 return rect;
michael@0 222 }
michael@0 223 return false;
michael@0 224 },
michael@0 225
michael@0 226 // ----------
michael@0 227 // Function: drag
michael@0 228 // Called in response to an <Item> draggable "drag" event.
michael@0 229 drag: function Drag_drag(event) {
michael@0 230 this.snap(UI.rtl ? 'topright' : 'topleft', true);
michael@0 231
michael@0 232 if (this.parent && this.parent.expanded) {
michael@0 233 var distance = this.startPosition.distance(new Point(event.clientX, event.clientY));
michael@0 234 if (distance > 100) {
michael@0 235 this.parent.remove(this.item);
michael@0 236 this.parent.collapse();
michael@0 237 }
michael@0 238 }
michael@0 239 },
michael@0 240
michael@0 241 // ----------
michael@0 242 // Function: stop
michael@0 243 // Called in response to an <Item> draggable "stop" event.
michael@0 244 //
michael@0 245 // Parameters:
michael@0 246 // immediately - bool for doing the pushAway immediately, without animation
michael@0 247 stop: function Drag_stop(immediately) {
michael@0 248 Trenches.hideGuides();
michael@0 249 this.item.isDragging = false;
michael@0 250
michael@0 251 if (this.parent && this.parent != this.item.parent)
michael@0 252 this.parent.closeIfEmpty();
michael@0 253
michael@0 254 if (this.parent && this.parent.expanded)
michael@0 255 this.parent.arrange();
michael@0 256
michael@0 257 if (this.item.parent)
michael@0 258 this.item.parent.arrange();
michael@0 259
michael@0 260 if (this.item.isAGroupItem) {
michael@0 261 this.item.setZ(drag.zIndex);
michael@0 262 drag.zIndex++;
michael@0 263
michael@0 264 this.item.pushAway(immediately);
michael@0 265 }
michael@0 266
michael@0 267 Trenches.disactivate();
michael@0 268 }
michael@0 269 };

mercurial