author | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
---|---|---|
committer | Giulio Cesare Solaroli <giulio.cesare@solaroli.it> | 2011-10-03 16:04:12 (UTC) |
commit | 541bb378ddece2eab135a8066a16994e94436dea (patch) (unidiff) | |
tree | ff160ea3e26f7fe07fcfd401387c5a0232ca715e /frontend/beta/js/YUI-extensions/widgets | |
parent | 1bf431fd3d45cbdf4afa3e12afefe5d24f4d3bc7 (diff) | |
parent | ecad5e895831337216544e81f1a467e0c68c4a6a (diff) | |
download | clipperz-541bb378ddece2eab135a8066a16994e94436dea.zip clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.gz clipperz-541bb378ddece2eab135a8066a16994e94436dea.tar.bz2 |
Merge pull request #1 from gcsolaroli/master
First version of the restructured repository
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.js | 1046 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/Button.js | 185 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/DatePicker.js | 344 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/InlineEditor.js | 216 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/MessageBox.js | 230 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/QuickTips.js | 311 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/Resizable.js | 586 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/SplitBar.js | 468 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/TabPanel.js | 756 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/TaskPanel.js | 0 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/TemplateView.js | 766 | ||||
-rw-r--r-- | frontend/beta/js/YUI-extensions/widgets/Toolbar.js | 296 |
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 | */ | ||
41 | YAHOO.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"> </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 | |||
261 | YAHOO.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 | */ | ||
868 | YAHOO.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 | */ | ||
1009 | YAHOO.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 | }; | ||
1020 | YAHOO.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 | */ | ||
14 | YAHOO.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 | |||
30 | YAHOO.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"> </td><td class="ybtn-center" unselectable="on">{0}</td><td class="ybtn-right"> </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 @@ | |||
1 | YAHOO.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 | |||
14 | YAHOO.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 | */ | ||
204 | YAHOO.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"> </div></td><td class="ypopcal-month"> </td><td class="ypopcal-arrow"><div class="next-month"> </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> </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 | |||
242 | YAHOO.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 | |||
329 | YAHOO.ext.DatePicker.prototype.todayText = "Today"; | ||
330 | YAHOO.ext.DatePicker.prototype.minDate = null; | ||
331 | YAHOO.ext.DatePicker.prototype.maxDate = null; | ||
332 | YAHOO.ext.DatePicker.prototype.minText = "This date is before the minimum date"; | ||
333 | YAHOO.ext.DatePicker.prototype.maxText = "This date is after the maximum date"; | ||
334 | YAHOO.ext.DatePicker.prototype.format = 'm/d/y'; | ||
335 | YAHOO.ext.DatePicker.prototype.disabledDays = null; | ||
336 | YAHOO.ext.DatePicker.prototype.disabledDaysText = ''; | ||
337 | YAHOO.ext.DatePicker.prototype.disabledDatesRE = null; | ||
338 | YAHOO.ext.DatePicker.prototype.disabledDatesText = ''; | ||
339 | YAHOO.ext.DatePicker.prototype.constrainToViewport = true; | ||
340 | |||
341 | |||
342 | YAHOO.ext.DatePicker.prototype.monthNames = Date.monthNames; | ||
343 | |||
344 | YAHOO.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 @@ | |||
1 | YAHOO.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 | |||
72 | YAHOO.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 = "  "; | ||
182 | }else{ | ||
183 | v = v.replace(/[<> ]/g, ' '); | ||
184 | if(this.multiline){ | ||
185 | v = v.replace(/\n/g, '<br /> '); | ||
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 @@ | |||
1 | YAHOO.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"> </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 || ' '); | ||
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 | |||
230 | YAHOO.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 | */ | ||
5 | YAHOO.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> | ||
10 | var 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 | }); | ||
39 | resizer.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 | */ | ||
50 | YAHOO.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: ' '}); | ||
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 | |||
221 | YAHOO.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 | ||
539 | YAHOO.ext.Resizable.positions = { | ||
540 | n: 'north', s: 'south', e: 'east', w: 'west', se: 'southeast', sw: 'southwest', nw: 'northwest', ne: 'northeast' | ||
541 | }; | ||
542 | |||
543 | |||
544 | YAHOO.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: ' '} | ||
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 | |||
567 | YAHOO.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 | */ | ||
6 | if(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> | ||
16 | var split = new YAHOO.ext.SplitBar('elementToDrag', 'elementToSize', | ||
17 | YAHOO.ext.SplitBar.HORIZONTAL, YAHOO.ext.SplitBar.LEFT); | ||
18 | split.setAdapter(new YAHOO.ext.SplitBar.AbsoluteLayoutAdapter("container")); | ||
19 | split.minSize = 100; | ||
20 | split.maxSize = 600; | ||
21 | split.animate = true; | ||
22 | split.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 | */ | ||
40 | YAHOO.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 | |||
143 | YAHOO.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 | */ | ||
288 | YAHOO.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 | */ | ||
307 | YAHOO.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 | */ | ||
332 | YAHOO.ext.SplitBar.BasicLayoutAdapter = function(){ | ||
333 | }; | ||
334 | |||
335 | YAHOO.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 | */ | ||
390 | YAHOO.ext.SplitBar.AbsoluteLayoutAdapter = function(container){ | ||
391 | this.basic = new YAHOO.ext.SplitBar.BasicLayoutAdapter(); | ||
392 | this.container = getEl(container); | ||
393 | } | ||
394 | |||
395 | YAHOO.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 | */ | ||
433 | YAHOO.ext.SplitBar.VERTICAL = 1; | ||
434 | |||
435 | /** | ||
436 | * Orientation constant - Create a horizontal SplitBar | ||
437 | * @static | ||
438 | * @type Number | ||
439 | */ | ||
440 | YAHOO.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 | */ | ||
447 | YAHOO.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 | */ | ||
454 | YAHOO.ext.SplitBar.RIGHT = 2; | ||
455 | |||
456 | /** | ||
457 | * Placement constant - The resizing element is positioned above the splitter element | ||
458 | * @static | ||
459 | * @type Number | ||
460 | */ | ||
461 | YAHOO.ext.SplitBar.TOP = 3; | ||
462 | |||
463 | /** | ||
464 | * Placement constant - The resizing element is positioned under splitter element | ||
465 | * @static | ||
466 | * @type Number | ||
467 | */ | ||
468 | YAHOO.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 | */ | ||
46 | YAHOO.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 | |||
130 | YAHOO.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 | */ | ||
400 | YAHOO.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 | |||
480 | YAHOO.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 */ | ||
697 | YAHOO.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 */ | ||
704 | YAHOO.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 */ | ||
710 | YAHOO.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 */ | ||
718 | YAHOO.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 */ | ||
729 | YAHOO.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"> </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> | ||
8 | var dataModel = new YAHOO.ext.grid.XMLDataModel(...); | ||
9 | var view = new YAHOO.ext.View('my-element', | ||
10 | '<div id="{0}">{2} - {1}</div>', // auto create template | ||
11 | dataModel, { | ||
12 | singleSelect: true, | ||
13 | selectedClass: 'ydataview-selected' | ||
14 | }); | ||
15 | |||
16 | // listen for node click? | ||
17 | view.on('click', function(vw, index, node, e){ | ||
18 | alert('Node "' + node.id + '" at index: ' + index + ' was clicked.'); | ||
19 | }); | ||
20 | |||
21 | // load XML data | ||
22 | dataModel.load('foobar.xml'); | ||
23 | </code></pre> | ||
24 | For 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 | */ | ||
35 | YAHOO.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 | |||
132 | YAHOO.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> | ||
531 | var view = new YAHOO.ext.JsonView('my-element', | ||
532 | '<div id="{id}">{foo} - {bar}</div>', // auto create template | ||
533 | { multiSelect: true, jsonRoot: 'data' }); | ||
534 | |||
535 | // listen for node click? | ||
536 | view.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 | ||
541 | view.load('foobar.php'); | ||
542 | |||
543 | |||
544 | // Example from my blog list | ||
545 | var tpl = new YAHOO.ext.Template( | ||
546 | '<div class="entry">' + | ||
547 | '<a class="entry-title" href="{link}">{title}</a>' + | ||
548 | '<h4>{date} by {author} | {comments} Comments</h4>{description}' + | ||
549 | '</div><hr />' | ||
550 | ); | ||
551 | |||
552 | var moreView = new YAHOO.ext.JsonView('entry-list', tpl, { | ||
553 | jsonRoot: 'posts' | ||
554 | }); | ||
555 | moreView.on('beforerender', this.sortEntries, this, true); | ||
556 | moreView.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 | */ | ||
568 | YAHOO.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 | }; | ||
597 | YAHOO.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> | ||
602 | view.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&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 | |||
29 | YAHOO.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 | */ | ||
161 | YAHOO.ext.ToolbarButton = function(config){ | ||
162 | YAHOO.ext.util.Config.apply(this, config); | ||
163 | }; | ||
164 | |||
165 | YAHOO.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 : ' '); | ||
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 | }; | ||