summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/widgets
Unidiff
Diffstat (limited to 'frontend/beta/js/YUI-extensions/widgets') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/BasicDialog.js1046
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Button.js185
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/DatePicker.js344
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/InlineEditor.js216
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/MessageBox.js230
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/QuickTips.js311
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Resizable.js586
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/SplitBar.js468
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TabPanel.js756
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TaskPanel.js0
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/TemplateView.js766
-rw-r--r--frontend/beta/js/YUI-extensions/widgets/Toolbar.js296
12 files changed, 5204 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js b/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js
new file mode 100644
index 0000000..3912568
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/BasicDialog.js
@@ -0,0 +1,1046 @@
1/**
2 * @class YAHOO.ext.BasicDialog
3 * @extends YAHOO.ext.util.Observable
4 * Lightweight Dialog Class.
5 *
6 * The code below lists all configuration options along with the default value.
7 * If the default value is what you want you can leave it out:
8 * <pre><code>
9 var dlg = new YAHOO.ext.BasicDialog('element-id', {
10 autoCreate: false, (true to auto create from scratch, or DomHelper Object)
11 title: null, (title to set at config time)
12 width: (css),
13 height: (css),
14 x: 200, //(defaults to center screen if blank)
15 y: 500, //(defaults to center screen if blank)
16 animateTarget: null,// (no animation) This is the id or element to animate from
17 resizable: true,
18 minHeight: 80,
19 minWidth: 200,
20 modal: false,
21 autoScroll: true,
22 closable: true,
23 constraintoviewport: true,
24 draggable: true,
25 autoTabs: false, (if true searches child nodes for elements with class ydlg-tab and converts them to tabs)
26 tabTag: 'div', // the tag name of tab elements
27 proxyDrag: false, (drag a proxy element rather than the dialog itself)
28 fixedcenter: false,
29 shadow: false,
30 buttonAlign: 'right',
31 minButtonWidth: 75,
32 shim: false // true to create an iframe shim to
33 // keep selects from showing through
34 });
35 </code></pre>
36 * @constructor
37 * Create a new BasicDialog.
38 * @param {String/HTMLElement/YAHOO.ext.Element} el The id of or container element
39 * @param {Object} config configuration options
40 */
41YAHOO.ext.BasicDialog = function(el, config){
42 this.el = getEl(el);
43 var dh = YAHOO.ext.DomHelper;
44 if(!this.el && config && config.autoCreate){
45 if(typeof config.autoCreate == 'object'){
46 if(!config.autoCreate.id){
47 config.autoCreate.id = el;
48 }
49 this.el = dh.append(document.body,
50 config.autoCreate, true);
51 }else{
52 this.el = dh.append(document.body,
53 {tag: 'div', id: el}, true);
54 }
55 }
56 el = this.el;
57 el.setDisplayed(true);
58 el.hide = this.hideAction;
59 this.id = el.id;
60 el.addClass('ydlg');
61
62 YAHOO.ext.util.Config.apply(this, config);
63
64 this.proxy = el.createProxy('ydlg-proxy');
65 this.proxy.hide = this.hideAction;
66 this.proxy.setOpacity(.5);
67 this.proxy.hide();
68
69 if(config.width){
70 el.setWidth(config.width);
71 }
72 if(config.height){
73 el.setHeight(config.height);
74 }
75 this.size = el.getSize();
76 if(typeof config.x != 'undefined' && typeof config.y != 'undefined'){
77 this.xy = [config.x,config.y];
78 }else{
79 this.xy = el.getCenterXY(true);
80 }
81 // find the header, body and footer
82 var cn = el.dom.childNodes;
83 for(var i = 0, len = cn.length; i < len; i++) {
84 var node = cn[i];
85 if(node && node.nodeType == 1){
86 if(YAHOO.util.Dom.hasClass(node, 'ydlg-hd')){
87 this.header = getEl(node, true);
88 }else if(YAHOO.util.Dom.hasClass(node, 'ydlg-bd')){
89 this.body = getEl(node, true);
90 }else if(YAHOO.util.Dom.hasClass(node, 'ydlg-ft')){
91 /**
92 * The footer element
93 * @type YAHOO.ext.Element
94 */
95 this.footer = getEl(node, true);
96 }
97 }
98 }
99
100 if(!this.header){
101 /**
102 * The header element
103 * @type YAHOO.ext.Element
104 */
105 this.header = this.body ?
106 dh.insertBefore(this.body.dom, {tag: 'div', cls:'ydlg-hd'}, true) :
107 dh.append(el.dom, {tag: 'div', cls:'ydlg-hd'}, true);
108 }
109 if(this.title){
110 this.header.update(this.title);
111 }
112 // this element allows the dialog to be focused for keyboard event
113 this.focusEl = dh.append(el.dom, {tag: 'a', href:'#', cls:'ydlg-focus', tabIndex:'-1'}, true);
114 this.focusEl.swallowEvent('click', true);
115 if(!this.body){
116 /**
117 * The body element
118 * @type YAHOO.ext.Element
119 */
120 this.body = dh.append(el.dom, {tag: 'div', cls:'ydlg-bd'}, true);
121 }
122 // wrap the header for special rendering
123 var hl = dh.insertBefore(this.header.dom, {tag: 'div', cls:'ydlg-hd-left'});
124 var hr = dh.append(hl, {tag: 'div', cls:'ydlg-hd-right'});
125 hr.appendChild(this.header.dom);
126
127 // wrap the body and footer for special rendering
128 this.bwrap = dh.insertBefore(this.body.dom, {tag: 'div', cls:'ydlg-dlg-body'}, true);
129 this.bwrap.dom.appendChild(this.body.dom);
130 if(this.footer) this.bwrap.dom.appendChild(this.footer.dom);
131
132 this.bg = this.el.createChild({
133 tag: 'div', cls:'ydlg-bg',
134 html: '<div class="ydlg-bg-left"><div class="ydlg-bg-right"><div class="ydlg-bg-center">&#160;</div></div></div>'
135 });
136 this.centerBg = getEl(this.bg.dom.firstChild.firstChild.firstChild);
137
138
139 if(this.autoScroll !== false && !this.autoTabs){
140 this.body.setStyle('overflow', 'auto');
141 }
142 if(this.closable !== false){
143 this.el.addClass('ydlg-closable');
144 this.close = dh.append(el.dom, {tag: 'div', cls:'ydlg-close'}, true);
145 this.close.mon('click', this.closeClick, this, true);
146 this.close.addClassOnOver('ydlg-close-over');
147 }
148 if(this.resizable !== false){
149 this.el.addClass('ydlg-resizable');
150 this.resizer = new YAHOO.ext.Resizable(el, {
151 minWidth: this.minWidth || 80,
152 minHeight:this.minHeight || 80,
153 handles: 'all',
154 pinned: true
155 });
156 this.resizer.on('beforeresize', this.beforeResize, this, true);
157 this.resizer.on('resize', this.onResize, this, true);
158 }
159 if(this.draggable !== false){
160 el.addClass('ydlg-draggable');
161 if (!this.proxyDrag) {
162 var dd = new YAHOO.util.DD(el.dom.id, 'WindowDrag');
163 }
164 else {
165 var dd = new YAHOO.util.DDProxy(el.dom.id, 'WindowDrag', {dragElId: this.proxy.id});
166 }
167 dd.setHandleElId(this.header.id);
168 dd.endDrag = this.endMove.createDelegate(this);
169 dd.startDrag = this.startMove.createDelegate(this);
170 dd.onDrag = this.onDrag.createDelegate(this);
171 this.dd = dd;
172 }
173 if(this.modal){
174 this.mask = dh.append(document.body, {tag: 'div', cls:'ydlg-mask'}, true);
175 this.mask.enableDisplayMode('block');
176 this.mask.hide();
177 this.el.addClass('ydlg-modal');
178 }
179 if(this.shadow){
180 this.shadow = el.createProxy({tag: 'div', cls:'ydlg-shadow'});
181 this.shadow.setOpacity(.3);
182 this.shadow.setVisibilityMode(YAHOO.ext.Element.VISIBILITY);
183 this.shadow.setDisplayed('block');
184 this.shadow.hide = this.hideAction;
185 this.shadow.hide();
186 }else{
187 this.shadowOffset = 0;
188 }
189 // adding an iframe shim to FF kills the cursor on the PC, but is needed on the Mac
190 // where it (luckily) does not kill the cursor
191 if(!YAHOO.ext.util.Browser.isGecko || YAHOO.ext.util.Browser.isMac){
192 if(this.shim){
193 this.shim = this.el.createShim();
194 this.shim.hide = this.hideAction;
195 this.shim.hide();
196 }
197 }else{
198 this.shim = false;
199 }
200 if(this.autoTabs){
201 this.initTabs();
202 }
203 this.syncBodyHeight();
204 this.events = {
205 /**
206 * @event keydown
207 * Fires when a key is pressed
208 * @param {YAHOO.ext.BasicDialog} this
209 * @param {YAHOO.ext.EventObject} e
210 */
211 'keydown' : true,
212 /**
213 * @event move
214 * Fires when this dialog is moved by the user.
215 * @param {YAHOO.ext.BasicDialog} this
216 * @param {Number} x The new page X
217 * @param {Number} y The new page Y
218 */
219 'move' : true,
220 /**
221 * @event resize
222 * Fires when this dialog is resized by the user.
223 * @param {YAHOO.ext.BasicDialog} this
224 * @param {Number} width The new width
225 * @param {Number} height The new height
226 */
227 'resize' : true,
228 /**
229 * @event beforehide
230 * Fires before this dialog is hidden.
231 * @param {YAHOO.ext.BasicDialog} this
232 */
233 'beforehide' : true,
234 /**
235 * @event hide
236 * Fires when this dialog is hidden.
237 * @param {YAHOO.ext.BasicDialog} this
238 */
239 'hide' : true,
240 /**
241 * @event beforeshow
242 * Fires before this dialog is shown.
243 * @param {YAHOO.ext.BasicDialog} this
244 */
245 'beforeshow' : true,
246 /**
247 * @event show
248 * Fires when this dialog is shown.
249 * @param {YAHOO.ext.BasicDialog} this
250 */
251 'show' : true
252 };
253 el.mon('keydown', this.onKeyDown, this, true);
254 el.mon("mousedown", this.toFront, this, true);
255
256 YAHOO.ext.EventManager.onWindowResize(this.adjustViewport, this, true);
257 this.el.hide();
258 YAHOO.ext.DialogManager.register(this);
259};
260
261YAHOO.extendX(YAHOO.ext.BasicDialog, YAHOO.ext.util.Observable, {
262 shadowOffset: 3,
263 minHeight: 80,
264 minWidth: 200,
265 minButtonWidth: 75,
266 defaultButton: null,
267 buttonAlign: 'right',
268 /**
269 * Sets the dialog title.
270 * @param {String} text
271 * @return {YAHOO.ext.BasicDialog} this
272 */
273 setTitle : function(text){
274 this.header.update(text);
275 return this;
276 },
277
278 closeClick : function(){
279 this.hide();
280 },
281
282 /**
283 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
284 * @return {YAHOO.ext.TabPanel} tabs The tabs component
285 */
286 initTabs : function(){
287 var tabs = this.getTabs();
288 while(tabs.getTab(0)){
289 tabs.removeTab(0);
290 }
291 var tabEls = YAHOO.util.Dom.getElementsByClassName('ydlg-tab', this.tabTag || 'div', this.el.dom);
292 if(tabEls.length > 0){
293 for(var i = 0, len = tabEls.length; i < len; i++) {
294 var tabEl = tabEls[i];
295 tabs.addTab(YAHOO.util.Dom.generateId(tabEl), tabEl.title);
296 tabEl.title = '';
297 }
298 tabs.activate(0);
299 }
300 return tabs;
301 },
302
303 beforeResize : function(){
304 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
305 },
306
307 onResize : function(){
308 this.refreshSize();
309 this.syncBodyHeight();
310 this.adjustAssets();
311 this.fireEvent('resize', this, this.size.width, this.size.height);
312 },
313
314 onKeyDown : function(e){
315 if(this.isVisible()){
316 this.fireEvent('keydown', this, e);
317 }
318 },
319
320 /**
321 * Resizes the dialog.
322 * @param {Number} width
323 * @param {Number} height
324 * @return {YAHOO.ext.BasicDialog} this
325 */
326 resizeTo : function(width, height){
327 this.el.setSize(width, height);
328 this.size = {width: width, height: height};
329 this.syncBodyHeight();
330 if(this.fixedcenter){
331 this.center();
332 }
333 if(this.isVisible()){
334 this.constrainXY();
335 this.adjustAssets();
336 }
337 this.fireEvent('resize', this, width, height);
338 return this;
339 },
340
341
342 /**
343 * Resizes the dialog to fit the specified content size.
344 * @param {Number} width
345 * @param {Number} height
346 * @return {YAHOO.ext.BasicDialog} this
347 */
348 setContentSize : function(w, h){
349 h += this.getHeaderFooterHeight() + this.body.getMargins('tb');
350 w += this.body.getMargins('lr') + this.bwrap.getMargins('lr') + this.centerBg.getPadding('lr');
351 //if(!this.el.isBorderBox()){
352 h += this.body.getPadding('tb') + this.bwrap.getBorderWidth('tb') + this.body.getBorderWidth('tb') + this.el.getBorderWidth('tb');
353 w += this.body.getPadding('lr') + this.bwrap.getBorderWidth('lr') + this.body.getBorderWidth('lr') + this.bwrap.getPadding('lr') + this.el.getBorderWidth('lr');
354 //}
355 if(this.tabs){
356 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins('tb') + this.tabs.bodyEl.getPadding('tb');
357 w += this.tabs.bodyEl.getMargins('lr') + this.tabs.bodyEl.getPadding('lr');
358 }
359 this.resizeTo(w, h);
360 return this;
361 },
362
363 /**
364 * Adds a key listener for when this dialog is displayed
365 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
366 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
367 * @param {Function} fn The function to call
368 * @param {Object} scope (optional) The scope of the function
369 * @return {YAHOO.ext.BasicDialog} this
370 */
371 addKeyListener : function(key, fn, scope){
372 var keyCode, shift, ctrl, alt;
373 if(typeof key == 'object' && !(key instanceof Array)){
374 keyCode = key['key'];
375 shift = key['shift'];
376 ctrl = key['ctrl'];
377 alt = key['alt'];
378 }else{
379 keyCode = key;
380 }
381 var handler = function(dlg, e){
382 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
383 var k = e.getKey();
384 if(keyCode instanceof Array){
385 for(var i = 0, len = keyCode.length; i < len; i++){
386 if(keyCode[i] == k){
387 fn.call(scope || window, dlg, k, e);
388 return;
389 }
390 }
391 }else{
392 if(k == keyCode){
393 fn.call(scope || window, dlg, k, e);
394 }
395 }
396 }
397 };
398 this.on('keydown', handler);
399 return this;
400 },
401
402 /**
403 * Returns the TabPanel component (if autoTabs)
404 * @return {YAHOO.ext.TabPanel}
405 */
406 getTabs : function(){
407 if(!this.tabs){
408 this.el.addClass('ydlg-auto-tabs');
409 this.body.addClass(this.tabPosition == 'bottom' ? 'ytabs-bottom' : 'ytabs-top');
410 this.tabs = new YAHOO.ext.TabPanel(this.body.dom, this.tabPosition == 'bottom');
411 }
412 return this.tabs;
413 },
414
415 /**
416 * Adds a button.
417 * @param {String/Object} config A string becomes the button text, an object is expected to be a valid YAHOO.ext.DomHelper element config
418 * @param {Function} handler The function called when the button is clicked
419 * @param {Object} scope (optional) The scope of the handler function
420 * @return {YAHOO.ext.Button}
421 */
422 addButton : function(config, handler, scope){
423 var dh = YAHOO.ext.DomHelper;
424 if(!this.footer){
425 this.footer = dh.append(this.bwrap.dom, {tag: 'div', cls:'ydlg-ft'}, true);
426 }
427 if(!this.btnContainer){
428 var tb = this.footer.createChild({
429 tag:'div',
430 cls:'ydlg-btns ydlg-btns-'+this.buttonAlign,
431 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table>'
432 });
433 this.btnContainer = tb.dom.firstChild.firstChild.firstChild;
434 }
435 var bconfig = {
436 handler: handler,
437 scope: scope,
438 minWidth: this.minButtonWidth
439 };
440 if(typeof config == 'string'){
441 bconfig.text = config;
442 }else{
443 bconfig.dhconfig = config;
444 }
445 var btn = new YAHOO.ext.Button(
446 this.btnContainer.appendChild(document.createElement('td')),
447 bconfig
448 );
449 this.syncBodyHeight();
450 if(!this.buttons){
451 this.buttons = [];
452 }
453 this.buttons.push(btn);
454 return btn;
455 },
456
457 /**
458 * Sets the default button to be focused when the dialog is displayed
459 * @param {YAHOO.ext.BasicDialog.Button} btn The button object returned by addButton
460 * @return {YAHOO.ext.BasicDialog} this
461 */
462 setDefaultButton : function(btn){
463 this.defaultButton = btn;
464 return this;
465 },
466
467 getHeaderFooterHeight : function(safe){
468 var height = 0;
469 if(this.header){
470 height += this.header.getHeight();
471 }
472 if(this.footer){
473 var fm = this.footer.getMargins();
474 height += (this.footer.getHeight()+fm.top+fm.bottom);
475 }
476 height += this.bwrap.getPadding('tb')+this.bwrap.getBorderWidth('tb');
477 height += this.centerBg.getPadding('tb');
478 return height;
479 },
480
481 syncBodyHeight : function(){
482 var height = this.size.height - this.getHeaderFooterHeight(false);
483 this.body.setHeight(height-this.body.getMargins('tb'));
484 if(this.tabs){
485 this.tabs.syncHeight();
486 }
487 var hh = this.header.getHeight();
488 var h = this.size.height-hh;
489 this.centerBg.setHeight(h);
490 this.bwrap.setLeftTop(this.centerBg.getPadding('l'), hh+this.centerBg.getPadding('t'));
491 this.bwrap.setHeight(h-this.centerBg.getPadding('tb'));
492 this.bwrap.setWidth(this.el.getWidth(true)-this.centerBg.getPadding('lr'));
493 this.body.setWidth(this.bwrap.getWidth(true));
494 },
495
496 /**
497 * Restores the previous state of the dialog if YAHOO.ext.state is configured
498 * @return {YAHOO.ext.BasicDialog} this
499 */
500 restoreState : function(){
501 var box = YAHOO.ext.state.Manager.get(this.stateId || (this.el.id + '-state'));
502 if(box && box.width){
503 this.xy = [box.x, box.y];
504 this.resizeTo(box.width, box.height);
505 }
506 return this;
507 },
508
509 beforeShow : function(){
510 if(this.fixedcenter) {
511 this.xy = this.el.getCenterXY(true);
512 }
513 if(this.modal){
514 YAHOO.util.Dom.addClass(document.body, 'masked');
515 this.mask.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
516 this.mask.show();
517 }
518 this.constrainXY();
519 },
520
521 animShow : function(){
522 var b = getEl(this.animateTarget, true).getBox();
523 this.proxy.setSize(b.width, b.height);
524 this.proxy.setLocation(b.x, b.y);
525 this.proxy.show();
526 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
527 true, .35, this.showEl.createDelegate(this));
528 },
529
530 /**
531 * Shows the dialog.
532 * @param {String/HTMLElement/YAHOO.ext.Element} animateTarget (optional) Reset the animation target
533 * @return {YAHOO.ext.BasicDialog} this
534 */
535 show : function(animateTarget){
536 if (this.fireEvent('beforeshow', this) === false){
537 return;
538 }
539 if(this.syncHeightBeforeShow){
540 this.syncBodyHeight();
541 }
542 this.animateTarget = animateTarget || this.animateTarget;
543 if(!this.el.isVisible()){
544 this.beforeShow();
545 if(this.animateTarget){
546 this.animShow();
547 }else{
548 this.showEl();
549 }
550 }
551 return this;
552 },
553
554 showEl : function(){
555 this.proxy.hide();
556 this.el.setXY(this.xy);
557 this.el.show();
558 this.adjustAssets(true);
559 this.toFront();
560 this.focus();
561 this.fireEvent('show', this);
562 },
563
564 focus : function(){
565 if(this.defaultButton){
566 this.defaultButton.focus();
567 }else{
568 this.focusEl.focus();
569 }
570 },
571
572 constrainXY : function(){
573 if(this.constraintoviewport !== false){
574 if(!this.viewSize){
575 if(this.container){
576 var s = this.container.getSize();
577 this.viewSize = [s.width, s.height];
578 }else{
579 this.viewSize = [YAHOO.util.Dom.getViewportWidth(),
580 YAHOO.util.Dom.getViewportHeight()];
581 }
582 }
583 var x = this.xy[0], y = this.xy[1];
584 var w = this.size.width, h = this.size.height;
585 var vw = this.viewSize[0], vh = this.viewSize[1];
586 // only move it if it needs it
587 var moved = false;
588 // first validate right/bottom
589 if(x + w > vw){
590 x = vw - w;
591 moved = true;
592 }
593 if(y + h > vh){
594 y = vh - h;
595 moved = true;
596 }
597 // then make sure top/left isn't negative
598 if(x < 0){
599 x = 0;
600 moved = true;
601 }
602 if(y < 0){
603 y = 0;
604 moved = true;
605 }
606 if(moved){
607 // cache xy
608 this.xy = [x, y];
609 if(this.isVisible()){
610 this.el.setLocation(x, y);
611 this.adjustAssets();
612 }
613 }
614 }
615 },
616
617 onDrag : function(){
618 if(!this.proxyDrag){
619 this.xy = this.el.getXY();
620 this.adjustAssets();
621 }
622 },
623
624 adjustAssets : function(doShow){
625 var x = this.xy[0], y = this.xy[1];
626 var w = this.size.width, h = this.size.height;
627 if(doShow === true){
628 if(this.shadow){
629 this.shadow.show();
630 }
631 if(this.shim){
632 this.shim.show();
633 }
634 }
635 if(this.shadow && this.shadow.isVisible()){
636 this.shadow.setBounds(x + this.shadowOffset, y + this.shadowOffset, w, h);
637 }
638 if(this.shim && this.shim.isVisible()){
639 this.shim.setBounds(x, y, w, h);
640 }
641 },
642
643
644 adjustViewport : function(w, h){
645 if(!w || !h){
646 w = YAHOO.util.Dom.getViewportWidth();
647 h = YAHOO.util.Dom.getViewportHeight();
648 }
649 // cache the size
650 this.viewSize = [w, h];
651 if(this.modal && this.mask.isVisible()){
652 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
653 this.mask.setSize(YAHOO.util.Dom.getDocumentWidth(), YAHOO.util.Dom.getDocumentHeight());
654 }
655 if(this.isVisible()){
656 this.constrainXY();
657 }
658 },
659
660 /**
661 * Destroys this dialog
662 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
663 */
664 destroy : function(removeEl){
665 YAHOO.ext.EventManager.removeResizeListener(this.adjustViewport, this);
666 if(this.tabs){
667 this.tabs.destroy(removeEl);
668 }
669 if(this.shim){
670 this.shim.remove();
671 }
672 if(this.shadow){
673 this.shadow.remove();
674 }
675 if(this.proxy){
676 this.proxy.remove();
677 }
678 if(this.resizer){
679 this.resizer.destroy();
680 }
681 if(this.close){
682 this.close.removeAllListeners();
683 this.close.remove();
684 }
685 if(this.mask){
686 this.mask.remove();
687 }
688 if(this.dd){
689 this.dd.unreg();
690 }
691 if(this.buttons){
692 for(var i = 0, len = this.buttons.length; i < len; i++){
693 this.buttons[i].destroy();
694 }
695 }
696 this.el.removeAllListeners();
697 if(removeEl === true){
698 this.el.update('');
699 this.el.remove();
700 }
701 YAHOO.ext.DialogManager.unregister(this);
702 },
703
704 startMove : function(){
705 if(this.proxyDrag){
706 this.proxy.show();
707 }
708 if(this.constraintoviewport !== false){
709 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
710 }
711 },
712
713 endMove : function(){
714 if(!this.proxyDrag){
715 YAHOO.util.DD.prototype.endDrag.apply(this.dd, arguments);
716 }else{
717 YAHOO.util.DDProxy.prototype.endDrag.apply(this.dd, arguments);
718 this.proxy.hide();
719 }
720 this.refreshSize();
721 this.adjustAssets();
722 this.fireEvent('move', this, this.xy[0], this.xy[1])
723 },
724
725 /**
726 * Brings this dialog to the front of any other visible dialogs
727 * @return {YAHOO.ext.BasicDialog} this
728 */
729 toFront : function(){
730 YAHOO.ext.DialogManager.bringToFront(this);
731 return this;
732 },
733
734 /**
735 * Sends this dialog to the back (under) of any other visible dialogs
736 * @return {YAHOO.ext.BasicDialog} this
737 */
738 toBack : function(){
739 YAHOO.ext.DialogManager.sendToBack(this);
740 return this;
741 },
742
743 /**
744 * Centers this dialog
745 * @return {YAHOO.ext.BasicDialog} this
746 */
747 center : function(){
748 var xy = this.el.getCenterXY(true);
749 this.moveTo(xy[0], xy[1]);
750 return this;
751 },
752
753 /**
754 * Moves the dialog to the specified point
755 * @param {Number} x
756 * @param {Number} y
757 * @return {YAHOO.ext.BasicDialog} this
758 */
759 moveTo : function(x, y){
760 this.xy = [x,y];
761 if(this.isVisible()){
762 this.el.setXY(this.xy);
763 this.adjustAssets();
764 }
765 return this;
766 },
767
768 /**
769 * Returns true if the dialog is visible
770 * @return {Boolean}
771 */
772 isVisible : function(){
773 return this.el.isVisible();
774 },
775
776 animHide : function(callback){
777 var b = getEl(this.animateTarget, true).getBox();
778 this.proxy.show();
779 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
780 this.el.hide();
781 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
782 this.hideEl.createDelegate(this, [callback]));
783 },
784
785 /**
786 * Hides the dialog.
787 * @param {Function} callback (optional) Function to call when the dialog is hidden
788 * @return {YAHOO.ext.BasicDialog} this
789 */
790 hide : function(callback){
791 if (this.fireEvent('beforehide', this) === false)
792 return;
793
794 if(this.shadow){
795 this.shadow.hide();
796 }
797 if(this.shim) {
798 this.shim.hide();
799 }
800 if(this.animateTarget){
801 this.animHide(callback);
802 }else{
803 this.el.hide();
804 this.hideEl(callback);
805 }
806 return this;
807 },
808
809 hideEl : function(callback){
810 this.proxy.hide();
811 if(this.modal){
812 this.mask.hide();
813 YAHOO.util.Dom.removeClass(document.body, 'masked');
814 }
815 this.fireEvent('hide', this);
816 if(typeof callback == 'function'){
817 callback();
818 }
819 },
820
821 hideAction : function(){
822 this.setLeft('-10000px');
823 this.setTop('-10000px');
824 this.setStyle('visibility', 'hidden');
825 },
826
827 refreshSize : function(){
828 this.size = this.el.getSize();
829 this.xy = this.el.getXY();
830 YAHOO.ext.state.Manager.set(this.stateId || this.el.id + '-state', this.el.getBox());
831 },
832
833 setZIndex : function(index){
834 if(this.modal){
835 this.mask.setStyle('z-index', index);
836 }
837 if(this.shim){
838 this.shim.setStyle('z-index', ++index);
839 }
840 if(this.shadow){
841 this.shadow.setStyle('z-index', ++index);
842 }
843 this.el.setStyle('z-index', ++index);
844 if(this.proxy){
845 this.proxy.setStyle('z-index', ++index);
846 }
847 if(this.resizer){
848 this.resizer.proxy.setStyle('z-index', ++index);
849 }
850
851 this.lastZIndex = index;
852 },
853
854 /**
855 * Returns the element for this dialog
856 * @return {YAHOO.ext.Element}
857 */
858 getEl : function(){
859 return this.el;
860 }
861});
862
863/**
864 * @class YAHOO.ext.DialogManager
865 * Provides global access to BasicDialogs that have been created and
866 * support for z-indexing (layering) multiple open dialogs.
867 */
868YAHOO.ext.DialogManager = function(){
869 var list = {};
870 var accessList = [];
871 var front = null;
872
873 var sortDialogs = function(d1, d2){
874 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
875 };
876
877 var orderDialogs = function(){
878 accessList.sort(sortDialogs);
879 var seed = YAHOO.ext.DialogManager.zseed;
880 for(var i = 0, len = accessList.length; i < len; i++){
881 if(accessList[i]){
882 accessList[i].setZIndex(seed + (i*10));
883 }
884 }
885 };
886
887 return {
888 /**
889 * The starting z-index for BasicDialogs - defaults to 10000
890 * @type Number
891 */
892 zseed : 10000,
893
894
895 register : function(dlg){
896 list[dlg.id] = dlg;
897 accessList.push(dlg);
898 },
899
900 unregister : function(dlg){
901 delete list[dlg.id];
902 if(!accessList.indexOf){
903 for(var i = 0, len = accessList.length; i < len; i++){
904 accessList.splice(i, 1);
905 return;
906 }
907 }else{
908 var i = accessList.indexOf(dlg);
909 if(i != -1){
910 accessList.splice(i, 1);
911 }
912 }
913 },
914
915 /**
916 * Gets a registered dialog by id
917 * @param {String/Object} id The id of the dialog or a dialog
918 * @return {YAHOO.ext.BasicDialog}
919 */
920 get : function(id){
921 return typeof id == 'object' ? id : list[id];
922 },
923
924 /**
925 * Brings the specified dialog to the front
926 * @param {String/Object} dlg The id of the dialog or a dialog
927 * @return {YAHOO.ext.BasicDialog}
928 */
929 bringToFront : function(dlg){
930 dlg = this.get(dlg);
931 if(dlg != front){
932 front = dlg;
933 dlg._lastAccess = new Date().getTime();
934 orderDialogs();
935 }
936 return dlg;
937 },
938
939 /**
940 * Sends the specified dialog to the back
941 * @param {String/Object} dlg The id of the dialog or a dialog
942 * @return {YAHOO.ext.BasicDialog}
943 */
944 sendToBack : function(dlg){
945 dlg = this.get(dlg);
946 dlg._lastAccess = -(new Date().getTime());
947 orderDialogs();
948 return dlg;
949 }
950 };
951}();
952
953/**
954 * @class YAHOO.ext.LayoutDialog
955 * @extends YAHOO.ext.BasicDialog
956 * Dialog which provides adjustments for working with a layout in a Dialog.
957 * Add your neccessary layout config options to the dialogs config.<br>
958 * Example Usage (including a nested layout):
959 * <pre><code> if(!dialog){
960 dialog = new YAHOO.ext.LayoutDialog("download-dlg", {
961 modal: true,
962 width:600,
963 height:450,
964 shadow:true,
965 minWidth:500,
966 minHeight:350,
967 autoTabs:true,
968 proxyDrag:true,
969 // layout config merges with the dialog config
970 center:{
971 tabPosition: 'top',
972 alwaysShowTabs: true
973 }
974 });
975 dialog.addKeyListener(27, dialog.hide, dialog);
976 dialog.setDefaultButton(dialog.addButton('Close', dialog.hide, dialog));
977 dialog.addButton('Build It!', this.getDownload, this);
978
979 // we can even add nested layouts
980 var innerLayout = new YAHOO.ext.BorderLayout('dl-inner', {
981 east: {
982 initialSize: 200,
983 autoScroll:true,
984 split:true
985 },
986 center: {
987 autoScroll:true
988 }
989 });
990 innerLayout.beginUpdate();
991 innerLayout.add('east', new YAHOO.ext.ContentPanel('dl-details'));
992 innerLayout.add('center', new YAHOO.ext.ContentPanel('selection-panel'));
993 innerLayout.endUpdate(true);
994
995 // when doing updates to the top level layout in a dialog, you need to
996 // use dialog.beginUpdate()/endUpdate() instead of layout.beginUpdate()/endUpdate()
997 var layout = dialog.getLayout();
998 dialog.beginUpdate();
999 layout.add('center', new YAHOO.ext.ContentPanel('standard-panel',
1000 {title: 'Download the Source', fitToFrame:true}));
1001 layout.add('center', new YAHOO.ext.NestedLayoutPanel(innerLayout,
1002 {title: 'Build your own yui-ext.js'}));
1003 layout.getRegion('center').showPanel(sp);
1004 dialog.endUpdate();</code></pre>
1005 * @constructor
1006 * @param {String/HTMLElement/YAHOO.ext.Element} el The id of or container element
1007 * @param {Object} config configuration options
1008 */
1009YAHOO.ext.LayoutDialog = function(el, config){
1010 config.autoTabs = false;
1011 YAHOO.ext.LayoutDialog.superclass.constructor.call(this, el, config);
1012 this.body.setStyle({overflow:'hidden', position:'relative'});
1013 this.layout = new YAHOO.ext.BorderLayout(this.body.dom, config);
1014 this.layout.monitorWindowResize = false;
1015 this.el.addClass('ydlg-auto-layout');
1016 // fix case when center region overwrites center function
1017 this.center = YAHOO.ext.BasicDialog.prototype.center;
1018 this.on('show', this.layout.layout, this.layout, true);
1019};
1020YAHOO.extendX(YAHOO.ext.LayoutDialog, YAHOO.ext.BasicDialog, {
1021 /**
1022 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
1023 * @deprecated
1024 */
1025 endUpdate : function(){
1026 this.layout.endUpdate();
1027 },
1028 /**
1029 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
1030 * @deprecated
1031 */
1032 beginUpdate : function(){
1033 this.layout.beginUpdate();
1034 },
1035 /**
1036 * Get the BorderLayout for this dialog
1037 * @return {YAHOO.ext.BorderLayout}
1038 */
1039 getLayout : function(){
1040 return this.layout;
1041 },
1042 syncBodyHeight : function(){
1043 YAHOO.ext.LayoutDialog.superclass.syncBodyHeight.call(this);
1044 if(this.layout)this.layout.layout();
1045 }
1046});
diff --git a/frontend/beta/js/YUI-extensions/widgets/Button.js b/frontend/beta/js/YUI-extensions/widgets/Button.js
new file mode 100644
index 0000000..5bf3dc3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Button.js
@@ -0,0 +1,185 @@
1/**
2 * @class YAHOO.ext.Button
3 * @extends YAHOO.ext.util.Observable
4 * Simple Button class
5 * @cfg {String} text The button text
6 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
7 * @cfg {Object} scope The scope of the handler
8 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
9 * @constructor
10 * Create a new button
11 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12 * @param {Object} config The config object
13 */
14YAHOO.ext.Button = function(renderTo, config){
15 YAHOO.ext.util.Config.apply(this, config);
16 this.events = {
17 /**
18 * @event click
19 * Fires when this button is clicked
20 * @param {Button} this
21 * @param {EventObject} e The click event
22 */
23 'click' : true
24 };
25 if(renderTo){
26 this.render(renderTo);
27 }
28};
29
30YAHOO.extendX(YAHOO.ext.Button, YAHOO.ext.util.Observable, {
31 render : function(renderTo){
32 var btn;
33 if(!this.dhconfig){
34 if(!YAHOO.ext.Button.buttonTemplate){
35 // hideous table template
36 YAHOO.ext.Button.buttonTemplate = new YAHOO.ext.DomHelper.Template('<a href="#" class="ybtn-focus"><table border="0" cellpadding="0" cellspacing="0" class="ybtn-wrap"><tbody><tr><td class="ybtn-left">&#160;</td><td class="ybtn-center" unselectable="on">{0}</td><td class="ybtn-right">&#160;</td></tr></tbody></table></a>');
37 }
38 btn = YAHOO.ext.Button.buttonTemplate.append(
39 getEl(renderTo).dom, [this.text], true);
40 this.tbl = getEl(btn.dom.firstChild, true);
41 }else{
42 btn = YAHOO.ext.DomHelper.append(this.footer.dom, this.dhconfig, true);
43 }
44 this.el = btn;
45 this.autoWidth();
46 btn.addClass('ybtn');
47 btn.mon('click', this.onClick, this, true);
48 btn.on('mouseover', this.onMouseOver, this, true);
49 btn.on('mouseout', this.onMouseOut, this, true);
50 btn.on('mousedown', this.onMouseDown, this, true);
51 btn.on('mouseup', this.onMouseUp, this, true);
52 },
53 /**
54 * Returns the buttons element
55 * @return {YAHOO.ext.Element}
56 */
57 getEl : function(){
58 return this.el;
59 },
60
61 /**
62 * Destroys this Button.
63 */
64 destroy : function(){
65 this.el.removeAllListeners();
66 this.purgeListeners();
67 this.el.update('');
68 this.el.remove();
69 },
70
71 autoWidth : function(){
72 if(this.tbl){
73 this.el.setWidth('auto');
74 this.tbl.setWidth('auto');
75 if(this.minWidth){
76 if(this.tbl.getWidth() < this.minWidth){
77 this.tbl.setWidth(this.minWidth);
78 }
79 }
80 this.el.setWidth(this.tbl.getWidth());
81 }
82 },
83 /**
84 * Sets this buttons click handler
85 * @param {Function} handler The function to call when the button is clicked
86 * @param {Object} scope (optional) Scope for the function passed above
87 */
88 setHandler : function(handler, scope){
89 this.handler = handler;
90 this.scope = scope;
91 },
92
93 /**
94 * Set this buttons text
95 * @param {String} text
96 */
97 setText : function(text){
98 this.text = text;
99 this.el.dom.firstChild.firstChild.firstChild.childNodes[1].innerHTML = text;
100 this.autoWidth();
101 },
102
103 /**
104 * Get the text for this button
105 * @return {String}
106 */
107 getText : function(){
108 return this.text;
109 },
110
111 /**
112 * Show this button
113 */
114 show: function(){
115 this.el.setStyle('display', '');
116 },
117
118 /**
119 * Hide this button
120 */
121 hide: function(){
122 this.el.setStyle('display', 'none');
123 },
124
125 /**
126 * Convenience function for boolean show/hide
127 * @param {Boolean} visible true to show/false to hide
128 */
129 setVisible: function(visible){
130 if(visible) {
131 this.show();
132 }else{
133 this.hide();
134 }
135 },
136
137 /**
138 * Focus the button
139 */
140 focus : function(){
141 this.el.focus();
142 },
143
144 /**
145 * Disable this button
146 */
147 disable : function(){
148 this.el.addClass('ybtn-disabled');
149 this.disabled = true;
150 },
151
152 /**
153 * Enable this button
154 */
155 enable : function(){
156 this.el.removeClass('ybtn-disabled');
157 this.disabled = false;
158 },
159
160 onClick : function(e){
161 e.preventDefault();
162 if(!this.disabled){
163 this.fireEvent('click', this, e);
164 if(this.handler){
165 this.handler.call(this.scope || this, this, e);
166 }
167 }
168 },
169 onMouseOver : function(e){
170 if(!this.disabled){
171 this.el.addClass('ybtn-over');
172 }
173 },
174 onMouseOut : function(e){
175 this.el.removeClass('ybtn-over');
176 },
177 onMouseDown : function(){
178 if(!this.disabled){
179 this.el.addClass('ybtn-click');
180 }
181 },
182 onMouseUp : function(){
183 this.el.removeClass('ybtn-click');
184 }
185});
diff --git a/frontend/beta/js/YUI-extensions/widgets/DatePicker.js b/frontend/beta/js/YUI-extensions/widgets/DatePicker.js
new file mode 100644
index 0000000..eb1e06f
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/DatePicker.js
@@ -0,0 +1,344 @@
1YAHOO.ext.DatePicker = function(id, parentElement){
2 this.id = id;
3 this.selectedDate = new Date();
4 this.visibleDate = new Date();
5 this.element = null;
6 this.shadow = null;
7 this.callback = null;
8 this.buildControl(parentElement || document.body);
9 this.mouseDownHandler = YAHOO.ext.EventManager.wrap(this.handleMouseDown, this, true);
10 this.keyDownHandler = YAHOO.ext.EventManager.wrap(this.handleKeyDown, this, true);
11 this.wheelHandler = YAHOO.ext.EventManager.wrap(this.handleMouseWheel, this, true);
12};
13
14YAHOO.ext.DatePicker.prototype = {
15 show : function(x, y, value, callback){
16 this.hide();
17 this.selectedDate = value;
18 this.visibleDate = value;
19 this.callback = callback;
20 this.refresh();
21 this.element.show();
22 this.element.setXY(this.constrainToViewport ? this.constrainXY(x, y) : [x, y]);
23 this.shadow.show();
24 this.shadow.setRegion(this.element.getRegion());
25 this.element.dom.tabIndex = 1;
26 this.element.focus();
27 YAHOO.util.Event.on(document, "mousedown", this.mouseDownHandler);
28 YAHOO.util.Event.on(document, "keydown", this.keyDownHandler);
29 YAHOO.util.Event.on(document, "mousewheel", this.wheelHandler);
30 YAHOO.util.Event.on(document, "DOMMouseScroll", this.wheelHandler);
31 },
32
33 constrainXY : function(x, y){
34 var w = YAHOO.util.Dom.getViewportWidth();
35 var h = YAHOO.util.Dom.getViewportHeight();
36 var size = this.element.getSize();
37 return [
38 Math.min(w-size.width, x),
39 Math.min(h-size.height, y)
40 ];
41 },
42
43 hide : function(){
44 this.shadow.hide();
45 this.element.hide();
46 YAHOO.util.Event.removeListener(document, "mousedown", this.mouseDownHandler);
47 YAHOO.util.Event.removeListener(document, "keydown", this.keyDownHandler);
48 YAHOO.util.Event.removeListener(document, "mousewheel", this.wheelHandler);
49 YAHOO.util.Event.removeListener(document, "DOMMouseScroll", this.wheelHandler);
50 },
51
52 setSelectedDate : function(date){
53 this.selectedDate = date;
54 },
55
56 getSelectedDate : function(){
57 return this.selectedDate;
58 },
59
60 showPrevMonth : function(){
61 this.visibleDate = this.getPrevMonth(this.visibleDate);
62 this.refresh();
63 },
64
65 showNextMonth : function(){
66 this.visibleDate = this.getNextMonth(this.visibleDate);
67 this.refresh();
68 },
69
70 showPrevYear : function(){
71 var d = this.visibleDate;
72 this.visibleDate = new Date(d.getFullYear()-1, d.getMonth(), d.getDate());
73 this.refresh();
74 },
75
76 showNextYear : function(){
77 var d = this.visibleDate;
78 this.visibleDate = new Date(d.getFullYear()+1, d.getMonth(), d.getDate());
79 this.refresh();
80 },
81
82 handleMouseDown : function(e){
83 var target = e.getTarget();
84 if(target != this.element.dom && !YAHOO.util.Dom.isAncestor(this.element.dom, target)){
85 this.hide();
86 }
87 },
88
89 handleKeyDown : function(e){
90 switch(e.browserEvent.keyCode){
91 case e.LEFT:
92 this.showPrevMonth();
93 e.stopEvent();
94 break;
95 case e.RIGHT:
96 this.showNextMonth();
97 e.stopEvent();
98 break;
99 case e.DOWN:
100 this.showPrevYear();
101 e.stopEvent();
102 break;
103 case e.UP:
104 this.showNextYear();
105 e.stopEvent();
106 break;
107 }
108 },
109
110 handleMouseWheel : function(e){
111 var delta = e.getWheelDelta();
112 if(delta > 0){
113 this.showPrevMonth();
114 e.stopEvent();
115 } else if(delta < 0){
116 this.showNextMonth();
117 e.stopEvent();
118 }
119 },
120
121 handleClick : function(e){
122 var d = this.visibleDate;
123 var t = e.getTarget();
124 if(t && t.className){
125 var cls = t.className.split(' ')[0];
126 switch(cls){
127 case 'active':
128 this.handleSelection(new Date(d.getFullYear(), d.getMonth(), parseInt(t.innerHTML)));
129 break;
130 case 'prevday':
131 var p = this.getPrevMonth(d);
132 this.handleSelection(new Date(p.getFullYear(), p.getMonth(), parseInt(t.innerHTML)));
133 break;
134 case 'nextday':
135 var n = this.getNextMonth(d);
136 this.handleSelection(new Date(n.getFullYear(), n.getMonth(), parseInt(t.innerHTML)));
137 break;
138 case 'ypopcal-today':
139 this.handleSelection(new Date());
140 break;
141 case 'next-month':
142 this.showNextMonth();
143 break;
144 case 'prev-month':
145 this.showPrevMonth();
146 break;
147 }
148 }
149 e.stopEvent();
150 },
151
152 selectToday : function(){
153 this.handleSelection(new Date());
154 },
155
156 handleSelection: function(date){
157 this.selectedDate = date;
158 this.callback(date);
159 this.hide();
160 },
161
162 getPrevMonth : function(d){
163 var m = d.getMonth();var y = d.getFullYear();
164 return (m == 0 ? new Date(--y, 11, 1) : new Date(y, --m, 1));
165 },
166
167 getNextMonth : function(d){
168 var m = d.getMonth();var y = d.getFullYear();
169 return (m == 11 ? new Date(++y, 0, 1) : new Date(y, ++m, 1));
170 },
171
172 getDaysInMonth : function(m, y){
173 return (m == 1 || m == 3 || m == 5 || m == 7 || m == 8 || m == 10 || m == 12) ? 31 : (m == 4 || m == 6 || m == 9 || m == 11) ? 30 : this.isLeapYear(y) ? 29 : 28;
174 },
175
176 isLeapYear : function(y){
177 return (((y % 4) == 0) && ((y % 100) != 0) || ((y % 400) == 0));
178 },
179
180 clearTime : function(date){
181 if(date){
182 date.setHours(0);
183 date.setMinutes(0);
184 date.setSeconds(0);
185 date.setMilliseconds(0);
186 }
187 return date;
188 },
189
190 refresh : function(){
191 var d = this.visibleDate;
192 this.buildInnerCal(d);
193 this.calHead.update(this.monthNames[d.getMonth()] + ' ' + d.getFullYear());
194 if(this.element.isVisible()){
195 this.shadow.setRegion(this.element.getRegion());
196 }
197 }
198};
199
200/**
201 * This code is not pretty, but it is fast!
202 * @ignore
203 */
204YAHOO.ext.DatePicker.prototype.buildControl = function(parentElement){
205 var c = document.createElement('div');
206 c.style.position = 'absolute';
207 c.style.visibility = 'hidden';
208 document.body.appendChild(c);
209 var html = '<iframe id="'+this.id+'_shdw" frameborder="0" class="ypopcal-shadow" src="'+YAHOO.ext.SSL_SECURE_URL+'"></iframe>' +
210 '<div hidefocus="true" class="ypopcal" id="'+this.id+'">' +
211 '<table class="ypopcal-head" border=0 cellpadding=0 cellspacing=0><tbody><tr><td class="ypopcal-arrow"><div class="prev-month">&#160;</div></td><td class="ypopcal-month">&#160;</td><td class="ypopcal-arrow"><div class="next-month">&#160;</div></td></tr></tbody></table>' +
212 '<center><div class="ypopcal-inner">';
213 html += "<table border=0 cellspacing=0 class=\"ypopcal-table\"><thead><tr class=\"ypopcal-daynames\">";
214 var names = this.dayNames;
215 for(var i = 0; i < names.length; i++){
216 html += '<td>' + names[i].substr(0, 1) + '</td>';
217 }
218 html+= "</tr></thead><tbody><tr>";
219 for(var i = 0; i < 42; i++) {
220 if(i % 7 == 0 && i != 0){
221 html += '</tr><tr>';
222 }
223 html += "<td>&nbsp;</td>";
224 }
225 html += "</tr></tbody></table>";
226 html += '</div><button class="ypopcal-today">'+this.todayText+'</button></center></div>';
227 c.innerHTML = html;
228 this.shadow = getEl(c.childNodes[0], true);
229 this.shadow.enableDisplayMode('block');
230 this.element = getEl(c.childNodes[1], true);
231 this.element.enableDisplayMode('block');
232 document.body.appendChild(this.shadow.dom);
233 document.body.appendChild(this.element.dom);
234 document.body.removeChild(c);
235 this.element.on("selectstart", function(){return false;});
236 var tbody = this.element.dom.getElementsByTagName('tbody')[1];
237 this.cells = tbody.getElementsByTagName('td');
238 this.calHead = this.element.getChildrenByClassName('ypopcal-month', 'td')[0];
239 this.element.mon('mousedown', this.handleClick, this, true);
240};
241
242YAHOO.ext.DatePicker.prototype.buildInnerCal = function(dateVal){
243 var days = this.getDaysInMonth(dateVal.getMonth() + 1, dateVal.getFullYear());
244 var firstOfMonth = new Date(dateVal.getFullYear(), dateVal.getMonth(), 1);
245 var startingPos = firstOfMonth.getDay();
246 if(startingPos == 0) startingPos = 7;
247 var pm = this.getPrevMonth(dateVal);
248 var prevStart = this.getDaysInMonth(pm.getMonth()+1, pm.getFullYear())-startingPos;
249 var cells = this.cells;
250 days += startingPos;
251
252 // convert everything to numbers so it's fast
253 var day = 86400000;
254 var date = this.clearTime(new Date(pm.getFullYear(), pm.getMonth(), prevStart));
255 var today = this.clearTime(new Date()).getTime();
256 var sel = this.selectedDate ? this.clearTime(this.selectedDate).getTime() : today + 1; //today +1 will never match anything
257 var min = this.minDate ? this.clearTime(this.minDate).getTime() : Number.NEGATIVE_INFINITY;
258 var max = this.maxDate ? this.clearTime(this.maxDate).getTime() : Number.POSITIVE_INFINITY;
259 var ddMatch = this.disabledDatesRE;
260 var ddText = this.disabledDatesText;
261 var ddays = this.disabledDays;
262 var ddaysText = this.disabledDaysText;
263 var format = this.format;
264
265 var setCellClass = function(cal, cell, d){
266 cell.title = '';
267 var t = d.getTime();
268 if(t == today){
269 cell.className += ' today';
270 cell.title = cal.todayText;
271 }
272 if(t == sel){
273 cell.className += ' selected';
274 }
275 // disabling
276 if(t < min) {
277 cell.className = ' ypopcal-disabled';
278 cell.title = cal.minText;
279 return;
280 }
281 if(t > max) {
282 cell.className = ' ypopcal-disabled';
283 cell.title = cal.maxText;
284 return;
285 }
286 if(ddays){
287 var day = d.getDay();
288 for(var i = 0; i < ddays.length; i++) {
289 if(day === ddays[i]){
290 cell.title = ddaysText;
291 cell.className = ' ypopcal-disabled';
292 return;
293 }
294 }
295 }
296 if(ddMatch && format){
297 var fvalue = d.format(format);
298 if(ddMatch.test(fvalue)){
299 cell.title = ddText.replace('%0', fvalue);
300 cell.className = ' ypopcal-disabled';
301 return;
302 }
303 }
304 };
305
306 var i = 0;
307 for(; i < startingPos; i++) {
308 cells[i].innerHTML = (++prevStart);
309 date.setDate(date.getDate()+1);
310 cells[i].className = 'prevday';
311 setCellClass(this, cells[i], date);
312 }
313 for(; i < days; i++){
314 intDay = i - startingPos + 1;
315 cells[i].innerHTML = (intDay);
316 date.setDate(date.getDate()+1);
317 cells[i].className = 'active';
318 setCellClass(this, cells[i], date);
319 }
320 var extraDays = 0;
321 for(; i < 42; i++) {
322 cells[i].innerHTML = (++extraDays);
323 date.setDate(date.getDate()+1);
324 cells[i].className = 'nextday';
325 setCellClass(this, cells[i], date);
326 }
327};
328
329YAHOO.ext.DatePicker.prototype.todayText = "Today";
330YAHOO.ext.DatePicker.prototype.minDate = null;
331YAHOO.ext.DatePicker.prototype.maxDate = null;
332YAHOO.ext.DatePicker.prototype.minText = "This date is before the minimum date";
333YAHOO.ext.DatePicker.prototype.maxText = "This date is after the maximum date";
334YAHOO.ext.DatePicker.prototype.format = 'm/d/y';
335YAHOO.ext.DatePicker.prototype.disabledDays = null;
336YAHOO.ext.DatePicker.prototype.disabledDaysText = '';
337YAHOO.ext.DatePicker.prototype.disabledDatesRE = null;
338YAHOO.ext.DatePicker.prototype.disabledDatesText = '';
339YAHOO.ext.DatePicker.prototype.constrainToViewport = true;
340
341
342YAHOO.ext.DatePicker.prototype.monthNames = Date.monthNames;
343
344YAHOO.ext.DatePicker.prototype.dayNames = Date.dayNames;
diff --git a/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js b/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js
new file mode 100644
index 0000000..a498faa
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/InlineEditor.js
@@ -0,0 +1,216 @@
1YAHOO.ext.InlineEditor = function(config, existingEl){
2 YAHOO.ext.util.Config.apply(this, config);
3 var dh = YAHOO.ext.DomHelper;
4 this.wrap = dh.append(this.container || document.body, {
5 tag:'div',
6 cls:'yinline-editor-wrap'
7 }, true);
8
9 this.textSizeEl = dh.append(document.body, {
10 tag: 'div',
11 cls: 'yinline-editor-sizer ' + (this.cls || '')
12 });
13 if(YAHOO.ext.util.Browser.isSafari){ // extra padding for safari's textboxes
14 this.textSizeEl.style.padding = '4px';
15 YAHOO.util.Dom.setStyle(this.textSizeEl, 'padding-right', '10px');
16 }
17
18 if(!YAHOO.ext.util.Browser.isGecko){ // no one else needs FireFox cursor fix
19 this.wrap.setStyle('overflow', 'hidden');
20 }
21
22 if(existingEl){
23 this.el = getEl(existingEl);
24 }
25 if(!this.el){
26 this.id = this.id || YAHOO.util.Dom.generateId();
27 if(!this.multiline){
28 this.el = this.wrap.createChild({
29 tag: 'input',
30 name: this.name || this.id,
31 id: this.id,
32 type: this.type || 'text',
33 autocomplete: 'off',
34 value: this.value || '',
35 cls: 'yinline-editor ' + (this.cls || ''),
36 maxlength: this.maxLength || ''
37 });
38 }else{
39 this.el = this.wrap.createChild({
40 tag: 'textarea',
41 name: this.name || this.id,
42 id: this.id,
43 html: this.value || '',
44 cls: 'yinline-editor yinline-editor-multiline ' + (this.cls || ''),
45 wrap: 'none'
46 });
47 }
48 }else{
49 this.wrap.dom.appendChild(this.el.dom);
50 }
51 this.el.addKeyMap([{
52 key: [10, 13],
53 fn: this.onEnter,
54 scope: this
55 },{
56 key: 27,
57 fn: this.onEsc,
58 scope: this
59 }]);
60 this.el.mon('keyup', this.onKeyUp, this, true);
61 this.el.on('blur', this.onBlur, this, true);
62 this.el.swallowEvent('keydown');
63 this.events = {
64 'startedit' : true,
65 'beforecomplete' : true,
66 'complete' : true
67 };
68 this.editing = false;
69 this.autoSizeTask = new YAHOO.ext.util.DelayedTask(this.autoSize, this);
70};
71
72YAHOO.extendX(YAHOO.ext.InlineEditor, YAHOO.ext.util.Observable, {
73 onEnter : function(k, e){
74 if(this.multiline && (e.ctrlKey || e.shiftKey)){
75 return;
76 }else{
77 this.completeEdit();
78 e.stopEvent();
79 }
80 },
81
82 onEsc : function(){
83 if(this.ignoreNoChange){
84 this.revert(true);
85 }else{
86 this.revert(false);
87 this.completeEdit();
88 }
89 },
90
91 onBlur : function(){
92 if(this.editing && this.completeOnBlur !== false){
93 this.completeEdit();
94 }
95 },
96
97 startEdit : function(el, value){
98 this.boundEl = YAHOO.util.Dom.get(el);
99 if(this.hideEl !== false){
100 this.boundEl.style.visibility = 'hidden';
101 }
102 var v = value || this.boundEl.innerHTML;
103 this.startValue = v;
104 this.setValue(v);
105 this.moveTo(YAHOO.util.Dom.getXY(this.boundEl));
106 this.editing = true;
107 if(YAHOO.ext.QuickTips){
108 YAHOO.ext.QuickTips.disable();
109 }
110 this.show.defer(10, this);
111 },
112
113 onKeyUp : function(e){
114 var k = e.getKey();
115 if(this.editing && (k < 33 || k > 40) && k != 27){
116 this.autoSizeTask.delay(50);
117 }
118 },
119
120 completeEdit : function(){
121 var v = this.getValue();
122 if(this.revertBlank !== false && v.length < 1){
123 v = this.startValue;
124 this.revert();
125 }
126 if(v == this.startValue && this.ignoreNoChange){
127 this.hide();
128 }
129 if(this.fireEvent('beforecomplete', this, v, this.startValue) !== false){
130 if(this.updateEl !== false && this.boundEl){
131 this.boundEl.innerHTML = v;
132 }
133 this.hide();
134 this.fireEvent('complete', this, v, this.startValue);
135 }
136 },
137
138 revert : function(hide){
139 this.setValue(this.startValue);
140 if(hide){
141 this.hide();
142 }
143 },
144
145 show : function(){
146 this.autoSize();
147 this.wrap.show();
148 this.el.focus();
149 if(this.selectOnEdit !== false){
150 this.el.dom.select();
151 }
152 },
153
154 hide : function(){
155 this.editing = false;
156 this.wrap.hide();
157 this.wrap.setLeftTop(-10000,-10000);
158 this.el.blur();
159 if(this.hideEl !== false){
160 this.boundEl.style.visibility = 'visible';
161 }
162 if(YAHOO.ext.QuickTips){
163 YAHOO.ext.QuickTips.enable();
164 }
165 },
166
167 setValue : function(v){
168 this.el.dom.value = v;
169 },
170
171 getValue : function(){
172 return this.el.dom.value;
173 },
174
175 autoSize : function(){
176 var el = this.el;
177 var wrap = this.wrap;
178 var v = el.dom.value;
179 var ts = this.textSizeEl;
180 if(v.length < 1){
181 ts.innerHTML = "&#160;&#160;";
182 }else{
183 v = v.replace(/[<> ]/g, '&#160;');
184 if(this.multiline){
185 v = v.replace(/\n/g, '<br />&#160;');
186 }
187 ts.innerHTML = v;
188 }
189 var ww = wrap.dom.offsetWidth;
190 var wh = wrap.dom.offsetHeight;
191 var w = ts.offsetWidth;
192 var h = ts.offsetHeight;
193 // lots of magic numbers in this block - wtf?
194 // the logic is to prevent the scrollbars from flashing
195 // in firefox. Updates the right element first
196 // so there's never overflow.
197 if(ww > w+4){
198 el.setWidth(w+4);
199 wrap.setWidth(w+8);
200 }else{
201 wrap.setWidth(w+8);
202 el.setWidth(w+4);
203 }
204 if(wh > h+4){
205 el.setHeight(h);
206 wrap.setHeight(h+4);
207 }else{
208 wrap.setHeight(h+4);
209 el.setHeight(h);
210 }
211 },
212
213 moveTo : function(xy){
214 this.wrap.setXY(xy);
215 }
216});
diff --git a/frontend/beta/js/YUI-extensions/widgets/MessageBox.js b/frontend/beta/js/YUI-extensions/widgets/MessageBox.js
new file mode 100644
index 0000000..01b168d
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/MessageBox.js
@@ -0,0 +1,230 @@
1YAHOO.ext.MessageBox = function(){
2 var dlg, opt, mask;
3 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4 var buttons, activeTextEl, bwidth;
5
6 var handleButton = function(button){
7 if(typeof opt.fn == 'function'){
8 if(opt.fn.call(opt.scope||window, button, activeTextEl.dom.value) !== false){
9 dlg.hide();
10 }
11 }else{
12 dlg.hide();
13 }
14 };
15 var updateButtons = function(b){
16 var width = 0;
17 if(!b){
18 buttons['ok'].hide();
19 buttons['cancel'].hide();
20 buttons['yes'].hide();
21 buttons['no'].hide();
22 return width;
23 }
24 for(var k in buttons){
25 if(typeof buttons[k] != 'function'){
26 if(b[k]){
27 buttons[k].show();
28 buttons[k].setText(typeof b[k] == 'string' ? b[k] : YAHOO.ext.MessageBox.buttonText[k]);
29 width += buttons[k].el.getWidth()+15;
30 }else{
31 buttons[k].hide();
32 }
33 }
34 }
35 return width;
36 };
37
38 return {
39 getDialog : function(){
40 if(!dlg){
41 dlg = new YAHOO.ext.BasicDialog('mb-dlg', {
42 autoCreate : true,
43 shadow: true,
44 draggable: true,
45 resizable:false,
46 constraintoviewport:true,
47 fixedcenter:true,
48 shim:true,
49 modal: true,
50 width:400, height:100,
51 buttonAlign:'center',
52 closeClick : function(){
53 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
54 handleButton('no');
55 }else{
56 handleButton('cancel');
57 }
58 }
59 });
60 dlg.closeClick = function(){
61 alert('wtf');
62 };
63 mask = dlg.mask;
64 dlg.addKeyListener(27, dlg.hide, dlg);
65 buttons = {};
66 buttons['ok'] = dlg.addButton(this.buttonText['ok'], handleButton.createCallback('ok'));
67 buttons['yes'] = dlg.addButton(this.buttonText['yes'], handleButton.createCallback('yes'));
68 buttons['no'] = dlg.addButton(this.buttonText['no'], handleButton.createCallback('no'));
69 buttons['cancel'] = dlg.addButton(this.buttonText['cancel'], handleButton.createCallback('cancel'));
70 bodyEl = dlg.body.createChild({
71 tag:'div',
72 html:'<span class="ext-mb-text"></span><br /><input type="text" class="ext-mb-input"><textarea class="ext-mb-textarea"></textarea><div class="ext-mb-progress-wrap"><div class="ext-mb-progress"><div class="ext-mb-progress-bar">&#160;</div></div></div>'
73 });
74 msgEl = bodyEl.dom.firstChild;
75 textboxEl = getEl(bodyEl.dom.childNodes[2]);
76 textboxEl.enableDisplayMode();
77 textboxEl.addKeyListener([10,13], function(){
78 if(dlg.isVisible() && opt && opt.buttons){
79 if(opt.buttons.ok){
80 handleButton('ok');
81 }else if(opt.buttons.yes){
82 handleButton('yes');
83 }
84 }
85 });
86 textareaEl = getEl(bodyEl.dom.childNodes[3]);
87 textareaEl.enableDisplayMode();
88 progressEl = getEl(bodyEl.dom.childNodes[4]);
89 progressEl.enableDisplayMode();
90 pp = getEl(progressEl.dom.firstChild.firstChild);
91 }
92 return dlg;
93 },
94
95 updateText : function(text){
96 if(!dlg.isVisible() && !opt.width){
97 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
98 }
99 msgEl.innerHTML = text;
100 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
101 Math.max(opt.minWidth || this.minWidth, bwidth));
102 if(opt.prompt){
103 activeTextEl.setWidth(w);
104 }
105 dlg.setContentSize(w, bodyEl.getHeight());
106 },
107
108 updateProgress : function(value, text){
109 if(text){
110 this.updateText(text);
111 }
112 pp.setWidth(value*progressEl.dom.firstChild.offsetWidth);
113 },
114
115 isVisible : function(){
116 return dlg && dlg.isVisible();
117 },
118
119 hide : function(){
120 if(this.isVisible()){
121 dlg.hide();
122 }
123 },
124
125 show : function(options){
126 var d = this.getDialog();
127 opt = options;
128 d.setTitle(opt.title || '&#160;');
129 d.close.setDisplayed(opt.closable !== false);
130 activeTextEl = textboxEl;
131 opt.prompt = opt.prompt || (opt.multiline ? true : false)
132 if(opt.prompt){
133 if(opt.multiline){
134 textboxEl.hide();
135 textareaEl.show();
136 textareaEl.setHeight(typeof opt.multiline == 'number' ?
137 opt.multiline : this.defaultTextHeight);
138 activeTextEl = textareaEl;
139 }else{
140 textboxEl.show();
141 textareaEl.hide();
142 }
143 }else{
144 textboxEl.hide();
145 textareaEl.hide();
146 }
147 progressEl.setDisplayed(opt.progress === true);
148 this.updateProgress(0);
149 activeTextEl.dom.value = opt.value || '';
150 if(opt.prompt){
151 dlg.setDefaultButton(activeTextEl);
152 }else{
153 var bs = opt.buttons;
154 var db = null;
155 if(bs && bs.ok){
156 db = buttons['ok'];
157 }else if(bs && bs.yes){
158 db = buttons['yes'];
159 }
160 dlg.setDefaultButton(db);
161 }
162 bwidth = updateButtons(opt.buttons);
163 this.updateText(opt.msg);
164 d.modal = opt.modal !== false;
165 d.mask = opt.modal !== false ? mask : false;
166 d.animateTarget = null;
167 d.show(options.animEl);
168 },
169
170 progress : function(title, msg){
171 this.show({
172 title : title,
173 msg : msg,
174 buttons: false,
175 progress:true,
176 closable:false
177 });
178 },
179
180 alert : function(title, msg, fn, scope){
181 this.show({
182 title : title,
183 msg : msg,
184 buttons: this.OK,
185 fn: fn,
186 scope : scope
187 });
188 },
189
190 confirm : function(title, msg, fn, scope){
191 this.show({
192 title : title,
193 msg : msg,
194 buttons: this.YESNO,
195 fn: fn,
196 scope : scope
197 });
198 },
199
200 prompt : function(title, msg, fn, scope, multiline){
201 this.show({
202 title : title,
203 msg : msg,
204 buttons: this.OKCANCEL,
205 fn: fn,
206 minWidth:250,
207 scope : scope,
208 prompt:true,
209 multiline: multiline
210 });
211 },
212
213 OK : {ok:true},
214 YESNO : {yes:true, no:true},
215 OKCANCEL : {ok:true, cancel:true},
216 YESNOCANCEL : {yes:true, no:true, cancel:true},
217
218 defaultTextHeight:75,
219 maxWidth : 500,
220 minWidth : 100,
221 buttonText : {
222 ok : 'OK',
223 cancel : 'Cancel',
224 yes : 'Yes',
225 no : 'No'
226 }
227 };
228}();
229
230YAHOO.ext.Msg = YAHOO.ext.MessageBox;
diff --git a/frontend/beta/js/YUI-extensions/widgets/QuickTips.js b/frontend/beta/js/YUI-extensions/widgets/QuickTips.js
new file mode 100644
index 0000000..6658574
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/QuickTips.js
@@ -0,0 +1,311 @@
1/**
2 * @class YAHOO.ext.QuickTips
3 * @singleton
4 */
5YAHOO.ext.QuickTips = function(){
6 var el, tipBody, tipTitle, tm, cfg, close, tagEls = {}, reader, esc, anim, removeCls = null;
7 var ce, bd, xy;
8 var visible = false, disabled = true, inited = false;
9 var showProc = hideProc = dismissProc = 1, locks = [];
10 var E = YAHOO.util.Event, dd;
11
12 var onOver = function(e){
13 if(disabled){
14 return;
15 }
16 var t = E.getTarget(e);
17 if(!t){
18 return;
19 }
20 if(ce && t == ce.el){
21 clearTimeout(hideProc);
22 return;
23 }
24 if(t && tagEls[t.id]){
25 tagEls[t.id].el = t;
26 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
27 return;
28 }
29 var ttp = reader.getAttribute(t, cfg.attribute);
30 if(!ttp && tm.interceptTitles && t.title){
31 ttp = t.title;
32 t.title = '';
33 if(reader.useNS){
34 t.setAttributeNS('y', 'qtip', ttp);
35 }else{
36 t.setAttribute('qtip', ttp);
37 }
38 }
39 if(ttp){
40 xy = E.getXY(e);
41 xy[0] += 12; xy[1] += 20;
42 showProc = show.defer(tm.showDelay, tm, [{
43 el: t,
44 text: ttp,
45 width: reader.getAttribute(t, cfg.width),
46 autoHide: reader.getAttribute(t, cfg.hide) != 'user',
47 title: reader.getAttribute(t, cfg.title),
48 cls: reader.getAttribute(t, cfg.cls)
49 }]);
50 }
51 };
52
53 var onOut = function(e){
54 clearTimeout(showProc);
55 var t = E.getTarget(e);
56 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
57 hideProc = setTimeout(hide, tm.hideDelay);
58 }
59 };
60
61 var onMove = function(e){
62 if(disabled){
63 return;
64 }
65 xy = E.getXY(e);
66 xy[0] += 12; xy[1] += 20;
67 if(tm.trackMouse && ce){
68 el.setXY(xy);
69 }
70 };
71
72 var onDown = function(e){
73 clearTimeout(showProc);
74 clearTimeout(hideProc);
75 if(!e.within(el)){
76 if(tm.hideOnClick && ce && ce.autoHide !== false){
77 hide();
78 tm.disable();
79 }
80 }
81 };
82
83 var onUp = function(e){
84 tm.enable();
85 }
86
87 var show = function(o){
88 if(disabled){
89 return;
90 }
91 clearTimeout(dismissProc);
92 stopAnim();
93 ce = o;
94 if(removeCls){ // in case manually hidden
95 el.removeClass(removeCls);
96 removeCls = null;
97 }
98 if(ce.cls){
99 el.addClass(ce.cls);
100 removeCls = ce.cls;
101 }
102 if(ce.title){
103 tipTitleText.update(ce.title);
104 tipTitle.show();
105 }else{
106 tipTitle.hide();
107 }
108 tipBody.update(o.text);
109 if(!ce.width){
110 if(tipBody.dom.style.width){
111 tipBody.dom.style.width = '';
112 }
113 if(tipBody.dom.offsetWidth > tm.maxWidth){
114 tipBody.setWidth(tm.maxWidth);
115 }
116 }else{
117 tipBody.setWidth(ce.width);
118 }
119 if(!ce.autoHide){
120 close.setDisplayed(true);
121 if(dd){
122 dd.unlock();
123 }
124 }else{
125 close.setDisplayed(false);
126 if(dd){
127 dd.lock();
128 }
129 }
130 if(xy){
131 el.setXY(xy);
132 }
133 if(tm.animate){
134 anim.attributes = {opacity:{to:1}};
135 el.setOpacity(.1);
136 el.setStyle('visibility', 'visible');
137 anim.animateX(afterShow);
138 }else{
139 afterShow();
140 }
141 };
142
143 var afterShow = function(){
144 if(ce){
145 el.show();
146 esc.enable();
147 if(tm.autoDismiss && ce.autoHide !== false){
148 dismissProc = setTimeout(hide, tm.autoDismissDelay);
149 }
150 }
151 }
152
153 var hide = function(noanim){
154 clearTimeout(dismissProc);
155 clearTimeout(hideProc);
156 ce = null;
157 if(el.isVisible()){
158 esc.disable();
159 stopAnim();
160 if(noanim !== true && tm.animate){
161 anim.attributes = {opacity:{to:.1}};
162 el.beforeAction();
163 anim.animateX(afterHide);
164 }else{
165 afterHide();
166 }
167 }
168 };
169
170 var afterHide = function(){
171 el.hide();
172 if(removeCls){
173 el.removeClass(removeCls);
174 removeCls = null;
175 }
176 }
177
178 var stopAnim = function(){
179 if(anim && anim.isAnimated()){
180 anim.stop();
181 }
182 }
183
184 return {
185 init : function(){
186 if(YAHOO.ext.util.Browser.isIE && !YAHOO.ext.util.Browser.isIE7){
187 return;
188 }
189 tm = YAHOO.ext.QuickTips;
190 cfg = tm.tagConfig;
191 reader = new YAHOO.ext.CustomTagReader(cfg.namespace);
192 if(!inited){
193 el = new YAHOO.ext.Layer({cls:'ytip', shadow:true, useDisplay: false});
194 el.update('<div class="ytip-hd-left"><div class="ytip-hd-right"><div class="ytip-hd"></div></div></div>');
195 tipTitle = getEl(el.dom.firstChild);
196 tipTitleText = getEl(el.dom.firstChild.firstChild.firstChild);
197 tipTitle.enableDisplayMode('block');
198 tipBody = el.createChild({tag:'div', cls:'ytip-bd'});
199 close = el.createChild({tag:'div', cls:'ytip-close'});
200 close.on('click', hide);
201 d = getEl(document);
202 d.mon('mousedown', onDown);
203 d.on('mouseup', onUp);
204 d.on('mouseover', onOver);
205 d.on('mouseout', onOut);
206 d.on('mousemove', onMove);
207 esc = d.addKeyListener(27, hide);
208 esc.disable();
209 if(tm.animate){
210 anim = new YAHOO.util.Anim(el.dom, {}, .1);
211 }
212 if(YAHOO.util.DD){
213 dd = el.initDD('default', null, {
214 onDrag : function(){
215 el.sync();
216 }
217 });
218 dd.setHandleElId(tipTitleText.id);
219 dd.lock();
220 }
221 inited = true;
222 }
223 this.scan(document.body);
224 this.enable();
225 },
226
227 tips : function(config){
228 var cs = config instanceof Array ? config : arguments;
229 for(var i = 0, len = cs.length; i < len; i++) {
230 var c = cs[i];
231 var target = c.target;
232 if(target){
233 if(target instanceof Array){
234 for(var j = 0, jlen = target.length; j < jlen; j++){
235 tagEls[target[j]] = c;
236 }
237 }else{
238 tagEls[target] = c;
239 }
240 }
241 }
242 },
243
244 enable : function(){
245 if(inited){
246 locks.pop();
247 if(locks.length < 1){
248 disabled = false;
249 }
250 }
251 },
252
253 disable : function(){
254 disabled = true;
255 clearTimeout(showProc);
256 clearTimeout(hideProc);
257 clearTimeout(dismissProc);
258 if(ce){
259 hide(true);
260 }
261 locks.push(1);
262 },
263
264 scan : function(toScan){
265 toScan = toScan.dom ? toScan.dom : YAHOO.util.Dom.get(toScan);
266 var found = [];
267 reader.eachElement(cfg.tag, toScan, function(el){
268 var t = reader.getAttribute(el, cfg.target);
269 if(t){
270 found.push({
271 target: t.indexOf(',') != -1 ? t.split(',') : t,
272 text: el.innerHTML,
273 autoHide: reader.getAttribute(el, cfg.hide) != 'user',
274 width: reader.getAttribute(el, cfg.width),
275 title: reader.getAttribute(el, cfg.title),
276 cls: reader.getAttribute(el, cfg.cls)
277 });
278 }
279 el.parentNode.removeChild(el);
280 });
281 this.tips(found);
282 },
283
284 tagConfig : {
285 namespace : 'y',
286 tag : 'qtip',
287 attribute : 'qtip',
288 width : 'width',
289 target : 'target',
290 title : 'qtitle',
291 hide : 'hide',
292 cls : 'qclass'
293 },
294
295 maxWidth : 300,
296 interceptTitles : true,
297 trackMouse : false,
298 hideOnClick : true,
299 showDelay : 500,
300 hideDelay : 200,
301 autoHide : true,
302 autoDismiss : true,
303 autoDismissDelay : 5000,
304 /**
305 * True to turn on fade animation. Defaults to true
306 * except in IE7 (ClearType/scrollbar flicker issues in IE7 with filters).
307 * @type Boolean
308 */
309 animate : YAHOO.util.Anim && !YAHOO.ext.util.Browser.isIE7
310 }
311}();
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
diff --git a/frontend/beta/js/YUI-extensions/widgets/SplitBar.js b/frontend/beta/js/YUI-extensions/widgets/SplitBar.js
new file mode 100644
index 0000000..855d138
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/SplitBar.js
@@ -0,0 +1,468 @@
1/*
2 * splitbar.js, version .7
3 * Copyright(c) 2006, Jack Slocum.
4 * Code licensed under the BSD License
5 */
6if(YAHOO.util.DragDropMgr){
7 YAHOO.util.DragDropMgr.clickTimeThresh = 350;
8}
9/**
10 * @class YAHOO.ext.SplitBar
11 * @extends YAHOO.ext.util.Observable
12 * Creates draggable splitter bar functionality from two elements.
13 * <br><br>
14 * Usage:
15 * <pre><code>
16var split = new YAHOO.ext.SplitBar('elementToDrag', 'elementToSize',
17 YAHOO.ext.SplitBar.HORIZONTAL, YAHOO.ext.SplitBar.LEFT);
18split.setAdapter(new YAHOO.ext.SplitBar.AbsoluteLayoutAdapter("container"));
19split.minSize = 100;
20split.maxSize = 600;
21split.animate = true;
22split.onMoved.subscribe(splitterMoved);
23</code></pre>
24 * @requires YAHOO.ext.Element
25 * @requires YAHOO.util.Dom
26 * @requires YAHOO.util.Event
27 * @requires YAHOO.util.CustomEvent
28 * @requires YAHOO.util.DDProxy
29 * @requires YAHOO.util.Anim (optional) to support animation
30 * @requires YAHOO.util.Easing (optional) to support animation
31 * @constructor
32 * Create a new SplitBar
33 * @param {String/HTMLElement/Element} dragElement The element to be dragged and act as the SplitBar.
34 * @param {String/HTMLElement/Element} resizingElement The element to be resized based on where the SplitBar element is dragged
35 * @param {Number} orientation (optional) Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36 * @param {Number} placement (optional) Either YAHOO.ext.SplitBar.LEFT or YAHOO.ext.SplitBar.RIGHT for horizontal or
37 YAHOO.ext.SplitBar.TOP or YAHOO.ext.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the intial position
38 position of the SplitBar).
39 */
40YAHOO.ext.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
41
42 /** @private */
43 this.el = YAHOO.ext.Element.get(dragElement, true);
44 this.el.dom.unselectable = 'on';
45 /** @private */
46 this.resizingEl = YAHOO.ext.Element.get(resizingElement, true);
47
48 /**
49 * @private
50 * The orientation of the split. Either YAHOO.ext.SplitBar.HORIZONTAL or YAHOO.ext.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
51 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
52 * @type Number
53 */
54 this.orientation = orientation || YAHOO.ext.SplitBar.HORIZONTAL;
55
56 /**
57 * The minimum size of the resizing element. (Defaults to 0)
58 * @type Number
59 */
60 this.minSize = 0;
61
62 /**
63 * The maximum size of the resizing element. (Defaults to 2000)
64 * @type Number
65 */
66 this.maxSize = 2000;
67
68 this.onMoved = new YAHOO.util.CustomEvent("SplitBarMoved", this);
69
70 /**
71 * Whether to animate the transition to the new size
72 * @type Boolean
73 */
74 this.animate = false;
75
76 /**
77 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
78 * @type Boolean
79 */
80 this.useShim = false;
81
82 /** @private */
83 this.shim = null;
84
85 if(!existingProxy){
86 /** @private */
87 this.proxy = YAHOO.ext.SplitBar.createProxy(this.orientation);
88 }else{
89 this.proxy = getEl(existingProxy).dom;
90 }
91 /** @private */
92 this.dd = new YAHOO.util.DDProxy(this.el.dom.id, "SplitBars", {dragElId : this.proxy.id});
93
94 /** @private */
95 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
96
97 /** @private */
98 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
99
100 /** @private */
101 this.dragSpecs = {};
102
103 /**
104 * @private The adapter to use to positon and resize elements
105 */
106 this.adapter = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
107 this.adapter.init(this);
108
109 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
110 /** @private */
111 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? YAHOO.ext.SplitBar.LEFT : YAHOO.ext.SplitBar.RIGHT);
112 this.el.setStyle('cursor', 'e-resize');
113 }else{
114 /** @private */
115 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? YAHOO.ext.SplitBar.TOP : YAHOO.ext.SplitBar.BOTTOM);
116 this.el.setStyle('cursor', 'n-resize');
117 }
118
119 this.events = {
120 /**
121 * @event resize
122 * Fires when the splitter is moved (alias for moved)
123 * @param {YAHOO.ext.SplitBar} this
124 * @param {Number} newSize the new width or height
125 */
126 'resize' : this.onMoved,
127 /**
128 * @event moved
129 * Fires when the splitter is moved
130 * @param {YAHOO.ext.SplitBar} this
131 * @param {Number} newSize the new width or height
132 */
133 'moved' : this.onMoved,
134 /**
135 * @event beforeresize
136 * Fires before the splitter is dragged
137 * @param {YAHOO.ext.SplitBar} this
138 */
139 'beforeresize' : new YAHOO.util.CustomEvent('beforeresize')
140 }
141}
142
143YAHOO.extendX(YAHOO.ext.SplitBar, YAHOO.ext.util.Observable, {
144 onStartProxyDrag : function(x, y){
145 this.fireEvent('beforeresize', this);
146 if(this.useShim){
147 if(!this.shim){
148 this.shim = YAHOO.ext.SplitBar.createShim();
149 }
150 this.shim.setVisible(true);
151 }
152 YAHOO.util.Dom.setStyle(this.proxy, 'display', 'block');
153 var size = this.adapter.getElementSize(this);
154 this.activeMinSize = this.getMinimumSize();;
155 this.activeMaxSize = this.getMaximumSize();;
156 var c1 = size - this.activeMinSize;
157 var c2 = Math.max(this.activeMaxSize - size, 0);
158 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
159 this.dd.resetConstraints();
160 this.dd.setXConstraint(
161 this.placement == YAHOO.ext.SplitBar.LEFT ? c1 : c2,
162 this.placement == YAHOO.ext.SplitBar.LEFT ? c2 : c1
163 );
164 this.dd.setYConstraint(0, 0);
165 }else{
166 this.dd.resetConstraints();
167 this.dd.setXConstraint(0, 0);
168 this.dd.setYConstraint(
169 this.placement == YAHOO.ext.SplitBar.TOP ? c1 : c2,
170 this.placement == YAHOO.ext.SplitBar.TOP ? c2 : c1
171 );
172 }
173 this.dragSpecs.startSize = size;
174 this.dragSpecs.startPoint = [x, y];
175
176 YAHOO.util.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
177 },
178
179 /**
180 * @private Called after the drag operation by the DDProxy
181 */
182 onEndProxyDrag : function(e){
183 YAHOO.util.Dom.setStyle(this.proxy, 'display', 'none');
184 var endPoint = YAHOO.util.Event.getXY(e);
185 if(this.useShim){
186 this.shim.setVisible(false);
187 }
188 var newSize;
189 if(this.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
190 newSize = this.dragSpecs.startSize +
191 (this.placement == YAHOO.ext.SplitBar.LEFT ?
192 endPoint[0] - this.dragSpecs.startPoint[0] :
193 this.dragSpecs.startPoint[0] - endPoint[0]
194 );
195 }else{
196 newSize = this.dragSpecs.startSize +
197 (this.placement == YAHOO.ext.SplitBar.TOP ?
198 endPoint[1] - this.dragSpecs.startPoint[1] :
199 this.dragSpecs.startPoint[1] - endPoint[1]
200 );
201 }
202 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
203 if(newSize != this.dragSpecs.startSize){
204 this.adapter.setElementSize(this, newSize);
205 this.onMoved.fireDirect(this, newSize);
206 }
207 },
208
209 /**
210 * Get the adapter this SplitBar uses
211 * @return The adapter object
212 */
213 getAdapter : function(){
214 return this.adapter;
215 },
216
217 /**
218 * Set the adapter this SplitBar uses
219 * @param {Object} adapter A SplitBar adapter object
220 */
221 setAdapter : function(adapter){
222 this.adapter = adapter;
223 this.adapter.init(this);
224 },
225
226 /**
227 * Gets the minimum size for the resizing element
228 * @return {Number} The minimum size
229 */
230 getMinimumSize : function(){
231 return this.minSize;
232 },
233
234 /**
235 * Sets the minimum size for the resizing element
236 * @param {Number} minSize The minimum size
237 */
238 setMinimumSize : function(minSize){
239 this.minSize = minSize;
240 },
241
242 /**
243 * Gets the maximum size for the resizing element
244 * @return {Number} The maximum size
245 */
246 getMaximumSize : function(){
247 return this.maxSize;
248 },
249
250 /**
251 * Sets the maximum size for the resizing element
252 * @param {Number} maxSize The maximum size
253 */
254 setMaximumSize : function(maxSize){
255 this.maxSize = maxSize;
256 },
257
258 /**
259 * Sets the initialize size for the resizing element
260 * @param {Number} size The initial size
261 */
262 setCurrentSize : function(size){
263 var oldAnimate = this.animate;
264 this.animate = false;
265 this.adapter.setElementSize(this, size);
266 this.animate = oldAnimate;
267 },
268
269 /**
270 * Destroy this splitbar.
271 * @param {Boolean} removeEl True to remove the element
272 */
273 destroy : function(removeEl){
274 if(this.shim){
275 this.shim.remove();
276 }
277 this.dd.unreg();
278 this.proxy.parentNode.removeChild(this.proxy);
279 if(removeEl){
280 this.el.remove();
281 }
282 }
283});
284
285/**
286 * @private static Create the shim to drag over iframes
287 */
288YAHOO.ext.SplitBar.createShim = function(){
289 var shim = document.createElement('div');
290 shim.unselectable = 'on';
291 YAHOO.util.Dom.generateId(shim, 'split-shim');
292 YAHOO.util.Dom.setStyle(shim, 'width', '100%');
293 YAHOO.util.Dom.setStyle(shim, 'height', '100%');
294 YAHOO.util.Dom.setStyle(shim, 'position', 'absolute');
295 YAHOO.util.Dom.setStyle(shim, 'background', 'white');
296 YAHOO.util.Dom.setStyle(shim, 'z-index', 11000);
297 window.document.body.appendChild(shim);
298 var shimEl = YAHOO.ext.Element.get(shim);
299 shimEl.setOpacity(.01);
300 shimEl.setXY([0, 0]);
301 return shimEl;
302};
303
304/**
305 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
306 */
307YAHOO.ext.SplitBar.createProxy = function(orientation){
308 var proxy = document.createElement('div');
309 proxy.unselectable = 'on';
310 YAHOO.util.Dom.generateId(proxy, 'split-proxy');
311 YAHOO.util.Dom.setStyle(proxy, 'position', 'absolute');
312 YAHOO.util.Dom.setStyle(proxy, 'visibility', 'hidden');
313 YAHOO.util.Dom.setStyle(proxy, 'z-index', 11001);
314 YAHOO.util.Dom.setStyle(proxy, 'background-color', "#aaa");
315 if(orientation == YAHOO.ext.SplitBar.HORIZONTAL){
316 YAHOO.util.Dom.setStyle(proxy, 'cursor', 'e-resize');
317 }else{
318 YAHOO.util.Dom.setStyle(proxy, 'cursor', 'n-resize');
319 }
320 // the next 2 fix IE abs position div height problem
321 YAHOO.util.Dom.setStyle(proxy, 'line-height', '0px');
322 YAHOO.util.Dom.setStyle(proxy, 'font-size', '0px');
323 window.document.body.appendChild(proxy);
324 return proxy;
325};
326
327/**
328 * @class YAHOO.ext.SplitBar.BasicLayoutAdapter
329 * Default Adapter. It assumes the splitter and resizing element are not positioned
330 * elements and only gets/sets the width of the element. Generally used for table based layouts.
331 */
332YAHOO.ext.SplitBar.BasicLayoutAdapter = function(){
333};
334
335YAHOO.ext.SplitBar.BasicLayoutAdapter.prototype = {
336 // do nothing for now
337 init : function(s){
338
339 },
340 /**
341 * Called before drag operations to get the current size of the resizing element.
342 * @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
343 */
344 getElementSize : function(s){
345 if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
346 return s.resizingEl.getWidth();
347 }else{
348 return s.resizingEl.getHeight();
349 }
350 },
351
352 /**
353 * Called after drag operations to set the size of the resizing element.
354 * @param {YAHOO.ext.SplitBar} s The SplitBar using this adapter
355 * @param {Number} newSize The new size to set
356 * @param {Function} onComplete A function to be invoke when resizing is complete
357 */
358 setElementSize : function(s, newSize, onComplete){
359 if(s.orientation == YAHOO.ext.SplitBar.HORIZONTAL){
360 if(!YAHOO.util.Anim || !s.animate){
361 s.resizingEl.setWidth(newSize);
362 if(onComplete){
363 onComplete(s, newSize);
364 }
365 }else{
366 s.resizingEl.setWidth(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
367 }
368 }else{
369
370 if(!YAHOO.util.Anim || !s.animate){
371 s.resizingEl.setHeight(newSize);
372 if(onComplete){
373 onComplete(s, newSize);
374 }
375 }else{
376 s.resizingEl.setHeight(newSize, true, .1, onComplete, YAHOO.util.Easing.easeOut);
377 }
378 }
379 }
380};
381
382/**
383 *@class YAHOO.ext.SplitBar.AbsoluteLayoutAdapter
384 * @extends YAHOO.ext.SplitBar.BasicLayoutAdapter
385 * Adapter that moves the splitter element to align with the resized sizing element.
386 * Used with an absolute positioned SplitBar.
387 * @param {String/HTMLElement/Element} container The container that wraps around the absolute positioned content. If it's
388 * document.body, make sure you assign an id to the body element.
389 */
390YAHOO.ext.SplitBar.AbsoluteLayoutAdapter = function(container){
391 this.basic = new YAHOO.ext.SplitBar.BasicLayoutAdapter();
392 this.container = getEl(container);
393}
394
395YAHOO.ext.SplitBar.AbsoluteLayoutAdapter.prototype = {
396 init : function(s){
397 this.basic.init(s);
398 //YAHOO.util.Event.on(window, 'resize', this.moveSplitter.createDelegate(this, [s]));
399 },
400
401 getElementSize : function(s){
402 return this.basic.getElementSize(s);
403 },
404
405 setElementSize : function(s, newSize, onComplete){
406 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
407 },
408
409 moveSplitter : function(s){
410 var yes = YAHOO.ext.SplitBar;
411 switch(s.placement){
412 case yes.LEFT:
413 s.el.setX(s.resizingEl.getRight());
414 break;
415 case yes.RIGHT:
416 s.el.setStyle('right', (this.container.getWidth() - s.resizingEl.getLeft()) + 'px');
417 break;
418 case yes.TOP:
419 s.el.setY(s.resizingEl.getBottom());
420 break;
421 case yes.BOTTOM:
422 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
423 break;
424 }
425 }
426};
427
428/**
429 * Orientation constant - Create a vertical SplitBar
430 * @static
431 * @type Number
432 */
433YAHOO.ext.SplitBar.VERTICAL = 1;
434
435/**
436 * Orientation constant - Create a horizontal SplitBar
437 * @static
438 * @type Number
439 */
440YAHOO.ext.SplitBar.HORIZONTAL = 2;
441
442/**
443 * Placement constant - The resizing element is to the left of the splitter element
444 * @static
445 * @type Number
446 */
447YAHOO.ext.SplitBar.LEFT = 1;
448
449/**
450 * Placement constant - The resizing element is to the right of the splitter element
451 * @static
452 * @type Number
453 */
454YAHOO.ext.SplitBar.RIGHT = 2;
455
456/**
457 * Placement constant - The resizing element is positioned above the splitter element
458 * @static
459 * @type Number
460 */
461YAHOO.ext.SplitBar.TOP = 3;
462
463/**
464 * Placement constant - The resizing element is positioned under splitter element
465 * @static
466 * @type Number
467 */
468YAHOO.ext.SplitBar.BOTTOM = 4;
diff --git a/frontend/beta/js/YUI-extensions/widgets/TabPanel.js b/frontend/beta/js/YUI-extensions/widgets/TabPanel.js
new file mode 100644
index 0000000..25fd142
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TabPanel.js
@@ -0,0 +1,756 @@
1/**
2 * @class YAHOO.ext.TabPanel
3 * @extends YAHOO.ext.util.Observable
4 * Creates a lightweight TabPanel component using Yahoo! UI.
5 * <br><br>
6 * Usage:
7 * <pre><code>
8 <font color="#008000">// basic tabs 1, built from existing content</font>
9 var tabs = new YAHOO.ext.TabPanel('tabs1');
10 tabs.addTab('script', "View Script");
11 tabs.addTab('markup', "View Markup");
12 tabs.activate('script');
13
14 <font color="#008000">// more advanced tabs, built from javascript</font>
15 var jtabs = new YAHOO.ext.TabPanel('jtabs');
16 jtabs.addTab('jtabs-1', "Normal Tab", "My content was added during construction.");
17
18 <font color="#008000">// set up the UpdateManager</font>
19 var tab2 = jtabs.addTab('jtabs-2', "Ajax Tab 1");
20 var updater = tab2.getUpdateManager();
21 updater.setDefaultUrl('ajax1.htm');
22 tab2.onActivate.subscribe(updater.refresh, updater, true);
23
24 <font color="#008000">// Use setUrl for Ajax loading</font>
25 var tab3 = jtabs.addTab('jtabs-3', "Ajax Tab 2");
26 tab3.setUrl('ajax2.htm', null, true);
27
28 <font color="#008000">// Disabled tab</font>
29 var tab4 = jtabs.addTab('tabs1-5', "Disabled Tab", "Can't see me cause I'm disabled");
30 tab4.disable();
31
32 jtabs.activate('jtabs-1');
33}
34 * </code></pre>
35 * @requires YAHOO.ext.Element
36 * @requires YAHOO.ext.UpdateManager
37 * @requires YAHOO.util.Dom
38 * @requires YAHOO.util.Event
39 * @requires YAHOO.util.CustomEvent
40 * @requires YAHOO.util.Connect (optional)
41 * @constructor
42 * Create new TabPanel.
43 * @param {String/HTMLElement/Element} container The id, DOM element or YAHOO.ext.Element container where this TabPanel is to be rendered.
44 * @param {Boolean} config Config object to set any properties for this TabPanel or true to render the tabs on the bottom.
45 */
46YAHOO.ext.TabPanel = function(container, config){
47 /**
48 * The container element for this TabPanel.
49 * @type YAHOO.ext.Element
50 */
51 this.el = getEl(container, true);
52 /** The position of the tabs. Can be 'top' or 'bottom' @type String */
53 this.tabPosition = 'top';
54 this.currentTabWidth = 0;
55 /** The minimum width of a tab (ignored if resizeTabs is not true). @type Number */
56 this.minTabWidth = 40;
57 /** The maximum width of a tab (ignored if resizeTabs is not true). @type Number */
58 this.maxTabWidth = 250;
59 /** The preferred (default) width of a tab (ignored if resizeTabs is not true). @type Number */
60 this.preferredTabWidth = 175;
61 /** Set this to true to enable dynamic tab resizing. @type Boolean */
62 this.resizeTabs = false;
63 /** Set this to true to turn on window resizing monitoring (ignored if resizeTabs is not true). @type Boolean */
64 this.monitorResize = true;
65
66 if(config){
67 if(typeof config == 'boolean'){
68 this.tabPosition = config ? 'bottom' : 'top';
69 }else{
70 YAHOO.ext.util.Config.apply(this, config);
71 }
72 }
73 if(this.tabPosition == 'bottom'){
74 this.bodyEl = getEl(this.createBody(this.el.dom));
75 this.el.addClass('ytabs-bottom');
76 }
77 this.stripWrap = getEl(this.createStrip(this.el.dom), true);
78 this.stripEl = getEl(this.createStripList(this.stripWrap.dom), true);
79 this.stripBody = getEl(this.stripWrap.dom.firstChild.firstChild, true);
80 if(YAHOO.ext.util.Browser.isIE){
81 YAHOO.util.Dom.setStyle(this.stripWrap.dom.firstChild, 'overflow-x', 'hidden');
82 }
83 if(this.tabPosition != 'bottom'){
84 /** The body element that contains TabPaneItem bodies.
85 * @type YAHOO.ext.Element
86 */
87 this.bodyEl = getEl(this.createBody(this.el.dom));
88 this.el.addClass('ytabs-top');
89 }
90 this.items = [];
91
92 this.bodyEl.setStyle('position', 'relative');
93
94 // add indexOf to array if it isn't present
95 if(!this.items.indexOf){
96 this.items.indexOf = function(o){
97 for(var i = 0, len = this.length; i < len; i++){
98 if(this[i] == o) return i;
99 }
100 return -1;
101 }
102 }
103 this.active = null;
104 this.onTabChange = new YAHOO.util.CustomEvent('TabItem.onTabChange');
105 this.activateDelegate = this.activate.createDelegate(this);
106
107 this.events = {
108 /**
109 * @event tabchange
110 * Fires when the active tab changes
111 * @param {YAHOO.ext.TabPanel} this
112 * @param {YAHOO.ext.TabPanelItem} activePanel The new active tab
113 */
114 'tabchange': this.onTabChange,
115 /**
116 * @event beforetabchange
117 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
118 * @param {YAHOO.ext.TabPanel} this
119 * @param {Object} e Set cancel to true on this object to cancel the tab change
120 * @param {YAHOO.ext.TabPanelItem} tab The tab being changed to
121 */
122 'beforetabchange' : new YAHOO.util.CustomEvent('beforechange')
123 };
124
125 YAHOO.ext.EventManager.onWindowResize(this.onResize, this, true);
126 this.cpad = this.el.getPadding('lr');
127 this.hiddenCount = 0;
128}
129
130YAHOO.ext.TabPanel.prototype = {
131 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
132 on : YAHOO.ext.util.Observable.prototype.on,
133 addListener : YAHOO.ext.util.Observable.prototype.addListener,
134 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
135 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
136 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
137 /**
138 * Creates a new TabPanelItem by looking for an existing element with the provided id - if it's not found it creates one.
139 * @param {String} id The id of the div to use <b>or create</b>
140 * @param {String} text The text for the tab
141 * @param {<i>String</i>} content (optional) Content to put in the TabPanelItem body
142 * @param {<i>Boolean</i>} closable (optional) True to create a close icon on the tab
143 * @return {YAHOO.ext.TabPanelItem} The created TabPanelItem
144 */
145 addTab : function(id, text, content, closable){
146 var item = new YAHOO.ext.TabPanelItem(this, id, text, closable);
147 this.addTabItem(item);
148 if(content){
149 item.setContent(content);
150 }
151 return item;
152 },
153
154 /**
155 * Returns the TabPanelItem with the specified id/index
156 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
157 * @return {YAHOO.ext.TabPanelItem}
158 */
159 getTab : function(id){
160 return this.items[id];
161 },
162
163 /**
164 * Hides the TabPanelItem with the specified id/index
165 * @param {String/Number} id The id or index of the TabPanelItem to hide.
166 */
167 hideTab : function(id){
168 var t = this.items[id];
169 if(!t.isHidden()){
170 t.setHidden(true);
171 this.hiddenCount++;
172 this.autoSizeTabs();
173 }
174 },
175
176 /**
177 * "Unhides" the TabPanelItem with the specified id/index
178 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
179 */
180 unhideTab : function(id){
181 var t = this.items[id];
182 if(t.isHidden()){
183 t.setHidden(false);
184 this.hiddenCount--;
185 this.autoSizeTabs();
186 }
187 },
188
189 /**
190 * Add an existing TabPanelItem.
191 * @param {YAHOO.ext.TabPanelItem} item The TabPanelItem to add
192 */
193 addTabItem : function(item){
194 this.items[item.id] = item;
195 this.items.push(item);
196 if(this.resizeTabs){
197 item.setWidth(this.currentTabWidth || this.preferredTabWidth)
198 this.autoSizeTabs();
199 }else{
200 item.autoSize();
201 }
202 },
203
204 /**
205 * Remove a TabPanelItem.
206 * @param {String/Number} id The id or index of the TabPanelItem to remove.
207 */
208 removeTab : function(id){
209 var items = this.items;
210 var tab = items[id];
211 if(!tab) return;
212 var index = items.indexOf(tab);
213 if(this.active == tab && items.length > 1){
214 var newTab = this.getNextAvailable(index);
215 if(newTab)newTab.activate();
216 }
217 this.stripEl.dom.removeChild(tab.pnode.dom);
218 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
219 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
220 }
221 items.splice(index, 1);
222 delete this.items[tab.id];
223 tab.fireEvent('close', tab);
224 tab.purgeListeners();
225 this.autoSizeTabs();
226 },
227
228 getNextAvailable : function(start){
229 var items = this.items;
230 var index = start;
231 // look for a next tab that will slide over to
232 // replace the one being removed
233 while(index < items.length){
234 var item = items[++index];
235 if(item && !item.isHidden()){
236 return item;
237 }
238 }
239 // if one isn't found select the previous tab (on the left)
240 var index = start;
241 while(index >= 0){
242 var item = items[--index];
243 if(item && !item.isHidden()){
244 return item;
245 }
246 }
247 return null;
248 },
249
250 /**
251 * Disable a TabPanelItem. <b>It cannot be the active tab, if it is this call is ignored.</b>.
252 * @param {String/Number} id The id or index of the TabPanelItem to disable.
253 */
254 disableTab : function(id){
255 var tab = this.items[id];
256 if(tab && this.active != tab){
257 tab.disable();
258 }
259 },
260
261 /**
262 * Enable a TabPanelItem that is disabled.
263 * @param {String/Number} id The id or index of the TabPanelItem to enable.
264 */
265 enableTab : function(id){
266 var tab = this.items[id];
267 tab.enable();
268 },
269
270 /**
271 * Activate a TabPanelItem. The currently active will be deactivated.
272 * @param {String/Number} id The id or index of the TabPanelItem to activate.
273 */
274 activate : function(id){
275 var tab = this.items[id];
276 if(tab == this.active){
277 return tab;
278 }
279 var e = {};
280 this.fireEvent('beforetabchange', this, e, tab);
281 if(e.cancel !== true && !tab.disabled){
282 if(this.active){
283 this.active.hide();
284 }
285 this.active = this.items[id];
286 this.active.show();
287 this.onTabChange.fireDirect(this, this.active);
288 }
289 return tab;
290 },
291
292 /**
293 * Get the active TabPanelItem
294 * @return {YAHOO.ext.TabPanelItem} The active TabPanelItem or null if none are active.
295 */
296 getActiveTab : function(){
297 return this.active;
298 },
299
300 /**
301 * Updates the tab body element to fit the height of the container element
302 * for overflow scrolling
303 * @param {Number} targetHeight (optional) Override the starting height from the elements height
304 */
305 syncHeight : function(targetHeight){
306 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth('tb')-this.el.getPadding('tb');
307 var bm = this.bodyEl.getMargins();
308 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
309 this.bodyEl.setHeight(newHeight);
310 return newHeight;
311 },
312
313 onResize : function(){
314 if(this.monitorResize){
315 this.autoSizeTabs();
316 }
317 },
318
319 /**
320 * Disables tab resizing while tabs are being added (if resizeTabs is false this does nothing)
321 */
322 beginUpdate : function(){
323 this.updating = true;
324 },
325
326 /**
327 * Stops an update and resizes the tabs (if resizeTabs is false this does nothing)
328 */
329 endUpdate : function(){
330 this.updating = false;
331 this.autoSizeTabs();
332 },
333
334 /**
335 * Manual call to resize the tabs (if resizeTabs is false this does nothing)
336 */
337 autoSizeTabs : function(){
338 var count = this.items.length;
339 var vcount = count - this.hiddenCount;
340 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
341 var w = Math.max(this.el.getWidth() - this.cpad, 10);
342 var availWidth = Math.floor(w / vcount);
343 var b = this.stripBody;
344 if(b.getWidth() > w){
345 var tabs = this.items;
346 this.setTabWidth(Math.max(availWidth, this.minTabWidth));
347 if(availWidth < this.minTabWidth){
348 /*if(!this.sleft){ // incomplete scrolling code
349 this.createScrollButtons();
350 }
351 this.showScroll();
352 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
353 }
354 }else{
355 if(this.currentTabWidth < this.preferredTabWidth){
356 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth));
357 }
358 }
359 },
360
361 /**
362 * Returns the number of tabs
363 * @return {Number}
364 */
365 getCount : function(){
366 return this.items.length;
367 },
368
369 /**
370 * Resizes all the tabs to the passed width
371 * @param {Number} The new width
372 */
373 setTabWidth : function(width){
374 this.currentTabWidth = width;
375 for(var i = 0, len = this.items.length; i < len; i++) {
376 if(!this.items[i].isHidden())this.items[i].setWidth(width);
377 }
378 },
379
380 /**
381 * Destroys this TabPanel
382 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well
383 */
384 destroy : function(removeEl){
385 YAHOO.ext.EventManager.removeResizeListener(this.onResize, this);
386 for(var i = 0, len = this.items.length; i < len; i++){
387 this.items[i].purgeListeners();
388 }
389 if(removeEl === true){
390 this.el.update('');
391 this.el.remove();
392 }
393 }
394};
395
396/**
397* @class YAHOO.ext.TabPanelItem
398* @extends YAHOO.ext.util.Observable
399*/
400YAHOO.ext.TabPanelItem = function(tabPanel, id, text, closable){
401 /**
402 * The TabPanel this TabPanelItem belongs to
403 * @type YAHOO.ext.TabPanel
404 */
405 this.tabPanel = tabPanel;
406 /**
407 * The id for this TabPanelItem
408 * @type String
409 */
410 this.id = id;
411 /** @private */
412 this.disabled = false;
413 /** @private */
414 this.text = text;
415 /** @private */
416 this.loaded = false;
417 this.closable = closable;
418
419 /**
420 * The body element for this TabPanelItem
421 * @type YAHOO.ext.Element
422 */
423 this.bodyEl = getEl(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
424 this.bodyEl.setVisibilityMode(YAHOO.ext.Element.VISIBILITY);
425 this.bodyEl.setStyle('display', 'block');
426 this.bodyEl.setStyle('zoom', '1');
427 this.hideAction();
428
429 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
430 /** @private */
431 this.el = getEl(els.el, true);
432 this.inner = getEl(els.inner, true);
433 this.textEl = getEl(this.el.dom.firstChild.firstChild.firstChild, true);
434 this.pnode = getEl(els.el.parentNode, true);
435 this.el.mon('click', this.onTabClick, this, true);
436 /** @private */
437 if(closable){
438 var c = getEl(els.close, true);
439 c.dom.title = this.closeText;
440 c.addClassOnOver('close-over');
441 c.mon('click', this.closeClick, this, true);
442 }
443
444 // these two are now private and deprecated
445 this.onActivate = new YAHOO.util.CustomEvent('TabItem.onActivate');
446 this.onDeactivate = new YAHOO.util.CustomEvent('TabItem.onDeactivate');
447
448 this.events = {
449 /**
450 * @event activate
451 * Fires when this tab becomes the active tab
452 * @param {YAHOO.ext.TabPanel} tabPanel
453 * @param {YAHOO.ext.TabPanelItem} this
454 */
455 'activate': this.onActivate,
456 /**
457 * @event beforeclose
458 * Fires before this tab is closed. To cancal the close, set cancel to true on e. (e.cancel = true)
459 * @param {YAHOO.ext.TabPanelItem} this
460 * @param {Object} e Set cancel to true on this object to cancel the close.
461 */
462 'beforeclose': new YAHOO.util.CustomEvent('beforeclose'),
463 /**
464 * @event close
465 * Fires when this tab is closed
466 * @param {YAHOO.ext.TabPanelItem} this
467 */
468 'close': new YAHOO.util.CustomEvent('close'),
469 /**
470 * @event deactivate
471 * Fires when this tab is no longer the active tab
472 * @param {YAHOO.ext.TabPanel} tabPanel
473 * @param {YAHOO.ext.TabPanelItem} this
474 */
475 'deactivate' : this.onDeactivate
476 };
477 this.hidden = false;
478};
479
480YAHOO.ext.TabPanelItem.prototype = {
481 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
482 on : YAHOO.ext.util.Observable.prototype.on,
483 addListener : YAHOO.ext.util.Observable.prototype.addListener,
484 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
485 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
486 purgeListeners : function(){
487 YAHOO.ext.util.Observable.prototype.purgeListeners.call(this);
488 this.el.removeAllListeners();
489 },
490 /**
491 * Show this TabPanelItem - this <b>does not</b> deactivate the currently active TabPanelItem.
492 */
493 show : function(){
494 this.pnode.addClass('on');
495 this.showAction();
496 if(YAHOO.ext.util.Browser.isOpera){
497 this.tabPanel.stripWrap.repaint();
498 }
499 this.onActivate.fireDirect(this.tabPanel, this);
500 },
501
502 /**
503 * Returns true if this tab is the active tab
504 * @return {Boolean}
505 */
506 isActive : function(){
507 return this.tabPanel.getActiveTab() == this;
508 },
509
510 /**
511 * Hide this TabPanelItem - if you don't activate another TabPanelItem this could look odd.
512 */
513 hide : function(){
514 this.pnode.removeClass('on');
515 this.hideAction();
516 this.onDeactivate.fireDirect(this.tabPanel, this);
517 },
518
519 hideAction : function(){
520 this.bodyEl.setStyle('position', 'absolute');
521 this.bodyEl.setLeft('-20000px');
522 this.bodyEl.setTop('-20000px');
523 this.bodyEl.hide();
524 },
525
526 showAction : function(){
527 this.bodyEl.setStyle('position', 'relative');
528 this.bodyEl.setTop('');
529 this.bodyEl.setLeft('');
530 this.bodyEl.show();
531 this.tabPanel.el.repaint.defer(1);
532 },
533
534 /**
535 * Set the tooltip (title attribute) for the tab
536 * @param {String} tooltip
537 */
538 setTooltip : function(text){
539 this.textEl.dom.title = text;
540 },
541
542 onTabClick : function(e){
543 e.preventDefault();
544 this.tabPanel.activate(this.id);
545 },
546
547 getWidth : function(){
548 return this.inner.getWidth();
549 },
550
551 setWidth : function(width){
552 var iwidth = width - this.pnode.getPadding("lr");
553 this.inner.setWidth(iwidth);
554 this.textEl.setWidth(iwidth-this.inner.getPadding('lr'));
555 this.pnode.setWidth(width);
556 },
557
558 setHidden : function(hidden){
559 this.hidden = hidden;
560 this.pnode.setStyle('display', hidden ? 'none' : '');
561 },
562
563 /**
564 * Returns true if this tab is "hidden"
565 * @return {Boolean}
566 */
567 isHidden : function(){
568 return this.hidden;
569 },
570
571 /**
572 * Returns the text for this tab
573 * @return {String}
574 */
575 getText : function(){
576 return this.text;
577 },
578
579 autoSize : function(){
580 this.el.beginMeasure();
581 this.textEl.setWidth(1);
582 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding('lr'));
583 this.el.endMeasure();
584 },
585
586 /**
587 * Sets the text for the tab (Note: this also sets the tooltip)
588 * @param {String} text
589 */
590 setText : function(text){
591 this.text = text;
592 this.textEl.update(text);
593 this.textEl.dom.title = text;
594 if(!this.tabPanel.resizeTabs){
595 this.autoSize();
596 }
597 },
598 /**
599 * Activate this TabPanelItem - this <b>does</b> deactivate the currently active TabPanelItem.
600 */
601 activate : function(){
602 this.tabPanel.activate(this.id);
603 },
604
605 /**
606 * Disable this TabPanelItem - this call is ignore if this is the active TabPanelItem.
607 */
608 disable : function(){
609 if(this.tabPanel.active != this){
610 this.disabled = true;
611 this.pnode.addClass('disabled');
612 }
613 },
614
615 /**
616 * Enable this TabPanelItem if it was previously disabled.
617 */
618 enable : function(){
619 this.disabled = false;
620 this.pnode.removeClass('disabled');
621 },
622
623 /**
624 * Set the content for this TabPanelItem.
625 * @param {String} content The content
626 * @param {Boolean} loadScripts true to look for and load scripts
627 */
628 setContent : function(content, loadScripts){
629 this.bodyEl.update(content, loadScripts);
630 },
631
632 /**
633 * Get the {@link YAHOO.ext.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
634 * @return {YAHOO.ext.UpdateManager} The UpdateManager
635 */
636 getUpdateManager : function(){
637 return this.bodyEl.getUpdateManager();
638 },
639
640 /**
641 * Set a URL to be used to load the content for this TabPanelItem.
642 * @param {String/Function} url The url to load the content from or a function to call to get the url
643 * @param {<i>String/Object</i>} params (optional) The string params for the update call or an object of the params. See {@link YAHOO.ext.UpdateManager#update} for more details. (Defaults to null)
644 * @param {<i>Boolean</i>} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
645 * @return {YAHOO.ext.UpdateManager} The UpdateManager
646 */
647 setUrl : function(url, params, loadOnce){
648 if(this.refreshDelegate){
649 this.onActivate.unsubscribe(this.refreshDelegate);
650 }
651 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
652 this.onActivate.subscribe(this.refreshDelegate);
653 return this.bodyEl.getUpdateManager();
654 },
655
656 /** @private */
657 _handleRefresh : function(url, params, loadOnce){
658 if(!loadOnce || !this.loaded){
659 var updater = this.bodyEl.getUpdateManager();
660 updater.update(url, params, this._setLoaded.createDelegate(this));
661 }
662 },
663
664 /**
665 * Force a content refresh from the URL specified in the setUrl() method.
666 * Will fail silently if the setUrl method has not been called.
667 * This does not activate the panel, just updates its content.
668 */
669 refresh : function(){
670 if(this.refreshDelegate){
671 this.loaded = false;
672 this.refreshDelegate();
673 }
674 },
675
676 /** @private */
677 _setLoaded : function(){
678 this.loaded = true;
679 },
680
681 /** @private */
682 closeClick : function(e){
683 var e = {};
684 this.fireEvent('beforeclose', this, e);
685 if(e.cancel !== true){
686 this.tabPanel.removeTab(this.id);
687 }
688 },
689 /**
690 * The text displayed in the tooltip for the close icon.
691 * @type String
692 */
693 closeText : 'Close this tab'
694};
695
696/** @private */
697YAHOO.ext.TabPanel.prototype.createStrip = function(container){
698 var strip = document.createElement('div');
699 strip.className = 'ytab-wrap';
700 container.appendChild(strip);
701 return strip;
702};
703/** @private */
704YAHOO.ext.TabPanel.prototype.createStripList = function(strip){
705 // div wrapper for retard IE
706 strip.innerHTML = '<div class="ytab-strip-wrap"><table class="ytab-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
707 return strip.firstChild.firstChild.firstChild.firstChild;
708};
709/** @private */
710YAHOO.ext.TabPanel.prototype.createBody = function(container){
711 var body = document.createElement('div');
712 YAHOO.util.Dom.generateId(body, 'tab-body');
713 YAHOO.util.Dom.addClass(body, 'yui-ext-tabbody');
714 container.appendChild(body);
715 return body;
716};
717/** @private */
718YAHOO.ext.TabPanel.prototype.createItemBody = function(bodyEl, id){
719 var body = YAHOO.util.Dom.get(id);
720 if(!body){
721 body = document.createElement('div');
722 body.id = id;
723 }
724 YAHOO.util.Dom.addClass(body, 'yui-ext-tabitembody');
725 bodyEl.insertBefore(body, bodyEl.firstChild);
726 return body;
727};
728/** @private */
729YAHOO.ext.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
730 var td = document.createElement('td');
731 stripEl.appendChild(td);
732 if(closable){
733 td.className = "ytab-closable";
734 if(!this.closeTpl){
735 this.closeTpl = new YAHOO.ext.Template(
736 '<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
737 '<span unselectable="on" title="{text}" class="ytab-text">{text}</span>' +
738 '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
739 );
740 }
741 var el = this.closeTpl.overwrite(td, {'text': text});
742 var close = el.getElementsByTagName('div')[0];
743 var inner = el.getElementsByTagName('em')[0];
744 return {'el': el, 'close': close, 'inner': inner};
745 } else {
746 if(!this.tabTpl){
747 this.tabTpl = new YAHOO.ext.Template(
748 '<a href="#" class="ytab-right"><span class="ytab-left"><em class="ytab-inner">' +
749 '<span unselectable="on" title="{text}" class="ytab-text">{text}</span></em></span></a>'
750 );
751 }
752 var el = this.tabTpl.overwrite(td, {'text': text});
753 var inner = el.getElementsByTagName('em')[0];
754 return {'el': el, 'inner': inner};
755 }
756};
diff --git a/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js b/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js
new file mode 100644
index 0000000..e69de29
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TaskPanel.js
diff --git a/frontend/beta/js/YUI-extensions/widgets/TemplateView.js b/frontend/beta/js/YUI-extensions/widgets/TemplateView.js
new file mode 100644
index 0000000..2100205
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/TemplateView.js
@@ -0,0 +1,766 @@
1/**
2 * @class YAHOO.ext.View
3 * @extends YAHOO.ext.util.Observable
4 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
5 * This class also supports single and multi selection modes. <br>
6 * Create a data model bound view:
7<pre><code>
8var dataModel = new YAHOO.ext.grid.XMLDataModel(...);
9var view = new YAHOO.ext.View('my-element',
10 '&lt;div id="{0}"&gt;{2} - {1}&lt;/div&gt;', // auto create template
11 dataModel, {
12 singleSelect: true,
13 selectedClass: 'ydataview-selected'
14 });
15
16// listen for node click?
17view.on('click', function(vw, index, node, e){
18 alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
19});
20
21// load XML data
22dataModel.load('foobar.xml');
23</code></pre>
24For an example of creating a JSON/UpdateManager view, see {@link YAHOO.ext.JsonView}.
25 * <br><br>
26 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27 * IE's limited insertion support with tables and Opera's faulty event bubbling.</b>
28 * @constructor
29 * Create a new View
30 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
31 * @param {String/DomHelper.Template} tpl The rendering template or a string to create a template with
32 * @param {DataModel} dataModel The bound data model
33 * @param {Object} config The config object
34*/
35YAHOO.ext.View = function(container, tpl, dataModel, config){
36 this.el = getEl(container, true);
37 this.nodes = this.el.dom.childNodes;
38 if(typeof tpl == 'string'){
39 tpl = new YAHOO.ext.Template(tpl);
40 }
41 tpl.compile();
42 /**
43 * The template used by this View
44 * @type {YAHOO.ext.DomHelper.Template}
45 */
46 this.tpl = tpl;
47 this.setDataModel(dataModel);
48 var CE = YAHOO.util.CustomEvent;
49 /** @private */
50 this.events = {
51 /**
52 * @event beforeclick
53 * Fires before a click is processed. Returns false to cancel the default action.
54 * @param {YAHOO.ext.View} this
55 * @param {Number} index The index of the target node
56 * @param {HTMLElement} node The target node
57 * @param {YAHOO.ext.EventObject} e The raw event object
58 */
59 'beforeclick' : true,
60 /**
61 * @event click
62 * Fires when a template node is clicked.
63 * @param {YAHOO.ext.View} this
64 * @param {Number} index The index of the target node
65 * @param {HTMLElement} node The target node
66 * @param {YAHOO.ext.EventObject} e The raw event object
67 */
68 'click' : true,
69 /**
70 * @event dblclick
71 * Fires when a template node is double clicked.
72 * @param {YAHOO.ext.View} this
73 * @param {Number} index The index of the target node
74 * @param {HTMLElement} node The target node
75 * @param {YAHOO.ext.EventObject} e The raw event object
76 */
77 'dblclick' : true,
78 /**
79 * @event contextmenu
80 * Fires when a template node is right clicked.
81 * @param {YAHOO.ext.View} this
82 * @param {Number} index The index of the target node
83 * @param {HTMLElement} node The target node
84 * @param {YAHOO.ext.EventObject} e The raw event object
85 */
86 'contextmenu' : true,
87 /**
88 * @event selectionchange
89 * Fires when the selected nodes change.
90 * @param {YAHOO.ext.View} this
91 * @param {Array} selections Array of the selected nodes
92 */
93 'selectionchange' : true,
94
95 /**
96 * @event beforeselect
97 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
98 * @param {YAHOO.ext.View} this
99 * @param {HTMLElement} node The node to be selected
100 * @param {Array} selections Array of currently selected nodes
101 */
102 'beforeselect' : true
103 };
104 this.el.mon("click", this.onClick, this, true);
105 this.el.mon("dblclick", this.onDblClick, this, true);
106 this.el.mon("contextmenu", this.onContextMenu, this, true);
107
108 /**
109 * The css class to add to selected nodes
110 * @type {YAHOO.ext.DomHelper.Template}
111 */
112 this.selectedClass = 'ydataview-selected';
113
114 this.emptyText = '';
115
116 this.selections = [];
117
118 this.lastSelection = null;
119
120 /**
121 * The root property in the loaded json object that contains the data
122 * @type {String}
123 */
124 this.jsonRoot = null;
125 YAHOO.ext.util.Config.apply(this, config);
126 if(this.renderUpdates || this.jsonRoot){
127 var um = this.el.getUpdateManager();
128 um.setRenderer(this);
129 }
130};
131
132YAHOO.extendX(YAHOO.ext.View, YAHOO.ext.util.Observable, {
133 /**
134 * Returns the element this view is bound to.
135 * @return {YAHOO.ext.Element}
136 */
137 getEl : function(){
138 return this.el;
139 },
140
141 render : function(el, response){
142 this.clearSelections();
143 this.el.update('');
144 var o;
145 try{
146 o = YAHOO.ext.util.JSON.decode(response.responseText);
147 if(this.jsonRoot){
148 o = eval('o.' + this.jsonRoot);
149 }
150 }catch(e){}
151 /**
152 * The current json data or null
153 */
154 this.jsonData = o;
155 this.beforeRender();
156 this.refresh();
157 },
158
159 beforeRender : function(){
160
161 },
162
163 /**
164 * Refreshes the view.
165 */
166 refresh : function(){
167 this.clearSelections();
168 this.el.update('');
169 this.html = [];
170 if(this.renderUpdates || this.jsonRoot){
171 var o = this.jsonData;
172 if(o){
173 for(var i = 0, len = o.length; i < len; i++) {
174 this.renderEach(o[i]);
175 }
176 }
177 }else{
178 this.dataModel.each(this.renderEach, this);
179 }
180 var strHtml;
181 if(this.html.length > 0){
182 strHtml = this.html.join('');
183 }else{
184 strHtml = this.emptyText;
185 }
186 this.el.update(strHtml);
187 this.html = null;
188 this.nodes = this.el.dom.childNodes;
189 this.updateIndexes(0);
190 },
191
192 /**
193 * Function to override to reformat the data that is sent to
194 * the template for each node.
195 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
196 * a JSON object for an UpdateManager bound view).
197 * @param {Number} index The index of the data within the data model
198 */
199 prepareData : function(data, index){
200 return data;
201 },
202
203 renderEach : function(data){
204 this.html[this.html.length] = this.tpl.applyTemplate(this.prepareData(data));
205 },
206
207 /**
208 * Refresh an individual node.
209 * @param {Number} index
210 */
211 refreshNode : function(index){
212 this.refreshNodes(index, index);
213 },
214
215 refreshNodes : function(dm, startIndex, endIndex){
216 this.clearSelections();
217 var dm = this.dataModel;
218 var ns = this.nodes;
219 for(var i = startIndex; i <= endIndex; i++){
220 var d = this.prepareData(dm.getRow(i), i);
221 if(i < ns.length-1){
222 var old = ns[i];
223 this.tpl.insertBefore(old, d);
224 this.el.dom.removeChild(old);
225 }else{
226 this.tpl.append(this.el.dom, d);
227 }
228 }
229 this.updateIndexes(startIndex, endIndex);
230 },
231
232 deleteNodes : function(dm, startIndex, endIndex){
233 this.clearSelections();
234 if(startIndex == 0 && endIndex >= this.nodes.length-1){
235 this.el.update('');
236 }else{
237 var el = this.el.dom;
238 for(var i = startIndex; i <= endIndex; i++){
239 el.removeChild(this.nodes[startIndex]);
240 }
241 this.updateIndexes(startIndex);
242 }
243 },
244
245 insertNodes : function(dm, startIndex, endIndex){
246 if(this.nodes.length == 0){
247 this.refresh();
248 }else{
249 this.clearSelections();
250 var t = this.tpl;
251 var before = this.nodes[startIndex];
252 var dm = this.dataModel;
253 if(before){
254 for(var i = startIndex; i <= endIndex; i++){
255 t.insertBefore(before, this.prepareData(dm.getRow(i), i));
256 }
257 }else{
258 var el = this.el.dom;
259 for(var i = startIndex; i <= endIndex; i++){
260 t.append(el, this.prepareData(dm.getRow(i), i));
261 }
262 }
263 this.updateIndexes(startIndex);
264 }
265 },
266
267 updateIndexes : function(dm, startIndex, endIndex){
268 var ns = this.nodes;
269 startIndex = startIndex || 0;
270 endIndex = endIndex || ns.length-1;
271 for(var i = startIndex; i <= endIndex; i++){
272 ns[i].nodeIndex = i;
273 }
274 },
275
276 /**
277 * Changes the data model this view uses and refresh the view.
278 * @param {DataModel} dataModel
279 */
280 setDataModel : function(dm){
281 if(!dm) return;
282 this.unplugDataModel(this.dataModel);
283 this.dataModel = dm;
284 dm.on('cellupdated', this.refreshNode, this, true);
285 dm.on('datachanged', this.refresh, this, true);
286 dm.on('rowsdeleted', this.deleteNodes, this, true);
287 dm.on('rowsinserted', this.insertNodes, this, true);
288 dm.on('rowsupdated', this.refreshNodes, this, true);
289 dm.on('rowssorted', this.refresh, this, true);
290 this.refresh();
291 },
292
293 /**
294 * Unplug the data model and stop updates.
295 * @param {DataModel} dataModel
296 */
297 unplugDataModel : function(dm){
298 if(!dm) return;
299 dm.removeListener('cellupdated', this.refreshNode, this);
300 dm.removeListener('datachanged', this.refresh, this);
301 dm.removeListener('rowsdeleted', this.deleteNodes, this);
302 dm.removeListener('rowsinserted', this.insertNodes, this);
303 dm.removeListener('rowsupdated', this.refreshNodes, this);
304 dm.removeListener('rowssorted', this.refresh, this);
305 this.dataModel = null;
306 },
307
308 /**
309 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
310 * @param {HTMLElement} node
311 * @return {HTMLElement} The template node
312 */
313 findItemFromChild : function(node){
314 var el = this.el.dom;
315 if(!node || node.parentNode == el){
316 return node;
317 }
318 var p = node.parentNode;
319 while(p && p != el){
320 if(p.parentNode == el){
321 return p;
322 }
323 p = p.parentNode;
324 }
325 return null;
326 },
327
328 /** @ignore */
329 onClick : function(e){
330 var item = this.findItemFromChild(e.getTarget());
331 if(item){
332 var index = this.indexOf(item);
333 if(this.onItemClick(item, index, e) !== false){
334 this.fireEvent('click', this, index, item, e);
335 }
336 }else{
337 this.clearSelections();
338 }
339 },
340
341 /** @ignore */
342 onContextMenu : function(e){
343 var item = this.findItemFromChild(e.getTarget());
344 if(item){
345 this.fireEvent('contextmenu', this, this.indexOf(item), item, e);
346 }
347 },
348
349 /** @ignore */
350 onDblClick : function(e){
351 var item = this.findItemFromChild(e.getTarget());
352 if(item){
353 this.fireEvent('dblclick', this, this.indexOf(item), item, e);
354 }
355 },
356
357 onItemClick : function(item, index, e){
358 if(this.fireEvent('beforeclick', this, index, item, e) !== false){
359 if(this.multiSelect || this.singleSelect){
360 if(this.multiSelect && e.shiftKey && this.lastSelection){
361 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
362 }else{
363 this.select(item, this.multiSelect && e.ctrlKey);
364 this.lastSelection = item;
365 }
366 e.preventDefault();
367 }
368 return true;
369 }else{
370 return false;
371 }
372 },
373
374 /**
375 * Get the number of selected nodes.
376 * @return {Number}
377 */
378 getSelectionCount : function(){
379 return this.selections.length;
380 },
381
382 /**
383 * Get the currently selected nodes.
384 * @return {Array} An array of HTMLElements
385 */
386 getSelectedNodes : function(){
387 return this.selections;
388 },
389
390 /**
391 * Get the indexes of the selected nodes.
392 * @return {Array}
393 */
394 getSelectedIndexes : function(){
395 var indexes = [];
396 for(var i = 0, len = this.selections.length; i < len; i++) {
397 indexes.push(this.selections[i].nodeIndex);
398 }
399 return indexes;
400 },
401
402 /**
403 * Clear all selections
404 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
405 */
406 clearSelections : function(suppressEvent){
407 if(this.multiSelect || this.singleSelect){
408 YAHOO.util.Dom.removeClass(this.selections, this.selectedClass);
409 this.selections = [];
410 if(!suppressEvent){
411 this.fireEvent('selectionchange', this, this.selections);
412 }
413 }
414 },
415
416 /**
417 * Returns true if the passed node is selected
418 * @param {HTMLElement/Number} node The node or node index
419 * @return {Boolean}
420 */
421 isSelected : function(node){
422 node = this.getNode(node);
423 var s = this.selections;
424 if(s.length < 1){
425 return false;
426 }
427 if(s.indexOf){
428 return s.indexOf(node) !== -1;
429 }else{
430 for(var i = 0, len = s.length; i < len; i++){
431 if (s[i] == node){
432 return true;
433 }
434 }
435 return false;
436 }
437 },
438
439 /**
440 * Selects nodes.
441 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
442 * @param {Boolean} keepExisting (optional) true to keep existing selections
443 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
444 */
445 select : function(nodeInfo, keepExisting, suppressEvent){
446 if(!keepExisting){
447 this.clearSelections(true);
448 }
449 if(nodeInfo instanceof Array){
450 for(var i = 0, len = nodeInfo.length; i < len; i++) {
451 this.select(nodeInfo[i], true, true);
452 }
453 }else{
454 var node = this.getNode(nodeInfo);
455 if(node && !this.isSelected(node)){
456 if(this.fireEvent('beforeselect', this, node, this.selections) !== false){
457 YAHOO.util.Dom.addClass(node, this.selectedClass);
458 this.selections.push(node);
459 }
460 }
461 }
462 if(!suppressEvent){
463 this.fireEvent('selectionchange', this, this.selections);
464 }
465 },
466
467 /**
468 * Gets a template node.
469 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
470 * @return {HTMLElement} The node or null if it wasn't found
471 */
472 getNode : function(nodeInfo){
473 if(typeof nodeInfo == 'object'){
474 return nodeInfo;
475 }else if(typeof nodeInfo == 'string'){
476 return document.getElementById(nodeInfo);
477 }else if(typeof nodeInfo == 'number'){
478 return this.nodes[nodeInfo];
479 }
480 return null;
481 },
482
483 /**
484 * Gets a range template nodes.
485 * @param {Number} startIndex
486 * @param {Number} endIndex
487 * @return {Array} An array of nodes
488 */
489 getNodes : function(start, end){
490 var ns = this.nodes;
491 start = start || 0;
492 end = typeof end == 'undefined' ? ns.length-1 : end;
493 var nodes = [];
494 if(start <= end){
495 for(var i = start; i <= end; i++) {
496 nodes.push(ns[i]);
497 }
498 }else{
499 for(var i = start; i >= end; i--) {
500 nodes.push(ns[i]);
501 }
502 }
503 return nodes;
504 },
505
506 /**
507 * Finds the index of the passed node
508 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
509 * @return {Number} The index of the node or -1
510 */
511 indexOf : function(node){
512 node = this.getNode(node);
513 if(typeof node.nodeIndex == 'number'){
514 return node.nodeIndex;
515 }
516 var ns = this.nodes;
517 for(var i = 0, len = ns.length; i < len; i++) {
518 if(ns[i] == node){
519 return i;
520 }
521 }
522 return -1;
523 }
524});
525
526/**
527 * @class YAHOO.ext.JsonView
528 * @extends YAHOO.ext.View
529 * Shortcut class to create a JSON + UpdateManager template view. Usage:
530<pre><code>
531var view = new YAHOO.ext.JsonView('my-element',
532 '&lt;div id="{id}"&gt;{foo} - {bar}&lt;/div&gt;', // auto create template
533 { multiSelect: true, jsonRoot: 'data' });
534
535// listen for node click?
536view.on('click', function(vw, index, node, e){
537 alert('Node "' + node.id + '" at index: ' + index + ' was clicked.');
538});
539
540// direct load of JSON data
541view.load('foobar.php');
542
543
544// Example from my blog list
545var tpl = new YAHOO.ext.Template(
546 '&lt;div class="entry"&gt;' +
547 '&lt;a class="entry-title" href="{link}"&gt;{title}&lt;/a&gt;' +
548 '&lt;h4&gt;{date} by {author} | {comments} Comments&lt;/h4&gt;{description}' +
549 '&lt;/div&gt;&lt;hr /&gt;'
550);
551
552var moreView = new YAHOO.ext.JsonView('entry-list', tpl, {
553 jsonRoot: 'posts'
554});
555moreView.on('beforerender', this.sortEntries, this, true);
556moreView.load({
557 url:'/blog/get-posts.php',
558 params: 'allposts=true',
559 text:'Loading Blog Entries...'
560});
561</code></pre>
562 * @constructor
563 * Create a new JsonView
564 * @param {String/HTMLElement/Element} container The container element where the view is to be rendered.
565 * @param {DomHelper.Template} tpl The rendering template
566 * @param {Object} config The config object
567 */
568YAHOO.ext.JsonView = function(container, tpl, config){
569 var cfg = config || {};
570 cfg.renderUpdates = true;
571 YAHOO.ext.JsonView.superclass.constructor.call(this, container, tpl, null, cfg);
572 /**
573 * @event beforerender
574 * Fires before rendering of the downloaded json data.
575 * @param {YAHOO.ext.View} this
576 * @param {Object} data The json data loaded
577 */
578 this.events['beforerender'] = true;
579 /**
580 * @event load
581 * Fires when data is loaded.
582 * @param {YAHOO.ext.View} this
583 * @param {Object} data The json data loaded
584 * @param {Object} response The raw Connect response object
585 */
586 this.events['load'] = true;
587 /**
588 * @event loadexception
589 * Fires when loading fails.
590 * @param {YAHOO.ext.View} this
591 * @param {Object} response The raw Connect response object
592 */
593 this.events['loadexception'] = true;
594 this.el.getUpdateManager().on('update', this.onLoad, this, true);
595 this.el.getUpdateManager().on('failure', this.onLoadException, this, true);
596};
597YAHOO.extendX(YAHOO.ext.JsonView, YAHOO.ext.View, {
598 /**
599 * Performs an async request, loading the JSON from the response. If params are specified it uses POST, otherwise it uses GET.
600 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
601<pre><code>
602view.load({
603 url: 'your-url.php',<br/>
604 params: {param1: 'foo', param2: 'bar'}, // or a URL encoded string<br/>
605 callback: yourFunction,<br/>
606 scope: yourObject, //(optional scope) <br/>
607 discardUrl: false, <br/>
608 nocache: false,<br/>
609 text: 'Loading...',<br/>
610 timeout: 30,<br/>
611 scripts: false<br/>
612});
613</code></pre>
614 * The only required property is url. The optional properties nocache, text and scripts
615 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
616 * @param {<i>String/Object</i>} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
617 * @param {<i>Function</i>} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
618 * @param {<i>Boolean</i>} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
619 */
620 load : function(){
621 var um = this.el.getUpdateManager();
622 um.update.apply(um, arguments);
623 },
624
625 /**
626 * Get the number of records in the current JSON dataset
627 * @return {Number}
628 */
629 getCount : function(){
630 return this.jsonData ? this.jsonData.length : 0;
631 },
632
633 /**
634 * Returns the JSON object for the specified node(s)
635 * @param {HTMLElement/Array} node The node or an array of nodes
636 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
637 * you get the JSON object for the node
638 */
639 getNodeData : function(node){
640 if(node instanceof Array){
641 var data = [];
642 for(var i = 0, len = node.length; i < len; i++){
643 data.push(this.getNodeData(node[i]));
644 }
645 return data;
646 }
647 return this.jsonData[this.indexOf(node)] || null;
648 },
649
650 beforeRender : function(){
651 this.snapshot = this.jsonData;
652 if(this.sortInfo){
653 this.sort.apply(this, this.sortInfo);
654 }
655 this.fireEvent('beforerender', this, this.jsonData);
656 },
657
658 onLoad : function(el, o){
659 this.fireEvent('load', this, this.jsonData, o);
660 },
661
662 onLoadException : function(el, o){
663 this.fireEvent('loadexception', this, o);
664 },
665
666 /**
667 * Filter the data by a specific property.
668 * @param {String} property A property on your JSON objects
669 * @param {String/RegExp} value Either string that the property values
670 * should start with or a RegExp to test against the property
671 */
672 filter : function(property, value){
673 if(this.jsonData){
674 var data = [];
675 var ss = this.snapshot;
676 if(typeof value == 'string'){
677 var vlen = value.length;
678 if(vlen == 0){
679 this.clearFilter();
680 return;
681 }
682 value = value.toLowerCase();
683 for(var i = 0, len = ss.length; i < len; i++){
684 var o = ss[i];
685 if(o[property].substr(0, vlen).toLowerCase() == value){
686 data.push(o);
687 }
688 }
689 }else if(value.exec){ // regex?
690 for(var i = 0, len = ss.length; i < len; i++){
691 var o = ss[i];
692 if(value.test(o[property])){
693 data.push(o);
694 }
695 }
696 }else{
697 return;
698 }
699 this.jsonData = data;
700 this.refresh();
701 }
702 },
703
704 /**
705 * Filter by a function. The passed function will be called with each
706 * object in the current dataset. If the function returns true, the value is kept
707 * otherwise it is filtered.
708 * @param {Function} fn
709 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
710 */
711 filterBy : function(fn, scope){
712 if(this.jsonData){
713 var data = [];
714 var ss = this.snapshot;
715 for(var i = 0, len = ss.length; i < len; i++){
716 var o = ss[i];
717 if(fn.call(scope|| this, o)){
718 data.push(o);
719 }
720 }
721 this.jsonData = data;
722 this.refresh();
723 }
724 },
725
726 /**
727 * Clears the current filter.
728 */
729 clearFilter : function(){
730 if(this.snapshot && this.jsonData != this.snapshot){
731 this.jsonData = this.snapshot;
732 this.refresh();
733 }
734 },
735
736
737 /**
738 * Sorts the data for this view and refreshes it.
739 * @param {String} property A property on your JSON objects to sort on
740 * @param {String} direction (optional) desc or asc (defaults to asc)
741 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
742 */
743 sort : function(property, dir, sortType){
744 this.sortInfo = Array.prototype.slice.call(arguments, 0);
745 if(this.jsonData){
746 var p = property;
747 var dsc = dir && dir.toLowerCase() == 'desc';
748 var f = function(o1, o2){
749 var v1 = sortType ? sortType(o1[p]) : o1[p];
750 var v2 = sortType ? sortType(o2[p]) : o2[p];;
751 if(v1 < v2){
752 return dsc ? +1 : -1;
753 }else if(v1 > v2){
754 return dsc ? -1 : +1;
755 }else{
756 return 0;
757 }
758 };
759 this.jsonData.sort(f);
760 this.refresh();
761 if(this.jsonData != this.snapshot){
762 this.snapshot.sort(f);
763 }
764 }
765 }
766});
diff --git a/frontend/beta/js/YUI-extensions/widgets/Toolbar.js b/frontend/beta/js/YUI-extensions/widgets/Toolbar.js
new file mode 100644
index 0000000..7c14753
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/widgets/Toolbar.js
@@ -0,0 +1,296 @@
1/**
2 * @class YAHOO.ext.Toolbar
3 * Basic Toolbar used by the Grid to create the paging toolbar. This class is reusable but functionality
4 * is limited. Look for more functionality in a future version.
5 * @constructor
6 * @param {String/HTMLElement/Element} container
7 * @param {Array} buttons (optional) array of button configs or elements to add
8 */
9 YAHOO.ext.Toolbar = function(container, buttons){
10 this.el = getEl(container, true);
11 var div = document.createElement('div');
12 div.className = 'ytoolbar';
13 var tb = document.createElement('table');
14 tb.border = 0;
15 tb.cellPadding = 0;
16 tb.cellSpacing = 0;
17 div.appendChild(tb);
18 var tbody = document.createElement('tbody');
19 tb.appendChild(tbody);
20 var tr = document.createElement('tr');
21 tbody.appendChild(tr);
22 this.el.dom.appendChild(div);
23 this.tr = tr;
24 if(buttons){
25 this.add.apply(this, buttons);
26 }
27};
28
29YAHOO.ext.Toolbar.prototype = {
30 /**
31 * Adds element(s) to the toolbar - this function takes a variable number of
32 * arguments of mixed type and adds them to the toolbar...
33 *
34 * @param {Mixed} arg If arg is a ToolbarButton, it is added. If arg is a string, it is wrapped
35 * in a ytb-text element and added unless the text is "separator" in which case a separator
36 * is added. Otherwise, it is assumed the element is an HTMLElement and it is added directly.
37 */
38 add : function(){
39 for(var i = 0; i < arguments.length; i++){
40 var el = arguments[i];
41 var td = document.createElement('td');
42 this.tr.appendChild(td);
43 if(el instanceof YAHOO.ext.ToolbarButton){
44 el.init(td);
45 }else if(el instanceof Array){
46 this.addButton(el);
47 }else if(typeof el == 'string'){
48 var span = document.createElement('span');
49 if(el == 'separator'){
50 span.className = 'ytb-sep';
51 }else{
52 span.innerHTML = el;
53 span.className = 'ytb-text';
54 }
55 td.appendChild(span);
56 }else if(typeof el == 'object' && el.nodeType){ // must be element?
57 td.appendChild(el);
58 }else if(typeof el == 'object'){ // must be button config?
59 this.addButton(el);
60 }
61 }
62 },
63
64 /**
65 * Returns the element for this toolbar
66 * @return {YAHOO.ext.Element}
67 */
68 getEl : function(){
69 return this.el;
70 },
71
72 /**
73 * Adds a separator
74 */
75 addSeparator : function(){
76 var td = document.createElement('td');
77 this.tr.appendChild(td);
78 var span = document.createElement('span');
79 span.className = 'ytb-sep';
80 td.appendChild(span);
81 },
82
83 /**
84 * Add a button (or buttons), see {@link YAHOO.ext.ToolbarButton} for more info on the config
85 * @param {Object/Array} config A button config or array of configs
86 * @return {YAHOO.ext.ToolbarButton/Array}
87 */
88 addButton : function(config){
89 if(config instanceof Array){
90 var buttons = [];
91 for(var i = 0, len = config.length; i < len; i++) {
92 buttons.push(this.addButton(config[i]));
93 }
94 return buttons;
95 }
96 var b = config;
97 if(!(config instanceof YAHOO.ext.ToolbarButton)){
98 b = new YAHOO.ext.ToolbarButton(config);
99 }
100 this.add(b);
101 return b;
102 },
103
104 /**
105 * Adds text to the toolbar
106 * @param {String} text The text to add
107 * @return {HTMLElement} The span element created which you can use to update the text.
108 */
109 addText : function(text){
110 var td = document.createElement('td');
111 this.tr.appendChild(td);
112 var span = document.createElement('span');
113 span.className = 'ytb-text';
114 span.innerHTML = text;
115 td.appendChild(span);
116 return span;
117 },
118
119 /**
120 * Inserts a button (or buttons) at the specified index
121 * @param {Number} index The index where the buttons are to be inserted
122 * @param {Object/Array} config A button config or array of configs
123 * @return {YAHOO.ext.ToolbarButton/Array}
124 */
125 insertButton : function(index, config){
126 if(config instanceof Array){
127 var buttons = [];
128 for(var i = 0, len = config.length; i < len; i++) {
129 buttons.push(this.insertButton(index + i, config[i]));
130 }
131 return buttons;
132 }
133 var b = new YAHOO.ext.ToolbarButton(config);
134 var td = document.createElement('td');
135 var nextSibling = this.tr.childNodes[index];
136 if (nextSibling)
137 this.tr.insertBefore(td, nextSibling);
138 else
139 this.tr.appendChild(td);
140 b.init(td);
141 return b;
142 }
143};
144
145/**
146 * @class YAHOO.ext.ToolbarButton
147 * A toolbar button. The config has the following options:
148 * <ul>
149 * <li>className - The CSS class for the button. Use this to attach a background image for an icon.</li>
150 * <li>text - The button's text</li>
151 * <li>tooltip - The buttons tooltip text</li>
152 * <li>click - function to call when the button is clicked</li>
153 * <li>mouseover - function to call when the mouse moves over the button</li>
154 * <li>mouseout - function to call when the mouse moves off the button</li>
155 * <li>scope - The scope of the above event handlers</li>
156 * <li></li>
157 * <li></li>
158 * @constructor
159 * @param {Object} config
160 */
161YAHOO.ext.ToolbarButton = function(config){
162 YAHOO.ext.util.Config.apply(this, config);
163};
164
165YAHOO.ext.ToolbarButton.prototype = {
166 /** @private */
167 init : function(appendTo){
168 var element = document.createElement('span');
169 element.className = 'ytb-button';
170 if(this.id){
171 element.id = this.id;
172 }
173 this.setDisabled(this.disabled === true);
174 var inner = document.createElement('span');
175 inner.className = 'ytb-button-inner ' + (this.className || this.cls);
176 inner.unselectable = 'on';
177 if(this.tooltip){
178 element.setAttribute('title', this.tooltip);
179 }
180 if(this.style){
181 YAHOO.ext.DomHelper.applyStyles(inner, this.style);
182 }
183 element.appendChild(inner);
184 appendTo.appendChild(element);
185 this.el = getEl(element, true);
186 this.el.unselectable();
187 inner.innerHTML = (this.text ? this.text : '&#160;');
188 this.inner = inner;
189 this.el.mon('click', this.onClick, this, true);
190 this.el.mon('mouseover', this.onMouseOver, this, true);
191 this.el.mon('mouseout', this.onMouseOut, this, true);
192 },
193
194 /**
195 * Sets this buttons click handler
196 * @param {Function} click The function to call when the button is clicked
197 * @param {Object} scope (optional) Scope for the function passed above
198 */
199 setHandler : function(click, scope){
200 this.click = click;
201 this.scope = scope;
202 },
203
204 /**
205 * Set this buttons text
206 * @param {String} text
207 */
208 setText : function(text){
209 this.inner.innerHTML = text;
210 },
211
212 /**
213 * Set this buttons tooltip text
214 * @param {String} text
215 */
216 setTooltip : function(text){
217 this.el.dom.title = text;
218 },
219
220 /**
221 * Show this button
222 */
223 show: function(){
224 this.el.dom.parentNode.style.display = '';
225 },
226
227 /**
228 * Hide this button
229 */
230 hide: function(){
231 this.el.dom.parentNode.style.display = 'none';
232 },
233
234 /**
235 * Disable this button
236 */
237 disable : function(){
238 this.disabled = true;
239 if(this.el){
240 this.el.addClass('ytb-button-disabled');
241 }
242 },
243
244 /**
245 * Enable this button
246 */
247 enable : function(){
248 this.disabled = false;
249 if(this.el){
250 this.el.removeClass('ytb-button-disabled');
251 }
252 },
253
254 /**
255 * Returns true if this button is disabled.
256 * @return {Boolean}
257 */
258 isDisabled : function(){
259 return this.disabled === true;
260 },
261
262 setDisabled : function(disabled){
263 if(disabled){
264 this.disable();
265 }else{
266 this.enable();
267 }
268 },
269
270 /** @private */
271 onClick : function(){
272 if(!this.disabled && this.click){
273 this.click.call(this.scope || window, this);
274 }
275 },
276
277 /** @private */
278 onMouseOver : function(){
279 if(!this.disabled){
280 this.el.addClass('ytb-button-over');
281 if(this.mouseover){
282 this.mouseover.call(this.scope || window, this);
283 }
284 }
285 },
286
287 /** @private */
288 onMouseOut : function(){
289 this.el.removeClass('ytb-button-over');
290 if(!this.disabled){
291 if(this.mouseout){
292 this.mouseout.call(this.scope || window, this);
293 }
294 }
295 }
296};