summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/widgets/Resizable.js
Unidiff
Diffstat (limited to 'frontend/beta/js/YUI-extensions/widgets/Resizable.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Resizable.js586
1 files changed, 586 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/widgets/Resizable.js b/frontend/beta/js/YUI-extensions/widgets/Resizable.js
new file mode 100644
index 0000000..6944683
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Resizable.js
@@ -0,0 +1,586 @@
1/**
2 * @class YAHOO.ext.Resizable
3 * @extends YAHOO.ext.util.Observable
4 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
5 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
6 * the textarea in a div and set "resizeChild" to true (or the id of the textarea), <b>or</b> set wrap:true in your config and
7 * the element will be wrapped for you automatically.</p><br/>
8 * Here's a Resizable with every possible config option and it's default value:
9<pre><code>
10var resizer = new YAHOO.ext.Resizable('element-id', {
11 resizeChild : false,
12 adjustments : [0, 0],
13 minWidth : 5,
14 minHeight : 5,
15 maxWidth : 10000,
16 maxHeight : 10000,
17 enabled : true,
18 wrap: false, // true to wrap the element
19 width: null, // initial size
20 height: null, // initial size
21 animate : false,
22 duration : .35,
23 dynamic : false,
24 handles : false,
25 multiDirectional : false,
26 disableTrackOver : false,
27 easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
28 widthIncrement : 0,
29 heightIncrement : 0,
30 pinned : false,
31 width : null,
32 height : null,
33 preserveRatio : false,
34 transparent: false,
35 minX: 0,
36 minY: 0,
37 draggable: false
38});
39resizer.on('resize', myHandler);
40</code></pre>
41* <p>
42 * To hide a particular handle, set it's display to none in CSS, or through script:<br>
43 * resizer.east.setDisplayed(false);
44 * </p>
45 * @constructor
46 * Create a new resizable component
47 * @param {String/HTMLElement/YAHOO.ext.Element} el The id or element to resize
48 * @param {Object} config configuration options
49 */
50YAHOO.ext.Resizable = function(el, config){
51 this.el = getEl(el);
52
53 if(config && config.wrap){
54 config.resizeChild = this.el;
55 this.el = this.el.wrap(typeof config.wrap == 'object' ? config.wrap : null);
56 this.el.id = this.el.dom.id = config.resizeChild.id + '-rzwrap';
57 this.el.setStyle('overflow', 'hidden');
58 this.el.setPositioning(config.resizeChild.getPositioning());
59 config.resizeChild.clearPositioning();
60 if(!config.width || !config.height){
61 var csize = config.resizeChild.getSize();
62 //csize.width -= config.adjustments[0];
63 //csize.height -= config.adjustments[1];
64 this.el.setSize(csize.width, csize.height);
65 }
66 if(config.pinned && !config.adjustments){
67 config.adjustments = 'auto';
68 }
69 }
70
71 this.proxy = this.el.createProxy({tag: 'div', cls: 'yresizable-proxy', id: this.el.id + '-rzproxy'})
72 this.proxy.unselectable();
73
74 // the overlay traps mouse events while dragging and fixes iframe issue
75 this.overlay = this.el.createProxy({tag: 'div', cls: 'yresizable-overlay', html: '&#160;'});
76 this.overlay.unselectable();
77 this.overlay.enableDisplayMode('block');
78 this.overlay.mon('mousemove', this.onMouseMove, this, true);
79 this.overlay.mon('mouseup', this.onMouseUp, this, true);
80
81 YAHOO.ext.util.Config.apply(this, config, {
82 /** True to resizeSize the first child or id/element to resize @type YAHOO.ext.Element */
83 resizeChild : false,
84 /** String "auto" or an array [width, height] with values to be <b>added</b> to the resize operation's new size. @type Array/String */
85 adjustments : [0, 0],
86 /** The minimum width for the element @type Number */
87 minWidth : 5,
88 /** The minimum height for the element @type Number */
89 minHeight : 5,
90 /** The maximum width for the element @type Number */
91 maxWidth : 10000,
92 /** The maximum height for the element @type Number */
93 maxHeight : 10000,
94 /** false to disable resizing @type Boolean */
95 enabled : true,
96 /** True to animate the resize (not compatible with dynamic sizing) @type Boolean */
97 animate : false,
98 /** Animation duration @type Float */
99 duration : .35,
100 /** True to resize the element while dragging instead of using a proxy @type Boolean */
101 dynamic : false,
102 // these 3 are only available at config time
103 /** String consisting of the resize handles to display. Valid handles are
104 * n (north), s (south) e (east), w (west), ne (northeast), nw (northwest), se (southeast), sw (southwest)
105 * and all (which applies them all). If this is blank it defaults to "e,s,se". Handles can be delimited using
106 * a space, comma or semi-colon. This is only applied at config time. @type String*/
107 handles : false,
108 multiDirectional : false,
109 /** true to disable mouse tracking. This is only applied at config time. @type Boolean*/
110 disableTrackOver : false,
111 /** Animation easing @type YAHOO.util.Easing */
112 easing : YAHOO.util.Easing ? YAHOO.util.Easing.easeOutStrong : null,
113 /** The increment to snap the width resize in pixels (dynamic must be true) @type Number */
114 widthIncrement : 0,
115 /** The increment to snap the height resize in pixels (dynamic must be true) @type Number */
116 heightIncrement : 0,
117 /** true to pin the resize handles. This is only applied at config time. @type Boolean*/
118 pinned : false,
119 /** The initial width for the element @type Number */
120 width : null,
121 /** The initial height for the element @type Number */
122 height : null,
123 /** true to preserve the initial size ratio. @type Boolean*/
124 preserveRatio : false,
125 /** true for transparent handles. This is only applied at config time. @type Boolean*/
126 transparent: false,
127 /** The minimum allowed page X for the element (only used for west resizing, defaults to 0) @type Number */
128 minX: 0,
129 /** The minimum allowed page Y for the element (only used for north resizing, defaults to 0) @type Number */
130 minY: 0,
131 /** convenience to initialize drag drop. @type Boolean*/
132 draggable: false
133 });
134
135 if(this.pinned){
136 this.disableTrackOver = true;
137 this.el.addClass('yresizable-pinned');
138 }
139 // if the element isn't positioned, make it relative
140 var position = this.el.getStyle('position');
141 if(position != 'absolute' && position != 'fixed'){
142 this.el.setStyle('position', 'relative');
143 }
144 if(!this.handles){ // no handles passed, must be legacy style
145 this.handles = 's,e,se';
146 if(this.multiDirectional){
147 this.handles += ',n,w';
148 }
149 }
150 if(this.handles == 'all'){
151 this.handles = 'n s e w ne nw se sw';
152 }
153 var hs = this.handles.split(/\s*?[,;]\s*?| /);
154 var ps = YAHOO.ext.Resizable.positions;
155 for(var i = 0, len = hs.length; i < len; i++){
156 if(hs[i] && ps[hs[i]]){
157 var pos = ps[hs[i]];
158 this[pos] = new YAHOO.ext.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
159 }
160 }
161 // legacy
162 this.corner = this.southeast;
163
164 this.activeHandle = null;
165
166 if(this.resizeChild){
167 if(typeof this.resizeChild == 'boolean'){
168 this.resizeChild = YAHOO.ext.Element.get(this.el.dom.firstChild, true);
169 }else{
170 this.resizeChild = YAHOO.ext.Element.get(this.resizeChild, true);
171 }
172 }
173
174 if(this.adjustments == 'auto'){
175 var rc = this.resizeChild;
176 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
177 if(rc && (hw || hn)){
178 rc.setRelativePositioned();
179 rc.setLeft(hw ? hw.el.getWidth() : 0);
180 rc.setTop(hn ? hn.el.getHeight() : 0);
181 }
182 this.adjustments = [
183 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
184 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
185 ];
186 }
187
188 if(this.draggable){
189 this.dd = this.dynamic ?
190 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
191 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
192 }
193
194 // public events
195 this.events = {
196 /**
197 * @event beforeresize
198 * Fired before resize is allowed. Set enabled to false to cancel resize.
199 * @param {YAHOO.ext.Resizable} this
200 * @param {YAHOO.ext.EventObject} e The mousedown event
201 */
202 'beforeresize' : new YAHOO.util.CustomEvent(),
203 /**
204 * @event resize
205 * Fired after a resize.
206 * @param {YAHOO.ext.Resizable} this
207 * @param {Number} width The new width
208 * @param {Number} height The new height
209 * @param {YAHOO.ext.EventObject} e The mouseup event
210 */
211 'resize' : new YAHOO.util.CustomEvent()
212 };
213
214 if(this.width !== null && this.height !== null){
215 this.resizeTo(this.width, this.height);
216 }else{
217 this.updateChildSize();
218 }
219};
220
221YAHOO.extendX(YAHOO.ext.Resizable, YAHOO.ext.util.Observable, {
222 /**
223 * Perform a manual resize
224 * @param {Number} width
225 * @param {Number} height
226 */
227 resizeTo : function(width, height){
228 this.el.setSize(width, height);
229 this.updateChildSize();
230 this.fireEvent('resize', this, width, height, null);
231 },
232
233 startSizing : function(e){
234 this.fireEvent('beforeresize', this, e);
235 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
236 this.resizing = true;
237 this.startBox = this.el.getBox();
238 this.startPoint = e.getXY();
239 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
240 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
241 this.proxy.setBox(this.startBox);
242
243 this.overlay.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
244 this.overlay.show();
245
246 if(!this.dynamic){
247 this.proxy.show();
248 }
249 }
250 },
251
252 onMouseDown : function(handle, e){
253 if(this.enabled){
254 e.stopEvent();
255 this.activeHandle = handle;
256 this.overlay.setStyle('cursor', handle.el.getStyle('cursor'));
257 this.startSizing(e);
258 }
259 },
260
261 onMouseUp : function(e){
262 var size = this.resizeElement();
263 this.resizing = false;
264 this.handleOut();
265 this.overlay.hide();
266 this.fireEvent('resize', this, size.width, size.height, e);
267 },
268
269 updateChildSize : function(){
270 if(this.resizeChild){
271 var el = this.el;
272 var child = this.resizeChild;
273 var adj = this.adjustments;
274 if(el.dom.offsetWidth){
275 var b = el.getSize(true);
276 child.setSize(b.width+adj[0], b.height+adj[1]);
277 }
278 // Second call here for IE
279 // The first call enables instant resizing and
280 // the second call corrects scroll bars if they
281 // exist
282 if(YAHOO.ext.util.Browser.isIE){
283 setTimeout(function(){
284 if(el.dom.offsetWidth){
285 var b = el.getSize(true);
286 child.setSize(b.width+adj[0], b.height+adj[1]);
287 }
288 }, 10);
289 }
290 }
291 },
292
293 snap : function(value, inc, min){
294 if(!inc || !value) return value;
295 var newValue = value;
296 var m = value % inc;
297 if(m > 0){
298 if(m > (inc/2)){
299 newValue = value + (inc-m);
300 }else{
301 newValue = value - m;
302 }
303 }
304 return Math.max(min, newValue);
305 },
306
307 resizeElement : function(){
308 var box = this.proxy.getBox();
309 //box.width = this.snap(box.width, this.widthIncrement);
310 //box.height = this.snap(box.height, this.heightIncrement);
311 //if(this.multiDirectional){
312 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
313 //}else{
314 // this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
315 //}
316 this.updateChildSize();
317 this.proxy.hide();
318 return box;
319 },
320
321 constrain : function(v, diff, m, mx){
322 if(v - diff < m){
323 diff = v - m;
324 }else if(v - diff > mx){
325 diff = mx - v;
326 }
327 return diff;
328 },
329
330 onMouseMove : function(e){
331 if(this.enabled){
332 try{// try catch so if something goes wrong the user doesn't get hung
333
334 //var curXY = this.startPoint;
335 var curSize = this.curSize || this.startBox;
336 var x = this.startBox.x, y = this.startBox.y;
337 var ox = x, oy = y;
338 var w = curSize.width, h = curSize.height;
339 var ow = w, oh = h;
340 var mw = this.minWidth, mh = this.minHeight;
341 var mxw = this.maxWidth, mxh = this.maxHeight;
342 var wi = this.widthIncrement;
343 var hi = this.heightIncrement;
344
345 var eventXY = e.getXY();
346 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
347 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
348
349 var pos = this.activeHandle.position;
350
351 switch(pos){
352 case 'east':
353 w += diffX;
354 w = Math.min(Math.max(mw, w), mxw);
355 break;
356 case 'south':
357 h += diffY;
358 h = Math.min(Math.max(mh, h), mxh);
359 break;
360 case 'southeast':
361 w += diffX;
362 h += diffY;
363 w = Math.min(Math.max(mw, w), mxw);
364 h = Math.min(Math.max(mh, h), mxh);
365 break;
366 case 'north':
367 diffY = this.constrain(h, diffY, mh, mxh);
368 y += diffY;
369 h -= diffY;
370 break;
371 case 'west':
372 diffX = this.constrain(w, diffX, mw, mxw);
373 x += diffX;
374 w -= diffX;
375 break;
376 case 'northeast':
377 w += diffX;
378 w = Math.min(Math.max(mw, w), mxw);
379 diffY = this.constrain(h, diffY, mh, mxh);
380 y += diffY;
381 h -= diffY;
382 break;
383 case 'northwest':
384 diffX = this.constrain(w, diffX, mw, mxw);
385 diffY = this.constrain(h, diffY, mh, mxh);
386 y += diffY;
387 h -= diffY;
388 x += diffX;
389 w -= diffX;
390 break;
391 case 'southwest':
392 diffX = this.constrain(w, diffX, mw, mxw);
393 h += diffY;
394 h = Math.min(Math.max(mh, h), mxh);
395 x += diffX;
396 w -= diffX;
397 break;
398 }
399
400 var sw = this.snap(w, wi, mw);
401 var sh = this.snap(h, hi, mh);
402 if(sw != w || sh != h){
403 switch(pos){
404 case 'northeast':
405 y -= sh - h;
406 break;
407 case 'north':
408 y -= sh - h;
409 break;
410 case 'southwest':
411 x -= sw - w;
412 break;
413 case 'west':
414 x -= sw - w;
415 break;
416 case 'northwest':
417 x -= sw - w;
418 y -= sh - h;
419 break;
420 }
421 w = sw;
422 h = sh;
423 }
424
425 if(this.preserveRatio){
426 switch(pos){
427 case 'southeast':
428 case 'east':
429 h = oh * (w/ow);
430 h = Math.min(Math.max(mh, h), mxh);
431 w = ow * (h/oh);
432 break;
433 case 'south':
434 w = ow * (h/oh);
435 w = Math.min(Math.max(mw, w), mxw);
436 h = oh * (w/ow);
437 break;
438 case 'northeast':
439 w = ow * (h/oh);
440 w = Math.min(Math.max(mw, w), mxw);
441 h = oh * (w/ow);
442 break;
443 case 'north':
444 var tw = w;
445 w = ow * (h/oh);
446 w = Math.min(Math.max(mw, w), mxw);
447 h = oh * (w/ow);
448 x += (tw - w) / 2;
449 break;
450 case 'southwest':
451 h = oh * (w/ow);
452 h = Math.min(Math.max(mh, h), mxh);
453 var tw = w;
454 w = ow * (h/oh);
455 x += tw - w;
456 break;
457 case 'west':
458 var th = h;
459 h = oh * (w/ow);
460 h = Math.min(Math.max(mh, h), mxh);
461 y += (th - h) / 2;
462 var tw = w;
463 w = ow * (h/oh);
464 x += tw - w;
465 break;
466 case 'northwest':
467 var tw = w;
468 var th = h;
469 h = oh * (w/ow);
470 h = Math.min(Math.max(mh, h), mxh);
471 w = ow * (h/oh);
472 y += th - h;
473 x += tw - w;
474 break;
475
476 }
477 }
478 this.proxy.setBounds(x, y, w, h);
479 if(this.dynamic){
480 this.resizeElement();
481 }
482 }catch(e){}
483 }
484 },
485
486 handleOver : function(){
487 if(this.enabled){
488 this.el.addClass('yresizable-over');
489 }
490 },
491
492 handleOut : function(){
493 if(!this.resizing){
494 this.el.removeClass('yresizable-over');
495 }
496 },
497
498 /**
499 * Returns the element this component is bound to.
500 * @return {YAHOO.ext.Element}
501 */
502 getEl : function(){
503 return this.el;
504 },
505
506 /**
507 * Returns the resizeChild element (or null).
508 * @return {YAHOO.ext.Element}
509 */
510 getResizeChild : function(){
511 return this.resizeChild;
512 },
513
514 /**
515 * Destroys this resizable. If the element was wrapped and
516 * removeEl is not true then the wrap remains.
517 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
518 */
519 destroy : function(removeEl){
520 this.proxy.remove();
521 this.overlay.removeAllListeners();
522 this.overlay.remove();
523 var ps = YAHOO.ext.Resizable.positions;
524 for(var k in ps){
525 if(typeof ps[k] != 'function' && this[ps[k]]){
526 var h = this[ps[k]];
527 h.el.removeAllListeners();
528 h.el.remove();
529 }
530 }
531 if(removeEl){
532 this.el.update('');
533 this.el.remove();
534 }
535 }
536});
537
538// hash to map config positions to true positions
539YAHOO.ext.Resizable.positions = {
540 n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast'
541};
542
543
544YAHOO.ext.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
545 if(!this.tpl){
546 // only initialize the template if resizable is used
547 var tpl = YAHOO.ext.DomHelper.createTemplate(
548 {tag: 'div', cls: 'yresizable-handle yresizable-handle-{0}', html: '&#160;'}
549 );
550 tpl.compile();
551 YAHOO.ext.Resizable.Handle.prototype.tpl = tpl;
552 }
553 this.position = pos;
554 this.rz = rz;
555 this.el = this.tpl.append(rz.el.dom, [this.position], true);
556 this.el.unselectable();
557 if(transparent){
558 this.el.setOpacity(0);
559 }
560 this.el.mon('mousedown', this.onMouseDown, this, true);
561 if(!disableTrackOver){
562 this.el.mon('mouseover', this.onMouseOver, this, true);
563 this.el.mon('mouseout', this.onMouseOut, this, true);
564 }
565};
566
567YAHOO.ext.Resizable.Handle.prototype = {
568 afterResize : function(rz){
569 // do nothing
570 },
571
572 onMouseDown : function(e){
573 this.rz.onMouseDown(this, e);
574 },
575
576 onMouseOver : function(e){
577 this.rz.handleOver(this, e);
578 },
579
580 onMouseOut : function(e){
581 this.rz.handleOut(this, e);
582 }
583};
584
585
586