Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 #ifdef 0
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #endif
7 /**
8 * This singleton allows to transform the grid by repositioning a site's node
9 * in the DOM and by showing or hiding the node. It additionally provides
10 * convenience methods to work with a site's DOM node.
11 */
12 let gTransformation = {
13 /**
14 * Returns the width of the left and top border of a cell. We need to take it
15 * into account when measuring and comparing site and cell positions.
16 */
17 get _cellBorderWidths() {
18 let cstyle = window.getComputedStyle(gGrid.cells[0].node, null);
19 let widths = {
20 left: parseInt(cstyle.getPropertyValue("border-left-width")),
21 top: parseInt(cstyle.getPropertyValue("border-top-width"))
22 };
24 // Cache this value, overwrite the getter.
25 Object.defineProperty(this, "_cellBorderWidths",
26 {value: widths, enumerable: true});
28 return widths;
29 },
31 /**
32 * Gets a DOM node's position.
33 * @param aNode The DOM node.
34 * @return A Rect instance with the position.
35 */
36 getNodePosition: function Transformation_getNodePosition(aNode) {
37 let {left, top, width, height} = aNode.getBoundingClientRect();
38 return new Rect(left + scrollX, top + scrollY, width, height);
39 },
41 /**
42 * Fades a given node from zero to full opacity.
43 * @param aNode The node to fade.
44 * @param aCallback The callback to call when finished.
45 */
46 fadeNodeIn: function Transformation_fadeNodeIn(aNode, aCallback) {
47 this._setNodeOpacity(aNode, 1, function () {
48 // Clear the style property.
49 aNode.style.opacity = "";
51 if (aCallback)
52 aCallback();
53 });
54 },
56 /**
57 * Fades a given node from full to zero opacity.
58 * @param aNode The node to fade.
59 * @param aCallback The callback to call when finished.
60 */
61 fadeNodeOut: function Transformation_fadeNodeOut(aNode, aCallback) {
62 this._setNodeOpacity(aNode, 0, aCallback);
63 },
65 /**
66 * Fades a given site from zero to full opacity.
67 * @param aSite The site to fade.
68 * @param aCallback The callback to call when finished.
69 */
70 showSite: function Transformation_showSite(aSite, aCallback) {
71 this.fadeNodeIn(aSite.node, aCallback);
72 },
74 /**
75 * Fades a given site from full to zero opacity.
76 * @param aSite The site to fade.
77 * @param aCallback The callback to call when finished.
78 */
79 hideSite: function Transformation_hideSite(aSite, aCallback) {
80 this.fadeNodeOut(aSite.node, aCallback);
81 },
83 /**
84 * Allows to set a site's position.
85 * @param aSite The site to re-position.
86 * @param aPosition The desired position for the given site.
87 */
88 setSitePosition: function Transformation_setSitePosition(aSite, aPosition) {
89 let style = aSite.node.style;
90 let {top, left} = aPosition;
92 style.top = top + "px";
93 style.left = left + "px";
94 },
96 /**
97 * Freezes a site in its current position by positioning it absolute.
98 * @param aSite The site to freeze.
99 */
100 freezeSitePosition: function Transformation_freezeSitePosition(aSite) {
101 if (this._isFrozen(aSite))
102 return;
104 let style = aSite.node.style;
105 let comp = getComputedStyle(aSite.node, null);
106 style.width = comp.getPropertyValue("width")
107 style.height = comp.getPropertyValue("height");
109 aSite.node.setAttribute("frozen", "true");
110 this.setSitePosition(aSite, this.getNodePosition(aSite.node));
111 },
113 /**
114 * Unfreezes a site by removing its absolute positioning.
115 * @param aSite The site to unfreeze.
116 */
117 unfreezeSitePosition: function Transformation_unfreezeSitePosition(aSite) {
118 if (!this._isFrozen(aSite))
119 return;
121 let style = aSite.node.style;
122 style.left = style.top = style.width = style.height = "";
123 aSite.node.removeAttribute("frozen");
124 },
126 /**
127 * Slides the given site to the target node's position.
128 * @param aSite The site to move.
129 * @param aTarget The slide target.
130 * @param aOptions Set of options (see below).
131 * unfreeze - unfreeze the site after sliding
132 * callback - the callback to call when finished
133 */
134 slideSiteTo: function Transformation_slideSiteTo(aSite, aTarget, aOptions) {
135 let currentPosition = this.getNodePosition(aSite.node);
136 let targetPosition = this.getNodePosition(aTarget.node)
137 let callback = aOptions && aOptions.callback;
139 let self = this;
141 function finish() {
142 if (aOptions && aOptions.unfreeze)
143 self.unfreezeSitePosition(aSite);
145 if (callback)
146 callback();
147 }
149 // We need to take the width of a cell's border into account.
150 targetPosition.left += this._cellBorderWidths.left;
151 targetPosition.top += this._cellBorderWidths.top;
153 // Nothing to do here if the positions already match.
154 if (currentPosition.left == targetPosition.left &&
155 currentPosition.top == targetPosition.top) {
156 finish();
157 } else {
158 this.setSitePosition(aSite, targetPosition);
159 this._whenTransitionEnded(aSite.node, ["left", "top"], finish);
160 }
161 },
163 /**
164 * Rearranges a given array of sites and moves them to their new positions or
165 * fades in/out new/removed sites.
166 * @param aSites An array of sites to rearrange.
167 * @param aOptions Set of options (see below).
168 * unfreeze - unfreeze the site after rearranging
169 * callback - the callback to call when finished
170 */
171 rearrangeSites: function Transformation_rearrangeSites(aSites, aOptions) {
172 let batch = [];
173 let cells = gGrid.cells;
174 let callback = aOptions && aOptions.callback;
175 let unfreeze = aOptions && aOptions.unfreeze;
177 aSites.forEach(function (aSite, aIndex) {
178 // Do not re-arrange empty cells or the dragged site.
179 if (!aSite || aSite == gDrag.draggedSite)
180 return;
182 let deferred = Promise.defer();
183 batch.push(deferred.promise);
184 let cb = deferred.resolve;
186 if (!cells[aIndex])
187 // The site disappeared from the grid, hide it.
188 this.hideSite(aSite, cb);
189 else if (this._getNodeOpacity(aSite.node) != 1)
190 // The site disappeared before but is now back, show it.
191 this.showSite(aSite, cb);
192 else
193 // The site's position has changed, move it around.
194 this._moveSite(aSite, aIndex, {unfreeze: unfreeze, callback: cb});
195 }, this);
197 if (callback) {
198 Promise.all(batch).then(callback);
199 }
200 },
202 /**
203 * Listens for the 'transitionend' event on a given node and calls the given
204 * callback.
205 * @param aNode The node that is transitioned.
206 * @param aProperties The properties we'll wait to be transitioned.
207 * @param aCallback The callback to call when finished.
208 */
209 _whenTransitionEnded:
210 function Transformation_whenTransitionEnded(aNode, aProperties, aCallback) {
212 let props = new Set(aProperties);
213 aNode.addEventListener("transitionend", function onEnd(e) {
214 if (props.has(e.propertyName)) {
215 aNode.removeEventListener("transitionend", onEnd);
216 aCallback();
217 }
218 });
219 },
221 /**
222 * Gets a given node's opacity value.
223 * @param aNode The node to get the opacity value from.
224 * @return The node's opacity value.
225 */
226 _getNodeOpacity: function Transformation_getNodeOpacity(aNode) {
227 let cstyle = window.getComputedStyle(aNode, null);
228 return cstyle.getPropertyValue("opacity");
229 },
231 /**
232 * Sets a given node's opacity.
233 * @param aNode The node to set the opacity value for.
234 * @param aOpacity The opacity value to set.
235 * @param aCallback The callback to call when finished.
236 */
237 _setNodeOpacity:
238 function Transformation_setNodeOpacity(aNode, aOpacity, aCallback) {
240 if (this._getNodeOpacity(aNode) == aOpacity) {
241 if (aCallback)
242 aCallback();
243 } else {
244 if (aCallback) {
245 this._whenTransitionEnded(aNode, ["opacity"], aCallback);
246 }
248 aNode.style.opacity = aOpacity;
249 }
250 },
252 /**
253 * Moves a site to the cell with the given index.
254 * @param aSite The site to move.
255 * @param aIndex The target cell's index.
256 * @param aOptions Options that are directly passed to slideSiteTo().
257 */
258 _moveSite: function Transformation_moveSite(aSite, aIndex, aOptions) {
259 this.freezeSitePosition(aSite);
260 this.slideSiteTo(aSite, gGrid.cells[aIndex], aOptions);
261 },
263 /**
264 * Checks whether a site is currently frozen.
265 * @param aSite The site to check.
266 * @return Whether the given site is frozen.
267 */
268 _isFrozen: function Transformation_isFrozen(aSite) {
269 return aSite.node.hasAttribute("frozen");
270 }
271 };