|
1 /** |
|
2 * Movable.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 */ |
|
10 |
|
11 /** |
|
12 * Movable mixin. Makes controls movable absolute and relative to other elements. |
|
13 * |
|
14 * @mixin tinymce.ui.Movable |
|
15 */ |
|
16 define("tinymce/ui/Movable", [ |
|
17 "tinymce/ui/DomUtils" |
|
18 ], function(DomUtils) { |
|
19 "use strict"; |
|
20 |
|
21 function calculateRelativePosition(ctrl, targetElm, rel) { |
|
22 var ctrlElm, pos, x, y, selfW, selfH, targetW, targetH, viewport, size; |
|
23 |
|
24 viewport = DomUtils.getViewPort(); |
|
25 |
|
26 // Get pos of target |
|
27 pos = DomUtils.getPos(targetElm); |
|
28 x = pos.x; |
|
29 y = pos.y; |
|
30 |
|
31 if (ctrl._fixed && DomUtils.getRuntimeStyle(document.body, 'position') == 'static') { |
|
32 x -= viewport.x; |
|
33 y -= viewport.y; |
|
34 } |
|
35 |
|
36 // Get size of self |
|
37 ctrlElm = ctrl.getEl(); |
|
38 size = DomUtils.getSize(ctrlElm); |
|
39 selfW = size.width; |
|
40 selfH = size.height; |
|
41 |
|
42 // Get size of target |
|
43 size = DomUtils.getSize(targetElm); |
|
44 targetW = size.width; |
|
45 targetH = size.height; |
|
46 |
|
47 // Parse align string |
|
48 rel = (rel || '').split(''); |
|
49 |
|
50 // Target corners |
|
51 if (rel[0] === 'b') { |
|
52 y += targetH; |
|
53 } |
|
54 |
|
55 if (rel[1] === 'r') { |
|
56 x += targetW; |
|
57 } |
|
58 |
|
59 if (rel[0] === 'c') { |
|
60 y += Math.round(targetH / 2); |
|
61 } |
|
62 |
|
63 if (rel[1] === 'c') { |
|
64 x += Math.round(targetW / 2); |
|
65 } |
|
66 |
|
67 // Self corners |
|
68 if (rel[3] === 'b') { |
|
69 y -= selfH; |
|
70 } |
|
71 |
|
72 if (rel[4] === 'r') { |
|
73 x -= selfW; |
|
74 } |
|
75 |
|
76 if (rel[3] === 'c') { |
|
77 y -= Math.round(selfH / 2); |
|
78 } |
|
79 |
|
80 if (rel[4] === 'c') { |
|
81 x -= Math.round(selfW / 2); |
|
82 } |
|
83 |
|
84 return { |
|
85 x: x, |
|
86 y: y, |
|
87 w: selfW, |
|
88 h: selfH |
|
89 }; |
|
90 } |
|
91 |
|
92 return { |
|
93 /** |
|
94 * Tests various positions to get the most suitable one. |
|
95 * |
|
96 * @method testMoveRel |
|
97 * @param {DOMElement} elm Element to position against. |
|
98 * @param {Array} rels Array with relative positions. |
|
99 * @return {String} Best suitable relative position. |
|
100 */ |
|
101 testMoveRel: function(elm, rels) { |
|
102 var viewPortRect = DomUtils.getViewPort(); |
|
103 |
|
104 for (var i = 0; i < rels.length; i++) { |
|
105 var pos = calculateRelativePosition(this, elm, rels[i]); |
|
106 |
|
107 if (this._fixed) { |
|
108 if (pos.x > 0 && pos.x + pos.w < viewPortRect.w && pos.y > 0 && pos.y + pos.h < viewPortRect.h) { |
|
109 return rels[i]; |
|
110 } |
|
111 } else { |
|
112 if (pos.x > viewPortRect.x && pos.x + pos.w < viewPortRect.w + viewPortRect.x && |
|
113 pos.y > viewPortRect.y && pos.y + pos.h < viewPortRect.h + viewPortRect.y) { |
|
114 return rels[i]; |
|
115 } |
|
116 } |
|
117 } |
|
118 |
|
119 return rels[0]; |
|
120 }, |
|
121 |
|
122 /** |
|
123 * Move relative to the specified element. |
|
124 * |
|
125 * @method moveRel |
|
126 * @param {Element} elm Element to move relative to. |
|
127 * @param {String} rel Relative mode. For example: br-tl. |
|
128 * @return {tinymce.ui.Control} Current control instance. |
|
129 */ |
|
130 moveRel: function(elm, rel) { |
|
131 if (typeof rel != 'string') { |
|
132 rel = this.testMoveRel(elm, rel); |
|
133 } |
|
134 |
|
135 var pos = calculateRelativePosition(this, elm, rel); |
|
136 return this.moveTo(pos.x, pos.y); |
|
137 }, |
|
138 |
|
139 /** |
|
140 * Move by a relative x, y values. |
|
141 * |
|
142 * @method moveBy |
|
143 * @param {Number} dx Relative x position. |
|
144 * @param {Number} dy Relative y position. |
|
145 * @return {tinymce.ui.Control} Current control instance. |
|
146 */ |
|
147 moveBy: function(dx, dy) { |
|
148 var self = this, rect = self.layoutRect(); |
|
149 |
|
150 self.moveTo(rect.x + dx, rect.y + dy); |
|
151 |
|
152 return self; |
|
153 }, |
|
154 |
|
155 /** |
|
156 * Move to absolute position. |
|
157 * |
|
158 * @method moveTo |
|
159 * @param {Number} x Absolute x position. |
|
160 * @param {Number} y Absolute y position. |
|
161 * @return {tinymce.ui.Control} Current control instance. |
|
162 */ |
|
163 moveTo: function(x, y) { |
|
164 var self = this; |
|
165 |
|
166 // TODO: Move this to some global class |
|
167 function contrain(value, max, size) { |
|
168 if (value < 0) { |
|
169 return 0; |
|
170 } |
|
171 |
|
172 if (value + size > max) { |
|
173 value = max - size; |
|
174 return value < 0 ? 0 : value; |
|
175 } |
|
176 |
|
177 return value; |
|
178 } |
|
179 |
|
180 if (self.settings.constrainToViewport) { |
|
181 var viewPortRect = DomUtils.getViewPort(window); |
|
182 var layoutRect = self.layoutRect(); |
|
183 |
|
184 x = contrain(x, viewPortRect.w + viewPortRect.x, layoutRect.w); |
|
185 y = contrain(y, viewPortRect.h + viewPortRect.y, layoutRect.h); |
|
186 } |
|
187 |
|
188 if (self._rendered) { |
|
189 self.layoutRect({x: x, y: y}).repaint(); |
|
190 } else { |
|
191 self.settings.x = x; |
|
192 self.settings.y = y; |
|
193 } |
|
194 |
|
195 self.fire('move', {x: x, y: y}); |
|
196 |
|
197 return self; |
|
198 } |
|
199 }; |
|
200 }); |