summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/yutil.js
authorGiulio Cesare Solaroli <giulio.cesare@clipperz.com>2011-10-02 23:56:18 (UTC)
committer Giulio Cesare Solaroli <giulio.cesare@clipperz.com>2011-10-02 23:56:18 (UTC)
commitef68436ac04da078ffdcacd7e1f785473a303d45 (patch) (unidiff)
treec403752d66a2c4775f00affd4fa8431b29c5b68c /frontend/beta/js/YUI-extensions/yutil.js
parent597ecfbc0249d83e1b856cbd558340c01237a360 (diff)
downloadclipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.zip
clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.gz
clipperz-ef68436ac04da078ffdcacd7e1f785473a303d45.tar.bz2
First version of the newly restructured repository
Diffstat (limited to 'frontend/beta/js/YUI-extensions/yutil.js') (more/less context) (show whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/yutil.js637
1 files changed, 637 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/yutil.js b/frontend/beta/js/YUI-extensions/yutil.js
new file mode 100644
index 0000000..a815397
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/yutil.js
@@ -0,0 +1,637 @@
1YAHOO.namespace('ext', 'ext.util', 'ext.grid', 'ext.dd', 'ext.tree', 'ext.data', 'ext.form');
2if(typeof Ext == 'undefined'){
3 Ext = YAHOO.ext;
4}
5YAHOO.ext.Strict = (document.compatMode == 'CSS1Compat');
6YAHOO.ext.SSL_SECURE_URL = 'javascript:false';
7YAHOO.ext.BLANK_IMAGE_URL = 'http:/'+'/www.yui-ext.com/blog/images/s.gif';
8
9// for old browsers
10window.undefined = undefined;
11/**
12 * @class Function
13 * These functions are available on every Function object (any javascript function).
14 */
15 //
16 /**
17 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
18 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
19 * Will create a function that is bound to those 2 args.
20 * @return {Function} The new function
21*/
22Function.prototype.createCallback = function(/*args...*/){
23 // make args available, in function below
24 var args = arguments;
25 var method = this;
26 return function() {
27 return method.apply(window, args);
28 };
29};
30
31/**
32 * Creates a delegate (callback) that sets the scope to obj.
33 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
34 * Will create a function that is automatically scoped to this.
35 * @param {Object} obj (optional) The object for which the scope is set
36 * @param {<i>Array</i>} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
37 * @param {<i>Boolean/Number</i>} appendArgs (optional) if True args are appended to call args instead of overriding,
38 * if a number the args are inserted at the specified position
39 * @return {Function} The new function
40 */
41Function.prototype.createDelegate = function(obj, args, appendArgs){
42 var method = this;
43 return function() {
44 var callArgs = args || arguments;
45 if(appendArgs === true){
46 callArgs = Array.prototype.slice.call(arguments, 0);
47 callArgs = callArgs.concat(args);
48 }else if(typeof appendArgs == 'number'){
49 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
50 var applyArgs = [appendArgs, 0].concat(args); // create method call params
51 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
52 }
53 return method.apply(obj || window, callArgs);
54 };
55};
56
57/**
58 * Calls this function after the number of millseconds specified.
59 * @param {Number} millis The number of milliseconds for the setTimeout call
60 * @param {Object} obj (optional) The object for which the scope is set
61 * @param {<i>Array</i>} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
62 * @param {<i>Boolean/Number</i>} appendArgs (optional) if True args are appended to call args instead of overriding,
63 * if a number the args are inserted at the specified position
64 * @return {Number} The timeout id that can be used with clearTimeout
65 */
66Function.prototype.defer = function(millis, obj, args, appendArgs){
67 return setTimeout(this.createDelegate(obj, args, appendArgs), millis);
68};
69/**
70 * Create a combined function call sequence of the original function + the passed function.
71 * The resulting function returns the results of the original function.
72 * The passed fcn is called with the parameters of the original function
73 * @param {Function} fcn The function to sequence
74 * @param {<i>Object</i>} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
75 * @return {Function} The new function
76 */
77Function.prototype.createSequence = function(fcn, scope){
78 if(typeof fcn != 'function'){
79 return this;
80 }
81 var method = this;
82 return function() {
83 var retval = method.apply(this || window, arguments);
84 fcn.apply(scope || this || window, arguments);
85 return retval;
86 };
87};
88
89/*
90 * IE will leak if this isn't here
91 */
92YAHOO.util.Event.on(window, 'unload', function(){
93 var p = Function.prototype;
94 delete p.createSequence;
95 delete p.defer;
96 delete p.createDelegate;
97 delete p.createCallback;
98 delete p.createInterceptor;
99});
100
101/**
102 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
103 * The resulting function returns the results of the original function.
104 * The passed fcn is called with the parameters of the original function.
105 * @addon
106 * @param {Function} fcn The function to call before the original
107 * @param {<i>Object</i>} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
108 * @return {Function} The new function
109 */
110Function.prototype.createInterceptor = function(fcn, scope){
111 if(typeof fcn != 'function'){
112 return this;
113 }
114 var method = this;
115 return function() {
116 fcn.target = this;
117 fcn.method = method;
118 if(fcn.apply(scope || this || window, arguments) === false){
119 return;
120 }
121 return method.apply(this || window, arguments);;
122 };
123};
124
125/**
126 * @class YAHOO.ext.util.Browser
127 * @singleton
128 */
129YAHOO.ext.util.Browser = new function(){
130 var ua = navigator.userAgent.toLowerCase();
131 /** @type Boolean */
132 this.isOpera = (ua.indexOf('opera') > -1);
133 /** @type Boolean */
134 this.isSafari = (ua.indexOf('webkit') > -1);
135 /** @type Boolean */
136 this.isIE = (window.ActiveXObject);
137 /** @type Boolean */
138 this.isIE7 = (ua.indexOf('msie 7') > -1);
139 /** @type Boolean */
140 this.isGecko = !this.isSafari && (ua.indexOf('gecko') > -1);
141
142 if(ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1){
143 /** @type Boolean */
144 this.isWindows = true;
145 }else if(ua.indexOf("macintosh") != -1){
146 /** @type Boolean */
147 this.isMac = true;
148 }
149 if(this.isIE && !this.isIE7){
150 try{
151 document.execCommand("BackgroundImageCache", false, true);
152 }catch(e){}
153 }
154}();
155
156 /**
157 * Enable custom handler signature and event cancelling. Using fireDirect() instead of fire() calls the subscribed event handlers
158 * with the exact parameters passed to fireDirect, instead of the usual (eventType, args[], obj). IMO this is more intuitive
159 * and promotes cleaner code. Also, if an event handler returns false, it is returned by fireDirect and no other handlers will be called.<br>
160 * Example:<br><br><pre><code>
161 * if(beforeUpdateEvent.fireDirect(myArg, myArg2) !== false){
162 * // do update
163 * }</code></pre>
164 */
165YAHOO.util.CustomEvent.prototype.fireDirect = function(){
166 var len=this.subscribers.length;
167 for (var i=0; i<len; ++i) {
168 var s = this.subscribers[i];
169 if(s){
170 var scope = (s.override) ? s.obj : this.scope;
171 if(s.fn.apply(scope, arguments) === false){
172 return false;
173 }
174 }
175 }
176 return true;
177};
178
179/**
180 * @class YAHOO-
181 * Additional functionality for the global YAHOO object.
182 * @singleton
183 */
184/**
185 * Prints all arguments to a resizable, movable, scrolling region without
186 * the need to include separate js or css. Double click it to hide it.
187 * @param {Mixed} arg1
188 * @param {Mixed} arg2
189 * @param {Mixed} etc
190 * @static
191 */
192YAHOO.print = function(arg1, arg2, etc){
193 if(!YAHOO.ext._console){
194 var cs = YAHOO.ext.DomHelper.insertBefore(document.body.firstChild,
195 {tag: 'div',style:'width:250px;height:350px;overflow:auto;border:3px solid #c3daf9;' +
196 'background:white;position:absolute;right:5px;top:5px;' +
197 'font:normal 8pt arial,verdana,helvetica;z-index:50000;padding:5px;'}, true);
198 if(YAHOO.ext.Resizable){
199 new YAHOO.ext.Resizable(cs, {
200 transparent:true,
201 handles: 'all',
202 pinned:true,
203 adjustments: [0,0],
204 wrap:true,
205 draggable:(YAHOO.util.DD ? true : false)
206 });
207 }
208 cs.on('dblclick', cs.hide);
209 YAHOO.ext._console = cs;
210 }
211 var m = '';
212 for(var i = 0, len = arguments.length; i < len; i++) {
213 m += (i == 0 ? '' : ', ') + arguments[i];
214 }
215 m += '<hr noshade style="color:#eeeeee;" size="1">'
216 var d = YAHOO.ext._console.dom;
217 d.innerHTML = m + d.innerHTML;
218 d.scrollTop = 0;
219 YAHOO.ext._console.show();
220};
221
222/**
223 * Applies the passed C#/DomHelper style format (e.g. "The variable {0} is equal to {1}") before calling {@link YAHOO#print}
224 * @param {String} format
225 * @param {Mixed} arg1
226 * @param {Mixed} arg2
227 * @param {Mixed} etc
228 * @static
229 */
230YAHOO.printf = function(format, arg1, arg2, etc){
231 var args = Array.prototype.slice.call(arguments, 1);
232 YAHOO.print(format.replace(
233 /\{\{[^{}]*\}\}|\{(\d+)(,\s*([\w.]+))?\}/g,
234 function(m, a1, a2, a3) {
235 if (m.chatAt == '{') {
236 return m.slice(1, -1);
237 }
238 var rpl = args[a1];
239 if (a3) {
240 var f = eval(a3);
241 rpl = f(rpl);
242 }
243 return rpl ? rpl : '';
244 }));
245}
246
247YAHOO._timers = {};
248/**
249 * If a timer with specified name doesn't exist it is started. If one exists and reset is not true
250 * it prints the ellapsed time since the start using YAHOO.printf.
251 * @param {String} name
252 * @param {Boolean} reset true to reset an existing timer
253 */
254YAHOO.timer = function(name, reset){
255 var t = new Date().getTime();
256 if(YAHOO._timers[name] && !reset){
257 YAHOO.printf("{0} : {1} ms", name, t-YAHOO._timers[name]);
258 }else{
259 YAHOO._timers[name] = t;
260 }
261}
262/**
263 * Extends one class with another class and optionally overrides members with the passed literal. This class
264 * also adds the function "override()" to the class that can be used to override
265 * members on an instance.
266 * @param {Object} subclass The class inheriting the functionality
267 * @param {Object} superclass The class being extended
268 * @param {Object} overrides (optional) A literal with members
269 * @static
270 */
271YAHOO.extendX = function(subclass, superclass, overrides){
272 YAHOO.extend(subclass, superclass);
273 subclass.override = function(o){
274 YAHOO.override(subclass, o);
275 };
276 if(!subclass.prototype.override){
277 subclass.prototype.override = function(o){
278 for(var method in o){
279 this[method] = o[method];
280 }
281 };
282 }
283 if(overrides){
284 subclass.override(overrides);
285 }
286};
287
288/**
289 * Creates namespaces but does not assume YAHOO is the root.
290 * @param {String} namespace1
291 * @param {String} namespace2
292 * @param {String} etc
293 * @static
294 */
295YAHOO.namespaceX = function(){
296 var a = arguments, len = a.length, i;
297 YAHOO.namespace.apply(YAHOO, a);
298 for(i = 0; i < len; i++){
299 var p = a[i].split('.')[0];
300 if(p != 'YAHOO' && YAHOO[p]){
301 eval(p + ' = YAHOO.' + p);
302 delete YAHOO[p];
303 }
304 }
305};
306
307YAHOO.override = function(origclass, overrides){
308 if(overrides){
309 var p = origclass.prototype;
310 for(var method in overrides){
311 p[method] = overrides[method];
312 }
313 }
314};
315
316/**
317 * @class YAHOO.ext.util.DelayedTask
318 * Provides a convenient method of performing setTimeout where a new
319 * timeout cancels the old timeout. An example would be performing validation on a keypress.
320 * You can use this class to buffer
321 * the keypress events for a certain number of milliseconds, and perform only if they stop
322 * for that amount of time.
323 * @constructor The parameters to this constructor serve as defaults and are not required.
324 * @param {<i>Function</i>} fn (optional) The default function to timeout
325 * @param {<i>Object</i>} scope (optional) The default scope of that timeout
326 * @param {<i>Array</i>} args (optional) The default Array of arguments
327 */
328YAHOO.ext.util.DelayedTask = function(fn, scope, args){
329 var timeoutId = null;
330
331 /**
332 * Cancels any pending timeout and queues a new one
333 * @param {Number} delay The milliseconds to delay
334 * @param {Function} newFn (optional) Overrides function passed to constructor
335 * @param {Object} newScope (optional) Overrides scope passed to constructor
336 * @param {Array} newArgs (optional) Overrides args passed to constructor
337 */
338 this.delay = function(delay, newFn, newScope, newArgs){
339 if(timeoutId){
340 clearTimeout(timeoutId);
341 }
342 fn = newFn || fn;
343 scope = newScope || scope;
344 args = newArgs || args;
345 timeoutId = setTimeout(fn.createDelegate(scope, args), delay);
346 };
347
348 /**
349 * Cancel the last queued timeout
350 */
351 this.cancel = function(){
352 if(timeoutId){
353 clearTimeout(timeoutId);
354 timeoutId = null;
355 }
356 };
357};
358
359/**
360 * @class YAHOO.ext.util.Observable
361 * Abstract base class that provides a common interface for publishing events. Subclasses are expected to
362 * to have a property "events" with all the events defined.<br>
363 * For example:
364 * <pre><code>
365 var Employee = function(name){
366 this.name = name;
367 this.events = {
368 'fired' : new YAHOO.util.CustomEvent('fired'),
369 'quit' : true // lazy initialize the CustomEvent
370 }
371 }
372 YAHOO.extend(Employee, YAHOO.ext.util.Observable);
373</code></pre>
374 */
375YAHOO.ext.util.Observable = function(){};
376YAHOO.ext.util.Observable.prototype = {
377 /**
378 * Fires the specified event with the passed parameters (minus the event name).
379 * @param {String} eventName
380 * @param {Object...} args Variable number of parameters are passed to handlers
381 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
382 */
383 fireEvent : function(){
384 var ce = this.events[arguments[0].toLowerCase()];
385 if(typeof ce == 'object'){
386 return ce.fireDirect.apply(ce, Array.prototype.slice.call(arguments, 1));
387 }else{
388 return true;
389 }
390 },
391 /**
392 * Appends an event handler to this component
393 * @param {String} eventName The type of event to listen for
394 * @param {Function} handler The method the event invokes
395 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
396 * @param {<i>boolean</i>} override (optional) If true, scope becomes the scope
397 */
398 addListener : function(eventName, fn, scope, override){
399 eventName = eventName.toLowerCase();
400 var ce = this.events[eventName];
401 if(!ce){
402 // added for a better message when subscribing to wrong event
403 throw 'You are trying to listen for an event that does not exist: "' + eventName + '".';
404 }
405 if(typeof ce == 'boolean'){
406 ce = new YAHOO.util.CustomEvent(eventName);
407 this.events[eventName] = ce;
408 }
409 ce.subscribe(fn, scope, override);
410 },
411
412 /**
413 * Appends an event handler to this component that is delayed the specified number of milliseconds. This
414 * is useful for events that modify the DOM and need to wait for the browser to catch up.
415 * @param {String} eventName The type of event to listen for
416 * @param {Function} handler The method the event invokes
417 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
418 * @param {<i>Number</i>} delay (optional) The number of milliseconds to delay (defaults to 1 millisecond)
419 * @return {Function} The wrapped function that was created (can be used to remove the listener)
420 */
421 delayedListener : function(eventName, fn, scope, delay){
422 var newFn = function(){
423 setTimeout(fn.createDelegate(scope, arguments), delay || 1);
424 }
425 this.addListener(eventName, newFn);
426 return newFn;
427 },
428
429 /**
430 * Appends an event handler to this component that is buffered. If the event is triggered more than once
431 * in the specified time-frame, only the last one actually fires.
432 * @param {String} eventName The type of event to listen for
433 * @param {Function} handler The method the event invokes
434 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
435 * @param {<i>Number</i>} millis (optional) The number of milliseconds to buffer (defaults to 250)
436 * @return {Function} The wrapped function that was created (can be used to remove the listener)
437 */
438 bufferedListener : function(eventName, fn, scope, millis){
439 var task = new YAHOO.ext.util.DelayedTask();
440 var newFn = function(){
441 task.delay(millis || 250, fn, scope, Array.prototype.slice.call(arguments, 0));
442 }
443 this.addListener(eventName, newFn);
444 return newFn;
445 },
446
447 /**
448 * Removes a listener
449 * @param {String} eventName The type of event to listen for
450 * @param {Function} handler The handler to remove
451 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
452 */
453 removeListener : function(eventName, fn, scope){
454 var ce = this.events[eventName.toLowerCase()];
455 if(typeof ce == 'object'){
456 ce.unsubscribe(fn, scope);
457 }
458 },
459
460 /**
461 * Removes all listeners for this object
462 */
463 purgeListeners : function(){
464 for(var evt in this.events){
465 if(typeof this.events[evt] == 'object'){
466 this.events[evt].unsubscribeAll();
467 }
468 }
469 }
470};
471/**
472 * Appends an event handler to this element (shorthand for addListener)
473 * @param {String} eventName The type of event to listen for
474 * @param {Function} handler The method the event invokes
475 * @param {<i>Object</i>} scope (optional) The scope (this object) for the handler
476 * @param {<i>boolean</i>} override (optional) If true, scope becomes the scope
477 * @method
478 */
479YAHOO.ext.util.Observable.prototype.on = YAHOO.ext.util.Observable.prototype.addListener;
480
481/**
482 * Starts capture on the specified Observable. All events will be passed
483 * to the supplied function with the event name + standard signature of the event
484 * <b>before</b> the event is fired. If the supplied function returns false,
485 * the event will not fire.
486 * @param {Observable} o The Observable to capture
487 * @param {Function} fn The function to call
488 * @param {Object} scope (optional) The scope (this object) for the fn
489 * @static
490 */
491YAHOO.ext.util.Observable.capture = function(o, fn, scope){
492 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
493};
494
495/**
496 * Removes <b>all</b> added captures from the Observable.
497 * @param {Observable} o The Observable to release
498 * @static
499 */
500YAHOO.ext.util.Observable.releaseCapture = function(o){
501 o.fireEvent = YAHOO.ext.util.Observable.prototype.fireEvent;
502};
503
504/**
505 * @class YAHOO.ext.util.Config
506 * Class with one useful method
507 * @singleton
508 */
509YAHOO.ext.util.Config = {
510 /**
511 * Copies all the properties of config to obj.
512 * @param {Object} obj The receiver of the properties
513 * @param {Object} config The source of the properties
514 * @param {Object} defaults A different object that will also be applied for default values
515 * @return {Object} returns obj
516 */
517 apply : function(obj, config, defaults){
518 if(defaults){
519 this.apply(obj, defaults);
520 }
521 if(config){
522 for(var prop in config){
523 obj[prop] = config[prop];
524 }
525 }
526 return obj;
527 }
528};
529
530if(!String.escape){
531 String.escape = function(string) {
532 return string.replace(/('|\\)/g, "\\$1");
533 };
534};
535
536String.leftPad = function (val, size, ch) {
537 var result = new String(val);
538 if (ch == null) {
539 ch = " ";
540 }
541 while (result.length < size) {
542 result = ch + result;
543 }
544 return result;
545};
546
547// workaround for Safari anim duration speed problems
548if(YAHOO.util.AnimMgr && YAHOO.ext.util.Browser.isSafari){
549 YAHOO.util.AnimMgr.fps = 500;
550}
551
552// add ability for callbacks instead of events for animations
553if(YAHOO.util.Anim){
554 YAHOO.util.Anim.prototype.animateX = function(callback, scope){
555 var f = function(){
556 this.onComplete.unsubscribe(f);
557 if(typeof callback == 'function'){
558 callback.call(scope || this, this);
559 }
560 };
561 this.onComplete.subscribe(f, this, true);
562 this.animate();
563 };
564}
565
566// workaround for Safari 1.3 not supporting hasOwnProperty
567if(YAHOO.util.Connect && YAHOO.ext.util.Browser.isSafari){
568 YAHOO.util.Connect.setHeader = function(o){
569 for(var prop in this._http_header){
570 // if(this._http_header.hasOwnProperty(prop)){
571 if(typeof this._http_header[prop] != 'function'){
572 o.conn.setRequestHeader(prop, this._http_header[prop]);
573 }
574 }
575 delete this._http_header;
576 this._http_header = {};
577 this._has_http_headers = false;
578 };
579}
580/**
581 * A simple enhancement to drag drop that allows you to constrain the movement of the
582 * DD or DDProxy object to a particular element.<br /><br />
583 *
584 * Usage:
585 <pre><code>
586 var dd = new YAHOO.util.DDProxy("dragDiv1", "proxytest",
587 { dragElId: "existingProxyDiv" });
588 dd.startDrag = function(){
589 this.constrainTo('parent-id');
590 };
591 </code></pre>
592 * Or you can initalize it using the {@link YAHOO.ext.Element} object:
593 <pre><code>
594 getEl('dragDiv1').initDDProxy('proxytest', {dragElId: "existingProxyDiv"}, {
595 startDrag : function(){
596 this.constrainTo('parent-id');
597 }
598 });
599 </code></pre>
600 */
601if(YAHOO.util.DragDrop){
602 /**
603 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
604 * @type Object
605 */
606 YAHOO.util.DragDrop.prototype.defaultPadding = {left:0, right:0, top:0, bottom:0};
607
608 /**
609 * Initializes the drag drop object's constraints to restrict movement to a certain element.
610 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
611 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
612 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
613 * an object containing the sides to pad. For example: {right:10, bottom:10}
614 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
615 */
616 YAHOO.util.DragDrop.prototype.constrainTo = function(constrainTo, pad, inContent){
617 if(typeof pad == 'number'){
618 pad = {left: pad, right:pad, top:pad, bottom:pad};
619 }
620 pad = pad || this.defaultPadding;
621 var b = getEl(this.getEl()).getBox();
622 var ce = getEl(constrainTo);
623 var c = ce.dom == document.body ? { x: 0, y: 0,
624 width: YAHOO.util.Dom.getViewportWidth(),
625 height: YAHOO.util.Dom.getViewportHeight()} : ce.getBox(inContent || false);
626 var topSpace = b.y - c.y;
627 var leftSpace = b.x - c.x;
628
629 this.resetConstraints();
630 this.setXConstraint(leftSpace - (pad.left||0), // left
631 c.width - leftSpace - b.width - (pad.right||0) //right
632 );
633 this.setYConstraint(topSpace - (pad.top||0), //top
634 c.height - topSpace - b.height - (pad.bottom||0) //bottom
635 );
636 }
637}