1 | /*
|
---|
2 | * jquery.layout 1.2.0
|
---|
3 | *
|
---|
4 | * Copyright (c) 2008
|
---|
5 | * Fabrizio Balliano (http://www.fabrizioballiano.net)
|
---|
6 | * Kevin Dalman (http://allpro.net)
|
---|
7 | *
|
---|
8 | * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
|
---|
9 | * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
|
---|
10 | *
|
---|
11 | * $Date: 2008-12-27 02:17:22 +0100 (sab, 27 dic 2008) $
|
---|
12 | * $Rev: 203 $
|
---|
13 | *
|
---|
14 | * NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars
|
---|
15 | */
|
---|
16 | (function($) {
|
---|
17 |
|
---|
18 | $.fn.layout = function (opts) {
|
---|
19 |
|
---|
20 | /*
|
---|
21 | * ###########################
|
---|
22 | * WIDGET CONFIG & OPTIONS
|
---|
23 | * ###########################
|
---|
24 | */
|
---|
25 |
|
---|
26 | // DEFAULTS for options
|
---|
27 | var
|
---|
28 | prefix = "ui-layout-" // prefix for ALL selectors and classNames
|
---|
29 | , defaults = { // misc default values
|
---|
30 | paneClass: prefix+"pane" // ui-layout-pane
|
---|
31 | , resizerClass: prefix+"resizer" // ui-layout-resizer
|
---|
32 | , togglerClass: prefix+"toggler" // ui-layout-toggler
|
---|
33 | , togglerInnerClass: prefix+"" // ui-layout-open / ui-layout-closed
|
---|
34 | , buttonClass: prefix+"button" // ui-layout-button
|
---|
35 | , contentSelector: "."+prefix+"content"// ui-layout-content
|
---|
36 | , contentIgnoreSelector: "."+prefix+"ignore" // ui-layout-mask
|
---|
37 | }
|
---|
38 | ;
|
---|
39 |
|
---|
40 | // DEFAULT PANEL OPTIONS - CHANGE IF DESIRED
|
---|
41 | var options = {
|
---|
42 | name: "" // FUTURE REFERENCE - not used right now
|
---|
43 | , scrollToBookmarkOnLoad: true // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark)
|
---|
44 | , defaults: { // default options for 'all panes' - will be overridden by 'per-pane settings'
|
---|
45 | applyDefaultStyles: false // apply basic styles directly to resizers & buttons? If not, then stylesheet must handle it
|
---|
46 | , closable: true // pane can open & close
|
---|
47 | , resizable: true // when open, pane can be resized
|
---|
48 | , slidable: true // when closed, pane can 'slide' open over other panes - closes on mouse-out
|
---|
49 | //, paneSelector: [ ] // MUST be pane-specific!
|
---|
50 | , contentSelector: defaults.contentSelector // INNER div/element to auto-size so only it scrolls, not the entire pane!
|
---|
51 | , contentIgnoreSelector: defaults.contentIgnoreSelector // elem(s) to 'ignore' when measuring 'content'
|
---|
52 | , paneClass: defaults.paneClass // border-Pane - default: 'ui-layout-pane'
|
---|
53 | , resizerClass: defaults.resizerClass // Resizer Bar - default: 'ui-layout-resizer'
|
---|
54 | , togglerClass: defaults.togglerClass // Toggler Button - default: 'ui-layout-toggler'
|
---|
55 | , buttonClass: defaults.buttonClass // CUSTOM Buttons - default: 'ui-layout-button-toggle/-open/-close/-pin'
|
---|
56 | , resizerDragOpacity: 1 // option for ui.draggable
|
---|
57 | //, resizerCursor: "" // MUST be pane-specific - cursor when over resizer-bar
|
---|
58 | , maskIframesOnResize: true // true = all iframes OR = iframe-selector(s) - adds masking-div during resizing/dragging
|
---|
59 | //, size: 100 // inital size of pane - defaults are set 'per pane'
|
---|
60 | , minSize: 0 // when manually resizing a pane
|
---|
61 | , maxSize: 0 // ditto, 0 = no limit
|
---|
62 | , spacing_open: 6 // space between pane and adjacent panes - when pane is 'open'
|
---|
63 | , spacing_closed: 6 // ditto - when pane is 'closed'
|
---|
64 | , togglerLength_open: 50 // Length = WIDTH of toggler button on north/south edges - HEIGHT on east/west edges
|
---|
65 | , togglerLength_closed: 50 // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden'
|
---|
66 | , togglerAlign_open: "center" // top/left, bottom/right, center, OR...
|
---|
67 | , togglerAlign_closed: "center" // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right
|
---|
68 | , togglerTip_open: "Close" // Toggler tool-tip (title)
|
---|
69 | , togglerTip_closed: "Open" // ditto
|
---|
70 | , resizerTip: "Resize" // Resizer tool-tip (title)
|
---|
71 | , sliderTip: "Slide Open" // resizer-bar triggers 'sliding' when pane is closed
|
---|
72 | , sliderCursor: "pointer" // cursor when resizer-bar will trigger 'sliding'
|
---|
73 | , slideTrigger_open: "click" // click, dblclick, mouseover
|
---|
74 | , slideTrigger_close: "mouseout" // click, mouseout
|
---|
75 | , hideTogglerOnSlide: false // when pane is slid-open, should the toggler show?
|
---|
76 | , togglerContent_open: "" // text or HTML to put INSIDE the toggler
|
---|
77 | , togglerContent_closed: "" // ditto
|
---|
78 | , showOverflowOnHover: false // will bind allowOverflow() utility to pane.onMouseOver
|
---|
79 | , enableCursorHotkey: true // enabled 'cursor' hotkeys
|
---|
80 | //, customHotkey: "" // MUST be pane-specific - EITHER a charCode OR a character
|
---|
81 | , customHotkeyModifier: "SHIFT" // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT'
|
---|
82 | // NOTE: fxSss_open & fxSss_close options (eg: fxName_open) are auto-generated if not passed
|
---|
83 | , fxName: "slide" // ('none' or blank), slide, drop, scale
|
---|
84 | , fxSpeed: null // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration
|
---|
85 | , fxSettings: {} // can be passed, eg: { easing: "easeOutBounce", duration: 1500 }
|
---|
86 | , initClosed: false // true = init pane as 'closed'
|
---|
87 | , initHidden: false // true = init pane as 'hidden' - no resizer or spacing
|
---|
88 |
|
---|
89 | /* callback options do not have to be set - listed here for reference only
|
---|
90 | , onshow_start: "" // CALLBACK when pane STARTS to Show - BEFORE onopen/onhide_start
|
---|
91 | , onshow_end: "" // CALLBACK when pane ENDS being Shown - AFTER onopen/onhide_end
|
---|
92 | , onhide_start: "" // CALLBACK when pane STARTS to Close - BEFORE onclose_start
|
---|
93 | , onhide_end: "" // CALLBACK when pane ENDS being Closed - AFTER onclose_end
|
---|
94 | , onopen_start: "" // CALLBACK when pane STARTS to Open
|
---|
95 | , onopen_end: "" // CALLBACK when pane ENDS being Opened
|
---|
96 | , onclose_start: "" // CALLBACK when pane STARTS to Close
|
---|
97 | , onclose_end: "" // CALLBACK when pane ENDS being Closed
|
---|
98 | , onresize_start: "" // CALLBACK when pane STARTS to be ***MANUALLY*** Resized
|
---|
99 | , onresize_end: "" // CALLBACK when pane ENDS being Resized ***FOR ANY REASON***
|
---|
100 | */
|
---|
101 | }
|
---|
102 | , north: {
|
---|
103 | paneSelector: "."+prefix+"north" // default = .ui-layout-north
|
---|
104 | , size: "auto"
|
---|
105 | , resizerCursor: "n-resize"
|
---|
106 | }
|
---|
107 | , south: {
|
---|
108 | paneSelector: "."+prefix+"south" // default = .ui-layout-south
|
---|
109 | , size: "auto"
|
---|
110 | , resizerCursor: "s-resize"
|
---|
111 | }
|
---|
112 | , east: {
|
---|
113 | paneSelector: "."+prefix+"east" // default = .ui-layout-east
|
---|
114 | , size: 200
|
---|
115 | , resizerCursor: "e-resize"
|
---|
116 | }
|
---|
117 | , west: {
|
---|
118 | paneSelector: "."+prefix+"west" // default = .ui-layout-west
|
---|
119 | , size: 200
|
---|
120 | , resizerCursor: "w-resize"
|
---|
121 | }
|
---|
122 | , center: {
|
---|
123 | paneSelector: "."+prefix+"center" // default = .ui-layout-center
|
---|
124 | }
|
---|
125 |
|
---|
126 | };
|
---|
127 |
|
---|
128 |
|
---|
129 | var effects = { // LIST *PREDEFINED EFFECTS* HERE, even if effect has no settings
|
---|
130 | slide: {
|
---|
131 | all: { duration: "fast" } // eg: duration: 1000, easing: "easeOutBounce"
|
---|
132 | , north: { direction: "up" }
|
---|
133 | , south: { direction: "down" }
|
---|
134 | , east: { direction: "right"}
|
---|
135 | , west: { direction: "left" }
|
---|
136 | }
|
---|
137 | , drop: {
|
---|
138 | all: { duration: "slow" } // eg: duration: 1000, easing: "easeOutQuint"
|
---|
139 | , north: { direction: "up" }
|
---|
140 | , south: { direction: "down" }
|
---|
141 | , east: { direction: "right"}
|
---|
142 | , west: { direction: "left" }
|
---|
143 | }
|
---|
144 | , scale: {
|
---|
145 | all: { duration: "fast" }
|
---|
146 | }
|
---|
147 | };
|
---|
148 |
|
---|
149 |
|
---|
150 | // STATIC, INTERNAL CONFIG - DO NOT CHANGE THIS!
|
---|
151 | var config = {
|
---|
152 | allPanes: "north,south,east,west,center"
|
---|
153 | , borderPanes: "north,south,east,west"
|
---|
154 | , zIndex: { // set z-index values here
|
---|
155 | resizer_normal: 1 // normal z-index for resizer-bars
|
---|
156 | , pane_normal: 2 // normal z-index for panes
|
---|
157 | , mask: 4 // overlay div used to mask pane(s) during resizing
|
---|
158 | , sliding: 100 // applied to both the pane and its resizer when a pane is 'slid open'
|
---|
159 | , resizing: 10000 // applied to the CLONED resizer-bar when being 'dragged'
|
---|
160 | , animation: 10000 // applied to the pane when being animated - not applied to the resizer
|
---|
161 | }
|
---|
162 | , resizers: {
|
---|
163 | cssReq: {
|
---|
164 | position: "absolute"
|
---|
165 | , padding: 0
|
---|
166 | , margin: 0
|
---|
167 | , fontSize: "1px"
|
---|
168 | , textAlign: "left" // to counter-act "center" alignment!
|
---|
169 | , overflow: "hidden" // keep toggler button from overflowing
|
---|
170 | , zIndex: 1
|
---|
171 | }
|
---|
172 | , cssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true
|
---|
173 | background: "#DDD"
|
---|
174 | , border: "none"
|
---|
175 | }
|
---|
176 | }
|
---|
177 | , togglers: {
|
---|
178 | cssReq: {
|
---|
179 | position: "absolute"
|
---|
180 | , display: "block"
|
---|
181 | , padding: 0
|
---|
182 | , margin: 0
|
---|
183 | , overflow: "hidden"
|
---|
184 | , textAlign: "center"
|
---|
185 | , fontSize: "1px"
|
---|
186 | , cursor: "pointer"
|
---|
187 | , zIndex: 1
|
---|
188 | }
|
---|
189 | , cssDef: { // DEFAULT CSS - applied if: options.PANE.applyDefaultStyles=true
|
---|
190 | background: "#AAA"
|
---|
191 | }
|
---|
192 | }
|
---|
193 | , content: {
|
---|
194 | cssReq: {
|
---|
195 | overflow: "auto"
|
---|
196 | }
|
---|
197 | , cssDef: {}
|
---|
198 | }
|
---|
199 | , defaults: { // defaults for ALL panes - overridden by 'per-pane settings' below
|
---|
200 | cssReq: {
|
---|
201 | position: "absolute"
|
---|
202 | , margin: 0
|
---|
203 | , zIndex: 2
|
---|
204 | }
|
---|
205 | , cssDef: {
|
---|
206 | padding: "10px"
|
---|
207 | , background: "#FFF"
|
---|
208 | , border: "1px solid #BBB"
|
---|
209 | , overflow: "auto"
|
---|
210 | }
|
---|
211 | }
|
---|
212 | , north: {
|
---|
213 | edge: "top"
|
---|
214 | , sizeType: "height"
|
---|
215 | , dir: "horz"
|
---|
216 | , cssReq: {
|
---|
217 | top: 0
|
---|
218 | , bottom: "auto"
|
---|
219 | , left: 0
|
---|
220 | , right: 0
|
---|
221 | , width: "auto"
|
---|
222 | // height: DYNAMIC
|
---|
223 | }
|
---|
224 | }
|
---|
225 | , south: {
|
---|
226 | edge: "bottom"
|
---|
227 | , sizeType: "height"
|
---|
228 | , dir: "horz"
|
---|
229 | , cssReq: {
|
---|
230 | top: "auto"
|
---|
231 | , bottom: 0
|
---|
232 | , left: 0
|
---|
233 | , right: 0
|
---|
234 | , width: "auto"
|
---|
235 | // height: DYNAMIC
|
---|
236 | }
|
---|
237 | }
|
---|
238 | , east: {
|
---|
239 | edge: "right"
|
---|
240 | , sizeType: "width"
|
---|
241 | , dir: "vert"
|
---|
242 | , cssReq: {
|
---|
243 | left: "auto"
|
---|
244 | , right: 0
|
---|
245 | , top: "auto" // DYNAMIC
|
---|
246 | , bottom: "auto" // DYNAMIC
|
---|
247 | , height: "auto"
|
---|
248 | // width: DYNAMIC
|
---|
249 | }
|
---|
250 | }
|
---|
251 | , west: {
|
---|
252 | edge: "left"
|
---|
253 | , sizeType: "width"
|
---|
254 | , dir: "vert"
|
---|
255 | , cssReq: {
|
---|
256 | left: 0
|
---|
257 | , right: "auto"
|
---|
258 | , top: "auto" // DYNAMIC
|
---|
259 | , bottom: "auto" // DYNAMIC
|
---|
260 | , height: "auto"
|
---|
261 | // width: DYNAMIC
|
---|
262 | }
|
---|
263 | }
|
---|
264 | , center: {
|
---|
265 | dir: "center"
|
---|
266 | , cssReq: {
|
---|
267 | left: "auto" // DYNAMIC
|
---|
268 | , right: "auto" // DYNAMIC
|
---|
269 | , top: "auto" // DYNAMIC
|
---|
270 | , bottom: "auto" // DYNAMIC
|
---|
271 | , height: "auto"
|
---|
272 | , width: "auto"
|
---|
273 | }
|
---|
274 | }
|
---|
275 | };
|
---|
276 |
|
---|
277 |
|
---|
278 | // DYNAMIC DATA
|
---|
279 | var state = {
|
---|
280 | // generate random 'ID#' to identify layout - used to create global namespace for timers
|
---|
281 | id: Math.floor(Math.random() * 10000)
|
---|
282 | , container: {}
|
---|
283 | , north: {}
|
---|
284 | , south: {}
|
---|
285 | , east: {}
|
---|
286 | , west: {}
|
---|
287 | , center: {}
|
---|
288 | };
|
---|
289 |
|
---|
290 |
|
---|
291 | var
|
---|
292 | altEdge = {
|
---|
293 | top: "bottom"
|
---|
294 | , bottom: "top"
|
---|
295 | , left: "right"
|
---|
296 | , right: "left"
|
---|
297 | }
|
---|
298 | , altSide = {
|
---|
299 | north: "south"
|
---|
300 | , south: "north"
|
---|
301 | , east: "west"
|
---|
302 | , west: "east"
|
---|
303 | }
|
---|
304 | ;
|
---|
305 |
|
---|
306 |
|
---|
307 | /*
|
---|
308 | * ###########################
|
---|
309 | * INTERNAL HELPER FUNCTIONS
|
---|
310 | * ###########################
|
---|
311 | */
|
---|
312 |
|
---|
313 | /**
|
---|
314 | * isStr
|
---|
315 | *
|
---|
316 | * Returns true if passed param is EITHER a simple string OR a 'string object' - otherwise returns false
|
---|
317 | */
|
---|
318 | var isStr = function (o) {
|
---|
319 | if (typeof o == "string")
|
---|
320 | return true;
|
---|
321 | else if (typeof o == "object") {
|
---|
322 | try {
|
---|
323 | var match = o.constructor.toString().match(/string/i);
|
---|
324 | return (match !== null);
|
---|
325 | } catch (e) {}
|
---|
326 | }
|
---|
327 | return false;
|
---|
328 | };
|
---|
329 |
|
---|
330 | /**
|
---|
331 | * str
|
---|
332 | *
|
---|
333 | * Returns a simple string if the passed param is EITHER a simple string OR a 'string object',
|
---|
334 | * else returns the original object
|
---|
335 | */
|
---|
336 | var str = function (o) {
|
---|
337 | if (typeof o == "string" || isStr(o)) return $.trim(o); // trim converts 'String object' to a simple string
|
---|
338 | else return o;
|
---|
339 | };
|
---|
340 |
|
---|
341 | /**
|
---|
342 | * min / max
|
---|
343 | *
|
---|
344 | * Alias for Math.min/.max to simplify coding
|
---|
345 | */
|
---|
346 | var min = function (x,y) { return Math.min(x,y); };
|
---|
347 | var max = function (x,y) { return Math.max(x,y); };
|
---|
348 |
|
---|
349 | /**
|
---|
350 | * transformData
|
---|
351 | *
|
---|
352 | * Processes the options passed in and transforms them into the format used by layout()
|
---|
353 | * Missing keys are added, and converts the data if passed in 'flat-format' (no sub-keys)
|
---|
354 | * In flat-format, pane-specific-settings are prefixed like: north__optName (2-underscores)
|
---|
355 | * To update effects, options MUST use nested-keys format, with an effects key
|
---|
356 | *
|
---|
357 | * @callers initOptions()
|
---|
358 | * @params JSON d Data/options passed by user - may be a single level or nested levels
|
---|
359 | * @returns JSON Creates a data struture that perfectly matches 'options', ready to be imported
|
---|
360 | */
|
---|
361 | var transformData = function (d) {
|
---|
362 | var json = { defaults:{fxSettings:{}}, north:{fxSettings:{}}, south:{fxSettings:{}}, east:{fxSettings:{}}, west:{fxSettings:{}}, center:{fxSettings:{}} };
|
---|
363 | d = d || {};
|
---|
364 | if (d.effects || d.defaults || d.north || d.south || d.west || d.east || d.center)
|
---|
365 | json = $.extend( json, d ); // already in json format - add to base keys
|
---|
366 | else
|
---|
367 | // convert 'flat' to 'nest-keys' format - also handles 'empty' user-options
|
---|
368 | $.each( d, function (key,val) {
|
---|
369 | a = key.split("__");
|
---|
370 | json[ a[1] ? a[0] : "defaults" ][ a[1] ? a[1] : a[0] ] = val;
|
---|
371 | });
|
---|
372 | return json;
|
---|
373 | };
|
---|
374 |
|
---|
375 | /**
|
---|
376 | * setFlowCallback
|
---|
377 | *
|
---|
378 | * Set an INTERNAL callback to avoid simultaneous animation
|
---|
379 | * Runs only if needed and only if all callbacks are not 'already set'!
|
---|
380 | *
|
---|
381 | * @param String action Either 'open' or 'close'
|
---|
382 | * @pane String pane A valid border-pane name, eg 'west'
|
---|
383 | * @pane Boolean param Extra param for callback (optional)
|
---|
384 | */
|
---|
385 | var setFlowCallback = function (action, pane, param) {
|
---|
386 | var
|
---|
387 | cb = action +","+ pane +","+ (param ? 1 : 0)
|
---|
388 | , cP, cbPane
|
---|
389 | ;
|
---|
390 | $.each(c.borderPanes.split(","), function (i,p) {
|
---|
391 | if (c[p].isMoving) {
|
---|
392 | bindCallback(p); // TRY to bind a callback
|
---|
393 | return false; // BREAK
|
---|
394 | }
|
---|
395 | });
|
---|
396 |
|
---|
397 | function bindCallback (p, test) {
|
---|
398 | cP = c[p];
|
---|
399 | if (!cP.doCallback) {
|
---|
400 | cP.doCallback = true;
|
---|
401 | cP.callback = cb;
|
---|
402 | }
|
---|
403 | else { // try to 'chain' this callback
|
---|
404 | cpPane = cP.callback.split(",")[1]; // 2nd param is 'pane'
|
---|
405 | if (cpPane != p && cpPane != pane) // callback target NOT 'itself' and NOT 'this pane'
|
---|
406 | bindCallback (cpPane, true); // RECURSE
|
---|
407 | }
|
---|
408 | }
|
---|
409 | };
|
---|
410 |
|
---|
411 | /**
|
---|
412 | * execFlowCallback
|
---|
413 | *
|
---|
414 | * RUN the INTERNAL callback for this pane - if one exists
|
---|
415 | *
|
---|
416 | * @param String action Either 'open' or 'close'
|
---|
417 | * @pane String pane A valid border-pane name, eg 'west'
|
---|
418 | * @pane Boolean param Extra param for callback (optional)
|
---|
419 | */
|
---|
420 | var execFlowCallback = function (pane) {
|
---|
421 | var cP = c[pane];
|
---|
422 |
|
---|
423 | // RESET flow-control flaGs
|
---|
424 | c.isLayoutBusy = false;
|
---|
425 | delete cP.isMoving;
|
---|
426 | if (!cP.doCallback || !cP.callback) return;
|
---|
427 |
|
---|
428 | cP.doCallback = false; // RESET logic flag
|
---|
429 |
|
---|
430 | // EXECUTE the callback
|
---|
431 | var
|
---|
432 | cb = cP.callback.split(",")
|
---|
433 | , param = (cb[2] > 0 ? true : false)
|
---|
434 | ;
|
---|
435 | if (cb[0] == "open")
|
---|
436 | open( cb[1], param );
|
---|
437 | else if (cb[0] == "close")
|
---|
438 | close( cb[1], param );
|
---|
439 |
|
---|
440 | if (!cP.doCallback) cP.callback = null; // RESET - unless callback above enabled it again!
|
---|
441 | };
|
---|
442 |
|
---|
443 | /**
|
---|
444 | * execUserCallback
|
---|
445 | *
|
---|
446 | * Executes a Callback function after a trigger event, like resize, open or close
|
---|
447 | *
|
---|
448 | * @param String pane This is passed only so we can pass the 'pane object' to the callback
|
---|
449 | * @param String v_fn Accepts a function name, OR a comma-delimited array: [0]=function name, [1]=argument
|
---|
450 | */
|
---|
451 | var execUserCallback = function (pane, v_fn) {
|
---|
452 | if (!v_fn) return;
|
---|
453 | var fn;
|
---|
454 | try {
|
---|
455 | if (typeof v_fn == "function")
|
---|
456 | fn = v_fn;
|
---|
457 | else if (typeof v_fn != "string")
|
---|
458 | return;
|
---|
459 | else if (v_fn.indexOf(",") > 0) {
|
---|
460 | // function name cannot contain a comma, so must be a function name AND a 'name' parameter
|
---|
461 | var
|
---|
462 | args = v_fn.split(",")
|
---|
463 | , fn = eval(args[0])
|
---|
464 | ;
|
---|
465 | if (typeof fn=="function" && args.length > 1)
|
---|
466 | return fn(args[1]); // pass the argument parsed from 'list'
|
---|
467 | }
|
---|
468 | else // just the name of an external function?
|
---|
469 | fn = eval(v_fn);
|
---|
470 |
|
---|
471 | if (typeof fn=="function")
|
---|
472 | // pass data: pane-name, pane-element, pane-state, pane-options, and layout-name
|
---|
473 | return fn( pane, $Ps[pane], $.extend({},state[pane]), $.extend({},options[pane]), options.name );
|
---|
474 | }
|
---|
475 | catch (ex) {}
|
---|
476 | };
|
---|
477 |
|
---|
478 | /**
|
---|
479 | * cssNum
|
---|
480 | *
|
---|
481 | * Returns the 'current CSS value' for an element - returns 0 if property does not exist
|
---|
482 | *
|
---|
483 | * @callers Called by many methods
|
---|
484 | * @param jQuery $Elem Must pass a jQuery object - first element is processed
|
---|
485 | * @param String property The name of the CSS property, eg: top, width, etc.
|
---|
486 | * @returns Variant Usually is used to get an integer value for position (top, left) or size (height, width)
|
---|
487 | */
|
---|
488 | var cssNum = function ($E, prop) {
|
---|
489 | var
|
---|
490 | val = 0
|
---|
491 | , hidden = false
|
---|
492 | , visibility = ""
|
---|
493 | ;
|
---|
494 | if (!$.browser.msie) { // IE CAN read dimensions of 'hidden' elements - FF CANNOT
|
---|
495 | if ($.curCSS($E[0], "display", true) == "none") {
|
---|
496 | hidden = true;
|
---|
497 | visibility = $.curCSS($E[0], "visibility", true); // SAVE current setting
|
---|
498 | $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so we can measure it
|
---|
499 | }
|
---|
500 | }
|
---|
501 |
|
---|
502 | val = parseInt($.curCSS($E[0], prop, true), 10) || 0;
|
---|
503 |
|
---|
504 | if (hidden) { // WAS hidden, so put back the way it was
|
---|
505 | $E.css({ display: "none" });
|
---|
506 | if (visibility && visibility != "hidden")
|
---|
507 | $E.css({ visibility: visibility }); // reset 'visibility'
|
---|
508 | }
|
---|
509 |
|
---|
510 | return val;
|
---|
511 | };
|
---|
512 |
|
---|
513 | /**
|
---|
514 | * cssW / cssH / cssSize
|
---|
515 | *
|
---|
516 | * Contains logic to check boxModel & browser, and return the correct width/height for the current browser/doctype
|
---|
517 | *
|
---|
518 | * @callers initPanes(), sizeMidPanes(), initHandles(), sizeHandles()
|
---|
519 | * @param Variant elem Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object
|
---|
520 | * @param Integer outerWidth/outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized
|
---|
521 | * @returns Integer Returns the innerHeight of the elem by subtracting padding and borders
|
---|
522 | *
|
---|
523 | * @TODO May need to add additional logic to handle more browser/doctype variations?
|
---|
524 | */
|
---|
525 | var cssW = function (e, outerWidth) {
|
---|
526 | var $E;
|
---|
527 | if (isStr(e)) {
|
---|
528 | e = str(e);
|
---|
529 | $E = $Ps[e];
|
---|
530 | }
|
---|
531 | else
|
---|
532 | $E = $(e);
|
---|
533 |
|
---|
534 | // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed
|
---|
535 | if (outerWidth <= 0)
|
---|
536 | return 0;
|
---|
537 | else if (!(outerWidth>0))
|
---|
538 | outerWidth = isStr(e) ? getPaneSize(e) : $E.outerWidth();
|
---|
539 |
|
---|
540 | if (!$.boxModel)
|
---|
541 | return outerWidth;
|
---|
542 |
|
---|
543 | else // strip border and padding size from outerWidth to get CSS Width
|
---|
544 | return outerWidth
|
---|
545 | - cssNum($E, "paddingLeft")
|
---|
546 | - cssNum($E, "paddingRight")
|
---|
547 | - ($.curCSS($E[0], "borderLeftStyle", true) == "none" ? 0 : cssNum($E, "borderLeftWidth"))
|
---|
548 | - ($.curCSS($E[0], "borderRightStyle", true) == "none" ? 0 : cssNum($E, "borderRightWidth"))
|
---|
549 | ;
|
---|
550 | };
|
---|
551 | var cssH = function (e, outerHeight) {
|
---|
552 | var $E;
|
---|
553 | if (isStr(e)) {
|
---|
554 | e = str(e);
|
---|
555 | $E = $Ps[e];
|
---|
556 | }
|
---|
557 | else
|
---|
558 | $E = $(e);
|
---|
559 |
|
---|
560 | // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed
|
---|
561 | if (outerHeight <= 0)
|
---|
562 | return 0;
|
---|
563 | else if (!(outerHeight>0))
|
---|
564 | outerHeight = (isStr(e)) ? getPaneSize(e) : $E.outerHeight();
|
---|
565 |
|
---|
566 | if (!$.boxModel)
|
---|
567 | return outerHeight;
|
---|
568 |
|
---|
569 | else // strip border and padding size from outerHeight to get CSS Height
|
---|
570 | return outerHeight
|
---|
571 | - cssNum($E, "paddingTop")
|
---|
572 | - cssNum($E, "paddingBottom")
|
---|
573 | - ($.curCSS($E[0], "borderTopStyle", true) == "none" ? 0 : cssNum($E, "borderTopWidth"))
|
---|
574 | - ($.curCSS($E[0], "borderBottomStyle", true) == "none" ? 0 : cssNum($E, "borderBottomWidth"))
|
---|
575 | ;
|
---|
576 | };
|
---|
577 | var cssSize = function (pane, outerSize) {
|
---|
578 | if (c[pane].dir=="horz") // pane = north or south
|
---|
579 | return cssH(pane, outerSize);
|
---|
580 | else // pane = east or west
|
---|
581 | return cssW(pane, outerSize);
|
---|
582 | };
|
---|
583 |
|
---|
584 | /**
|
---|
585 | * getPaneSize
|
---|
586 | *
|
---|
587 | * Calculates the current 'size' (width or height) of a border-pane - optionally with 'pane spacing' added
|
---|
588 | *
|
---|
589 | * @returns Integer Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser
|
---|
590 | */
|
---|
591 | var getPaneSize = function (pane, inclSpace) {
|
---|
592 | var
|
---|
593 | $P = $Ps[pane]
|
---|
594 | , o = options[pane]
|
---|
595 | , s = state[pane]
|
---|
596 | , oSp = (inclSpace ? o.spacing_open : 0)
|
---|
597 | , cSp = (inclSpace ? o.spacing_closed : 0)
|
---|
598 | ;
|
---|
599 | if (!$P || s.isHidden)
|
---|
600 | return 0;
|
---|
601 | else if (s.isClosed || (s.isSliding && inclSpace))
|
---|
602 | return cSp;
|
---|
603 | else if (c[pane].dir == "horz")
|
---|
604 | return $P.outerHeight() + oSp;
|
---|
605 | else // dir == "vert"
|
---|
606 | return $P.outerWidth() + oSp;
|
---|
607 | };
|
---|
608 |
|
---|
609 | var setPaneMinMaxSizes = function (pane) {
|
---|
610 | var
|
---|
611 | d = cDims
|
---|
612 | , edge = c[pane].edge
|
---|
613 | , dir = c[pane].dir
|
---|
614 | , o = options[pane]
|
---|
615 | , s = state[pane]
|
---|
616 | , $P = $Ps[pane]
|
---|
617 | , $altPane = $Ps[ altSide[pane] ]
|
---|
618 | , paneSpacing = o.spacing_open
|
---|
619 | , altPaneSpacing = options[ altSide[pane] ].spacing_open
|
---|
620 | , altPaneSize = (!$altPane ? 0 : (dir=="horz" ? $altPane.outerHeight() : $altPane.outerWidth()))
|
---|
621 | , containerSize = (dir=="horz" ? d.innerHeight : d.innerWidth)
|
---|
622 | // limitSize prevents this pane from 'overlapping' opposite pane - even if opposite pane is currently closed
|
---|
623 | , limitSize = containerSize - paneSpacing - altPaneSize - altPaneSpacing
|
---|
624 | , minSize = s.minSize || 0
|
---|
625 | , maxSize = Math.min(s.maxSize || 9999, limitSize)
|
---|
626 | , minPos, maxPos // used to set resizing limits
|
---|
627 | ;
|
---|
628 | switch (pane) {
|
---|
629 | case "north": minPos = d.offsetTop + minSize;
|
---|
630 | maxPos = d.offsetTop + maxSize;
|
---|
631 | break;
|
---|
632 | case "west": minPos = d.offsetLeft + minSize;
|
---|
633 | maxPos = d.offsetLeft + maxSize;
|
---|
634 | break;
|
---|
635 | case "south": minPos = d.offsetTop + d.innerHeight - maxSize;
|
---|
636 | maxPos = d.offsetTop + d.innerHeight - minSize;
|
---|
637 | break;
|
---|
638 | case "east": minPos = d.offsetLeft + d.innerWidth - maxSize;
|
---|
639 | maxPos = d.offsetLeft + d.innerWidth - minSize;
|
---|
640 | break;
|
---|
641 | }
|
---|
642 | // save data to pane-state
|
---|
643 | $.extend(s, { minSize: minSize, maxSize: maxSize, minPosition: minPos, maxPosition: maxPos });
|
---|
644 | };
|
---|
645 |
|
---|
646 | /**
|
---|
647 | * getPaneDims
|
---|
648 | *
|
---|
649 | * Returns data for setting the size/position of center pane. Date is also used to set Height for east/west panes
|
---|
650 | *
|
---|
651 | * @returns JSON Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height
|
---|
652 | */
|
---|
653 | var getPaneDims = function () {
|
---|
654 | var d = {
|
---|
655 | top: getPaneSize("north", true) // true = include 'spacing' value for p
|
---|
656 | , bottom: getPaneSize("south", true)
|
---|
657 | , left: getPaneSize("west", true)
|
---|
658 | , right: getPaneSize("east", true)
|
---|
659 | , width: 0
|
---|
660 | , height: 0
|
---|
661 | };
|
---|
662 |
|
---|
663 | with (d) {
|
---|
664 | width = cDims.innerWidth - left - right;
|
---|
665 | height = cDims.innerHeight - bottom - top;
|
---|
666 | // now add the 'container border/padding' to get final positions - relative to the container
|
---|
667 | top += cDims.top;
|
---|
668 | bottom += cDims.bottom;
|
---|
669 | left += cDims.left;
|
---|
670 | right += cDims.right;
|
---|
671 | }
|
---|
672 |
|
---|
673 | return d;
|
---|
674 | };
|
---|
675 |
|
---|
676 |
|
---|
677 | /**
|
---|
678 | * getElemDims
|
---|
679 | *
|
---|
680 | * Returns data for setting size of an element (container or a pane).
|
---|
681 | *
|
---|
682 | * @callers create(), onWindowResize() for container, plus others for pane
|
---|
683 | * @returns JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc
|
---|
684 | */
|
---|
685 | var getElemDims = function ($E) {
|
---|
686 | var
|
---|
687 | d = {} // dimensions hash
|
---|
688 | , e, b, p // edge, border, padding
|
---|
689 | ;
|
---|
690 |
|
---|
691 | $.each("Left,Right,Top,Bottom".split(","), function () {
|
---|
692 | e = str(this);
|
---|
693 | b = d["border" +e] = cssNum($E, "border"+e+"Width");
|
---|
694 | p = d["padding"+e] = cssNum($E, "padding"+e);
|
---|
695 | d["offset" +e] = b + p; // total offset of content from outer edge
|
---|
696 | // if BOX MODEL, then 'position' = PADDING (ignore borderWidth)
|
---|
697 | if ($E == $Container)
|
---|
698 | d[e.toLowerCase()] = ($.boxModel ? p : 0);
|
---|
699 | });
|
---|
700 |
|
---|
701 | d.innerWidth = d.outerWidth = $E.outerWidth();
|
---|
702 | d.innerHeight = d.outerHeight = $E.outerHeight();
|
---|
703 | if ($.boxModel) {
|
---|
704 | d.innerWidth -= (d.offsetLeft + d.offsetRight);
|
---|
705 | d.innerHeight -= (d.offsetTop + d.offsetBottom);
|
---|
706 | }
|
---|
707 |
|
---|
708 | return d;
|
---|
709 | };
|
---|
710 |
|
---|
711 |
|
---|
712 | var setTimer = function (pane, action, fn, ms) {
|
---|
713 | var
|
---|
714 | Layout = window.layout = window.layout || {}
|
---|
715 | , Timers = Layout.timers = Layout.timers || {}
|
---|
716 | , name = "layout_"+ state.id +"_"+ pane +"_"+ action // UNIQUE NAME for every layout-pane-action
|
---|
717 | ;
|
---|
718 | if (Timers[name]) return; // timer already set!
|
---|
719 | else Timers[name] = setTimeout(fn, ms);
|
---|
720 | };
|
---|
721 |
|
---|
722 | var clearTimer = function (pane, action) {
|
---|
723 | var
|
---|
724 | Layout = window.layout = window.layout || {}
|
---|
725 | , Timers = Layout.timers = Layout.timers || {}
|
---|
726 | , name = "layout_"+ state.id +"_"+ pane +"_"+ action // UNIQUE NAME for every layout-pane-action
|
---|
727 | ;
|
---|
728 | if (Timers[name]) {
|
---|
729 | clearTimeout( Timers[name] );
|
---|
730 | delete Timers[name];
|
---|
731 | return true;
|
---|
732 | }
|
---|
733 | else
|
---|
734 | return false;
|
---|
735 | };
|
---|
736 |
|
---|
737 |
|
---|
738 | /*
|
---|
739 | * ###########################
|
---|
740 | * INITIALIZATION METHODS
|
---|
741 | * ###########################
|
---|
742 | */
|
---|
743 |
|
---|
744 | /**
|
---|
745 | * create
|
---|
746 | *
|
---|
747 | * Initialize the layout - called automatically whenever an instance of layout is created
|
---|
748 | *
|
---|
749 | * @callers NEVER explicity called
|
---|
750 | * @returns An object pointer to the instance created
|
---|
751 | */
|
---|
752 | var create = function () {
|
---|
753 | // initialize config/options
|
---|
754 | initOptions();
|
---|
755 |
|
---|
756 | // initialize all objects
|
---|
757 | initContainer(); // set CSS as needed and init state.container dimensions
|
---|
758 | initPanes(); // size & position all panes
|
---|
759 | initHandles(); // create and position all resize bars & togglers buttons
|
---|
760 | initResizable(); // activate resizing on all panes where resizable=true
|
---|
761 | sizeContent("all"); // AFTER panes & handles have been initialized, size 'content' divs
|
---|
762 |
|
---|
763 | if (options.scrollToBookmarkOnLoad)
|
---|
764 | with (self.location) if (hash) replace( hash ); // scrollTo Bookmark
|
---|
765 |
|
---|
766 | // bind hotkey function - keyDown - if required
|
---|
767 | initHotkeys();
|
---|
768 |
|
---|
769 | // bind resizeAll() for 'this layout instance' to window.resize event
|
---|
770 | $(window).resize(function () {
|
---|
771 | var timerID = "timerLayout_"+state.id;
|
---|
772 | if (window[timerID]) clearTimeout(window[timerID]);
|
---|
773 | window[timerID] = null;
|
---|
774 | if (true || $.browser.msie) // use a delay for IE because the resize event fires repeatly
|
---|
775 | window[timerID] = setTimeout(resizeAll, 100);
|
---|
776 | else // most other browsers have a built-in delay before firing the resize event
|
---|
777 | resizeAll(); // resize all layout elements NOW!
|
---|
778 | });
|
---|
779 | };
|
---|
780 |
|
---|
781 | /**
|
---|
782 | * initContainer
|
---|
783 | *
|
---|
784 | * Validate and initialize container CSS and events
|
---|
785 | *
|
---|
786 | * @callers create()
|
---|
787 | */
|
---|
788 | var initContainer = function () {
|
---|
789 | try { // format html/body if this is a full page layout
|
---|
790 | if ($Container[0].tagName == "BODY") {
|
---|
791 | $("html").css({
|
---|
792 | height: "100%"
|
---|
793 | , overflow: "hidden"
|
---|
794 | });
|
---|
795 | $("body").css({
|
---|
796 | position: "relative"
|
---|
797 | , height: "100%"
|
---|
798 | , overflow: "hidden"
|
---|
799 | , margin: 0
|
---|
800 | , padding: 0 // TODO: test whether body-padding could be handled?
|
---|
801 | , border: "none" // a body-border creates problems because it cannot be measured!
|
---|
802 | });
|
---|
803 | }
|
---|
804 | else { // set required CSS - overflow and position
|
---|
805 | var
|
---|
806 | CSS = { overflow: "hidden" } // make sure container will not 'scroll'
|
---|
807 | , p = $Container.css("position")
|
---|
808 | , h = $Container.css("height")
|
---|
809 | ;
|
---|
810 | // if this is a NESTED layout, then outer-pane ALREADY has position and height
|
---|
811 | if (!$Container.hasClass("ui-layout-pane")) {
|
---|
812 | if (!p || "fixed,absolute,relative".indexOf(p) < 0)
|
---|
813 | CSS.position = "relative"; // container MUST have a 'position'
|
---|
814 | if (!h || h=="auto")
|
---|
815 | CSS.height = "100%"; // container MUST have a 'height'
|
---|
816 | }
|
---|
817 | $Container.css( CSS );
|
---|
818 | }
|
---|
819 | } catch (ex) {}
|
---|
820 |
|
---|
821 | // get layout-container dimensions (updated when necessary)
|
---|
822 | cDims = state.container = getElemDims( $Container ); // update data-pointer too
|
---|
823 | };
|
---|
824 |
|
---|
825 | /**
|
---|
826 | * initHotkeys
|
---|
827 | *
|
---|
828 | * Bind layout hotkeys - if options enabled
|
---|
829 | *
|
---|
830 | * @callers create()
|
---|
831 | */
|
---|
832 | var initHotkeys = function () {
|
---|
833 | // bind keyDown to capture hotkeys, if option enabled for ANY pane
|
---|
834 | $.each(c.borderPanes.split(","), function (i,pane) {
|
---|
835 | var o = options[pane];
|
---|
836 | if (o.enableCursorHotkey || o.customHotkey) {
|
---|
837 | $(document).keydown( keyDown ); // only need to bind this ONCE
|
---|
838 | return false; // BREAK - binding was done
|
---|
839 | }
|
---|
840 | });
|
---|
841 | };
|
---|
842 |
|
---|
843 | /**
|
---|
844 | * initOptions
|
---|
845 | *
|
---|
846 | * Build final CONFIG and OPTIONS data
|
---|
847 | *
|
---|
848 | * @callers create()
|
---|
849 | */
|
---|
850 | var initOptions = function () {
|
---|
851 | // simplify logic by making sure passed 'opts' var has basic keys
|
---|
852 | opts = transformData( opts );
|
---|
853 |
|
---|
854 | // update default effects, if case user passed key
|
---|
855 | if (opts.effects) {
|
---|
856 | $.extend( effects, opts.effects );
|
---|
857 | delete opts.effects;
|
---|
858 | }
|
---|
859 |
|
---|
860 | // see if any 'global options' were specified
|
---|
861 | $.each("name,scrollToBookmarkOnLoad".split(","), function (idx,key) {
|
---|
862 | if (opts[key] !== undefined)
|
---|
863 | options[key] = opts[key];
|
---|
864 | else if (opts.defaults[key] !== undefined) {
|
---|
865 | options[key] = opts.defaults[key];
|
---|
866 | delete opts.defaults[key];
|
---|
867 | }
|
---|
868 | });
|
---|
869 |
|
---|
870 | // remove any 'defaults' that MUST be set 'per-pane'
|
---|
871 | $.each("paneSelector,resizerCursor,customHotkey".split(","),
|
---|
872 | function (idx,key) { delete opts.defaults[key]; } // is OK if key does not exist
|
---|
873 | );
|
---|
874 |
|
---|
875 | // now update options.defaults
|
---|
876 | $.extend( options.defaults, opts.defaults );
|
---|
877 | // make sure required sub-keys exist
|
---|
878 | //if (typeof options.defaults.fxSettings != "object") options.defaults.fxSettings = {};
|
---|
879 |
|
---|
880 | // merge all config & options for the 'center' pane
|
---|
881 | c.center = $.extend( true, {}, c.defaults, c.center );
|
---|
882 | $.extend( options.center, opts.center );
|
---|
883 | // Most 'default options' do not apply to 'center', so add only those that DO
|
---|
884 | var o_Center = $.extend( true, {}, options.defaults, opts.defaults, options.center ); // TEMP data
|
---|
885 | $.each("paneClass,contentSelector,contentIgnoreSelector,applyDefaultStyles,showOverflowOnHover".split(","),
|
---|
886 | function (idx,key) { options.center[key] = o_Center[key]; }
|
---|
887 | );
|
---|
888 |
|
---|
889 | var defs = options.defaults;
|
---|
890 |
|
---|
891 | // create a COMPLETE set of options for EACH border-pane
|
---|
892 | $.each(c.borderPanes.split(","), function(i,pane) {
|
---|
893 | // apply 'pane-defaults' to CONFIG.PANE
|
---|
894 | c[pane] = $.extend( true, {}, c.defaults, c[pane] );
|
---|
895 | // apply 'pane-defaults' + user-options to OPTIONS.PANE
|
---|
896 | o = options[pane] = $.extend( true, {}, options.defaults, options[pane], opts.defaults, opts[pane] );
|
---|
897 |
|
---|
898 | // make sure we have base-classes
|
---|
899 | if (!o.paneClass) o.paneClass = defaults.paneClass;
|
---|
900 | if (!o.resizerClass) o.resizerClass = defaults.resizerClass;
|
---|
901 | if (!o.togglerClass) o.togglerClass = defaults.togglerClass;
|
---|
902 |
|
---|
903 | // create FINAL fx options for each pane, ie: options.PANE.fxName/fxSpeed/fxSettings[_open|_close]
|
---|
904 | $.each(["_open","_close",""], function (i,n) {
|
---|
905 | var
|
---|
906 | sName = "fxName"+n
|
---|
907 | , sSpeed = "fxSpeed"+n
|
---|
908 | , sSettings = "fxSettings"+n
|
---|
909 | ;
|
---|
910 | // recalculate fxName according to specificity rules
|
---|
911 | o[sName] =
|
---|
912 | opts[pane][sName] // opts.west.fxName_open
|
---|
913 | || opts[pane].fxName // opts.west.fxName
|
---|
914 | || opts.defaults[sName] // opts.defaults.fxName_open
|
---|
915 | || opts.defaults.fxName // opts.defaults.fxName
|
---|
916 | || o[sName] // options.west.fxName_open
|
---|
917 | || o.fxName // options.west.fxName
|
---|
918 | || defs[sName] // options.defaults.fxName_open
|
---|
919 | || defs.fxName // options.defaults.fxName
|
---|
920 | || "none"
|
---|
921 | ;
|
---|
922 | // validate fxName to be sure is a valid effect
|
---|
923 | var fxName = o[sName];
|
---|
924 | if (fxName == "none" || !$.effects || !$.effects[fxName] || (!effects[fxName] && !o[sSettings] && !o.fxSettings))
|
---|
925 | fxName = o[sName] = "none"; // effect not loaded, OR undefined FX AND fxSettings not passed
|
---|
926 | // set vars for effects subkeys to simplify logic
|
---|
927 | var
|
---|
928 | fx = effects[fxName] || {} // effects.slide
|
---|
929 | , fx_all = fx.all || {} // effects.slide.all
|
---|
930 | , fx_pane = fx[pane] || {} // effects.slide.west
|
---|
931 | ;
|
---|
932 | // RECREATE the fxSettings[_open|_close] keys using specificity rules
|
---|
933 | o[sSettings] = $.extend(
|
---|
934 | {}
|
---|
935 | , fx_all // effects.slide.all
|
---|
936 | , fx_pane // effects.slide.west
|
---|
937 | , defs.fxSettings || {} // options.defaults.fxSettings
|
---|
938 | , defs[sSettings] || {} // options.defaults.fxSettings_open
|
---|
939 | , o.fxSettings // options.west.fxSettings
|
---|
940 | , o[sSettings] // options.west.fxSettings_open
|
---|
941 | , opts.defaults.fxSettings // opts.defaults.fxSettings
|
---|
942 | , opts.defaults[sSettings] || {} // opts.defaults.fxSettings_open
|
---|
943 | , opts[pane].fxSettings // opts.west.fxSettings
|
---|
944 | , opts[pane][sSettings] || {} // opts.west.fxSettings_open
|
---|
945 | );
|
---|
946 | // recalculate fxSpeed according to specificity rules
|
---|
947 | o[sSpeed] =
|
---|
948 | opts[pane][sSpeed] // opts.west.fxSpeed_open
|
---|
949 | || opts[pane].fxSpeed // opts.west.fxSpeed (pane-default)
|
---|
950 | || opts.defaults[sSpeed] // opts.defaults.fxSpeed_open
|
---|
951 | || opts.defaults.fxSpeed // opts.defaults.fxSpeed
|
---|
952 | || o[sSpeed] // options.west.fxSpeed_open
|
---|
953 | || o[sSettings].duration // options.west.fxSettings_open.duration
|
---|
954 | || o.fxSpeed // options.west.fxSpeed
|
---|
955 | || o.fxSettings.duration // options.west.fxSettings.duration
|
---|
956 | || defs.fxSpeed // options.defaults.fxSpeed
|
---|
957 | || defs.fxSettings.duration// options.defaults.fxSettings.duration
|
---|
958 | || fx_pane.duration // effects.slide.west.duration
|
---|
959 | || fx_all.duration // effects.slide.all.duration
|
---|
960 | || "normal" // DEFAULT
|
---|
961 | ;
|
---|
962 | // DEBUG: if (pane=="east") debugData( $.extend({}, {speed: o[sSpeed], fxSettings_duration: o[sSettings].duration}, o[sSettings]), pane+"."+sName+" = "+fxName );
|
---|
963 | });
|
---|
964 | });
|
---|
965 | };
|
---|
966 |
|
---|
967 | /**
|
---|
968 | * initPanes
|
---|
969 | *
|
---|
970 | * Initialize module objects, styling, size and position for all panes
|
---|
971 | *
|
---|
972 | * @callers create()
|
---|
973 | */
|
---|
974 | var initPanes = function () {
|
---|
975 | // NOTE: do north & south FIRST so we can measure their height - do center LAST
|
---|
976 | $.each(c.allPanes.split(","), function() {
|
---|
977 | var
|
---|
978 | pane = str(this)
|
---|
979 | , o = options[pane]
|
---|
980 | , s = state[pane]
|
---|
981 | , fx = s.fx
|
---|
982 | , dir = c[pane].dir
|
---|
983 | // if o.size is not > 0, then we will use MEASURE the pane and use that as it's 'size'
|
---|
984 | , size = o.size=="auto" || isNaN(o.size) ? 0 : o.size
|
---|
985 | , minSize = o.minSize || 1
|
---|
986 | , maxSize = o.maxSize || 9999
|
---|
987 | , spacing = o.spacing_open || 0
|
---|
988 | , sel = o.paneSelector
|
---|
989 | , isIE6 = ($.browser.msie && $.browser.version < 7)
|
---|
990 | , CSS = {}
|
---|
991 | , $P, $C
|
---|
992 | ;
|
---|
993 | $Cs[pane] = false; // init
|
---|
994 |
|
---|
995 | if (sel.substr(0,1)==="#") // ID selector
|
---|
996 | // NOTE: elements selected 'by ID' DO NOT have to be 'children'
|
---|
997 | $P = $Ps[pane] = $Container.find(sel+":first");
|
---|
998 | else { // class or other selector
|
---|
999 | $P = $Ps[pane] = $Container.children(sel+":first");
|
---|
1000 | // look for the pane nested inside a 'form' element
|
---|
1001 | if (!$P.length) $P = $Ps[pane] = $Container.children("form:first").children(sel+":first");
|
---|
1002 | }
|
---|
1003 |
|
---|
1004 | if (!$P.length) {
|
---|
1005 | $Ps[pane] = false; // logic
|
---|
1006 | return true; // SKIP to next
|
---|
1007 | }
|
---|
1008 |
|
---|
1009 | // add basic classes & attributes
|
---|
1010 | $P
|
---|
1011 | .attr("pane", pane) // add pane-identifier
|
---|
1012 | .addClass( o.paneClass +" "+ o.paneClass+"-"+pane ) // default = "ui-layout-pane ui-layout-pane-west" - may be a dupe of 'paneSelector'
|
---|
1013 | ;
|
---|
1014 |
|
---|
1015 | // init pane-logic vars, etc.
|
---|
1016 | if (pane != "center") {
|
---|
1017 | s.isClosed = false; // true = pane is closed
|
---|
1018 | s.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes
|
---|
1019 | s.isResizing= false; // true = pane is in process of being resized
|
---|
1020 | s.isHidden = false; // true = pane is hidden - no spacing, resizer or toggler is visible!
|
---|
1021 | s.noRoom = false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically
|
---|
1022 | // create special keys for internal use
|
---|
1023 | c[pane].pins = []; // used to track and sync 'pin-buttons' for border-panes
|
---|
1024 | }
|
---|
1025 |
|
---|
1026 | CSS = $.extend({ visibility: "visible", display: "block" }, c.defaults.cssReq, c[pane].cssReq );
|
---|
1027 | if (o.applyDefaultStyles) $.extend( CSS, c.defaults.cssDef, c[pane].cssDef ); // cosmetic defaults
|
---|
1028 | $P.css(CSS); // add base-css BEFORE 'measuring' to calc size & position
|
---|
1029 | CSS = {}; // reset var
|
---|
1030 |
|
---|
1031 | // set css-position to account for container borders & padding
|
---|
1032 | switch (pane) {
|
---|
1033 | case "north": CSS.top = cDims.top;
|
---|
1034 | CSS.left = cDims.left;
|
---|
1035 | CSS.right = cDims.right;
|
---|
1036 | break;
|
---|
1037 | case "south": CSS.bottom = cDims.bottom;
|
---|
1038 | CSS.left = cDims.left;
|
---|
1039 | CSS.right = cDims.right;
|
---|
1040 | break;
|
---|
1041 | case "west": CSS.left = cDims.left; // top, bottom & height set by sizeMidPanes()
|
---|
1042 | break;
|
---|
1043 | case "east": CSS.right = cDims.right; // ditto
|
---|
1044 | break;
|
---|
1045 | case "center": // top, left, width & height set by sizeMidPanes()
|
---|
1046 | }
|
---|
1047 |
|
---|
1048 | if (dir == "horz") { // north or south pane
|
---|
1049 | if (size === 0 || size == "auto") {
|
---|
1050 | $P.css({ height: "auto" });
|
---|
1051 | size = $P.outerHeight();
|
---|
1052 | }
|
---|
1053 | size = max(size, minSize);
|
---|
1054 | size = min(size, maxSize);
|
---|
1055 | size = min(size, cDims.innerHeight - spacing);
|
---|
1056 | CSS.height = max(1, cssH(pane, size));
|
---|
1057 | s.size = size; // update state
|
---|
1058 | // make sure minSize is sufficient to avoid errors
|
---|
1059 | s.maxSize = maxSize; // init value
|
---|
1060 | s.minSize = max(minSize, size - CSS.height + 1); // = pane.outerHeight when css.height = 1px
|
---|
1061 | // handle IE6
|
---|
1062 | //if (isIE6) CSS.width = cssW($P, cDims.innerWidth);
|
---|
1063 | $P.css(CSS); // apply size & position
|
---|
1064 | }
|
---|
1065 | else if (dir == "vert") { // east or west pane
|
---|
1066 | if (size === 0 || size == "auto") {
|
---|
1067 | $P.css({ width: "auto", float: "left" }); // float = FORCE pane to auto-size
|
---|
1068 | size = $P.outerWidth();
|
---|
1069 | $P.css({ float: "none" }); // RESET
|
---|
1070 | }
|
---|
1071 | size = max(size, minSize);
|
---|
1072 | size = min(size, maxSize);
|
---|
1073 | size = min(size, cDims.innerWidth - spacing);
|
---|
1074 | CSS.width = max(1, cssW(pane, size));
|
---|
1075 | s.size = size; // update state
|
---|
1076 | s.maxSize = maxSize; // init value
|
---|
1077 | // make sure minSize is sufficient to avoid errors
|
---|
1078 | s.minSize = max(minSize, size - CSS.width + 1); // = pane.outerWidth when css.width = 1px
|
---|
1079 | $P.css(CSS); // apply size - top, bottom & height set by sizeMidPanes
|
---|
1080 | sizeMidPanes(pane, null, true); // true = onInit
|
---|
1081 | }
|
---|
1082 | else if (pane == "center") {
|
---|
1083 | $P.css(CSS); // top, left, width & height set by sizeMidPanes...
|
---|
1084 | sizeMidPanes("center", null, true); // true = onInit
|
---|
1085 | }
|
---|
1086 |
|
---|
1087 | // close or hide the pane if specified in settings
|
---|
1088 | if (o.initClosed && o.closable) {
|
---|
1089 | $P.hide().addClass("closed");
|
---|
1090 | s.isClosed = true;
|
---|
1091 | }
|
---|
1092 | else if (o.initHidden || o.initClosed) {
|
---|
1093 | hide(pane, true); // will be completely invisible - no resizer or spacing
|
---|
1094 | s.isHidden = true;
|
---|
1095 | }
|
---|
1096 | else
|
---|
1097 | $P.addClass("open");
|
---|
1098 |
|
---|
1099 | // check option for auto-handling of pop-ups & drop-downs
|
---|
1100 | if (o.showOverflowOnHover)
|
---|
1101 | $P.hover( allowOverflow, resetOverflow );
|
---|
1102 |
|
---|
1103 | /*
|
---|
1104 | * see if this pane has a 'content element' that we need to auto-size
|
---|
1105 | */
|
---|
1106 | if (o.contentSelector) {
|
---|
1107 | $C = $Cs[pane] = $P.children(o.contentSelector+":first"); // match 1-element only
|
---|
1108 | if (!$C.length) {
|
---|
1109 | $Cs[pane] = false;
|
---|
1110 | return true; // SKIP to next
|
---|
1111 | }
|
---|
1112 | $C.css( c.content.cssReq );
|
---|
1113 | if (o.applyDefaultStyles) $C.css( c.content.cssDef ); // cosmetic defaults
|
---|
1114 | // NO PANE-SCROLLING when there is a content-div
|
---|
1115 | $P.css({ overflow: "hidden" });
|
---|
1116 | }
|
---|
1117 | });
|
---|
1118 | };
|
---|
1119 |
|
---|
1120 | /**
|
---|
1121 | * initHandles
|
---|
1122 | *
|
---|
1123 | * Initialize module objects, styling, size and position for all resize bars and toggler buttons
|
---|
1124 | *
|
---|
1125 | * @callers create()
|
---|
1126 | */
|
---|
1127 | var initHandles = function () {
|
---|
1128 | // create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV
|
---|
1129 | $.each(c.borderPanes.split(","), function() {
|
---|
1130 | var
|
---|
1131 | pane = str(this)
|
---|
1132 | , o = options[pane]
|
---|
1133 | , s = state[pane]
|
---|
1134 | , rClass = o.resizerClass
|
---|
1135 | , tClass = o.togglerClass
|
---|
1136 | , $P = $Ps[pane]
|
---|
1137 | ;
|
---|
1138 | $Rs[pane] = false; // INIT
|
---|
1139 | $Ts[pane] = false;
|
---|
1140 |
|
---|
1141 | if (!$P || (!o.closable && !o.resizable)) return; // pane does not exist - skip
|
---|
1142 |
|
---|
1143 | var
|
---|
1144 | edge = c[pane].edge
|
---|
1145 | , isOpen = $P.is(":visible")
|
---|
1146 | , spacing = (isOpen ? o.spacing_open : o.spacing_closed)
|
---|
1147 | , _pane = "-"+ pane // used for classNames
|
---|
1148 | , _state = (isOpen ? "-open" : "-closed") // used for classNames
|
---|
1149 | , $R, $T
|
---|
1150 | ;
|
---|
1151 | // INIT RESIZER BAR
|
---|
1152 | $R = $Rs[pane] = $("<span></span>");
|
---|
1153 |
|
---|
1154 | if (isOpen && o.resizable)
|
---|
1155 | ; // this is handled by initResizable
|
---|
1156 | else if (!isOpen && o.slidable)
|
---|
1157 | $R.attr("title", o.sliderTip).css("cursor", o.sliderCursor);
|
---|
1158 |
|
---|
1159 | $R
|
---|
1160 | // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-resizer"
|
---|
1161 | .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-resizer" : ""))
|
---|
1162 | .attr("resizer", pane) // so we can read this from the resizer
|
---|
1163 | .css(c.resizers.cssReq) // add base/required styles
|
---|
1164 | // POSITION of resizer bar - allow for container border & padding
|
---|
1165 | .css(edge, cDims[edge] + getPaneSize(pane))
|
---|
1166 | // ADD CLASSNAMES - eg: class="resizer resizer-west resizer-open"
|
---|
1167 | .addClass( rClass +" "+ rClass+_pane +" "+ rClass+_state +" "+ rClass+_pane+_state )
|
---|
1168 | .appendTo($Container) // append DIV to container
|
---|
1169 | ;
|
---|
1170 | // ADD VISUAL STYLES
|
---|
1171 | if (o.applyDefaultStyles)
|
---|
1172 | $R.css(c.resizers.cssDef);
|
---|
1173 |
|
---|
1174 | if (o.closable) {
|
---|
1175 | // INIT COLLAPSER BUTTON
|
---|
1176 | $T = $Ts[pane] = $("<div></div>");
|
---|
1177 | $T
|
---|
1178 | // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-toggler"
|
---|
1179 | .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-toggler" : ""))
|
---|
1180 | .css(c.togglers.cssReq) // add base/required styles
|
---|
1181 | .attr("title", (isOpen ? o.togglerTip_open : o.togglerTip_closed))
|
---|
1182 | .click(function(evt){ toggle(pane); evt.stopPropagation(); })
|
---|
1183 | .mouseover(function(evt){ evt.stopPropagation(); }) // prevent resizer event
|
---|
1184 | // ADD CLASSNAMES - eg: class="toggler toggler-west toggler-west-open"
|
---|
1185 | .addClass( tClass +" "+ tClass+_pane +" "+ tClass+_state +" "+ tClass+_pane+_state )
|
---|
1186 | .appendTo($R) // append SPAN to resizer DIV
|
---|
1187 | ;
|
---|
1188 |
|
---|
1189 | // ADD INNER-SPANS TO TOGGLER
|
---|
1190 | if (o.togglerContent_open) // ui-layout-open
|
---|
1191 | $("<span>"+ o.togglerContent_open +"</span>")
|
---|
1192 | .addClass("content content-open")
|
---|
1193 | .css("display", s.isClosed ? "none" : "block")
|
---|
1194 | .appendTo( $T )
|
---|
1195 | ;
|
---|
1196 | if (o.togglerContent_closed) // ui-layout-closed
|
---|
1197 | $("<span>"+ o.togglerContent_closed +"</span>")
|
---|
1198 | .addClass("content content-closed")
|
---|
1199 | .css("display", s.isClosed ? "block" : "none")
|
---|
1200 | .appendTo( $T )
|
---|
1201 | ;
|
---|
1202 |
|
---|
1203 | // ADD BASIC VISUAL STYLES
|
---|
1204 | if (o.applyDefaultStyles)
|
---|
1205 | $T.css(c.togglers.cssDef);
|
---|
1206 |
|
---|
1207 | if (!isOpen) bindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true
|
---|
1208 | }
|
---|
1209 |
|
---|
1210 | });
|
---|
1211 |
|
---|
1212 | // SET ALL HANDLE SIZES & LENGTHS
|
---|
1213 | sizeHandles("all", true); // true = onInit
|
---|
1214 | };
|
---|
1215 |
|
---|
1216 | /**
|
---|
1217 | * initResizable
|
---|
1218 | *
|
---|
1219 | * Add resize-bars to all panes that specify it in options
|
---|
1220 | *
|
---|
1221 | * @dependancies $.fn.resizable - will abort if not found
|
---|
1222 | * @callers create()
|
---|
1223 | */
|
---|
1224 | var initResizable = function () {
|
---|
1225 | var
|
---|
1226 | draggingAvailable = (typeof $.fn.draggable == "function")
|
---|
1227 | , minPosition, maxPosition, edge // set in start()
|
---|
1228 | ;
|
---|
1229 |
|
---|
1230 | $.each(c.borderPanes.split(","), function() {
|
---|
1231 | var
|
---|
1232 | pane = str(this)
|
---|
1233 | , o = options[pane]
|
---|
1234 | , s = state[pane]
|
---|
1235 | ;
|
---|
1236 | if (!draggingAvailable || !$Ps[pane] || !o.resizable) {
|
---|
1237 | o.resizable = false;
|
---|
1238 | return true; // skip to next
|
---|
1239 | }
|
---|
1240 |
|
---|
1241 | var
|
---|
1242 | rClass = o.resizerClass
|
---|
1243 | // 'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process
|
---|
1244 | , dragClass = rClass+"-drag" // resizer-drag
|
---|
1245 | , dragPaneClass = rClass+"-"+pane+"-drag" // resizer-north-drag
|
---|
1246 | // 'dragging' class is applied to the CLONED resizer-bar while it is being dragged
|
---|
1247 | , draggingClass = rClass+"-dragging" // resizer-dragging
|
---|
1248 | , draggingPaneClass = rClass+"-"+pane+"-dragging" // resizer-north-dragging
|
---|
1249 | , draggingClassSet = false // logic var
|
---|
1250 | , $P = $Ps[pane]
|
---|
1251 | , $R = $Rs[pane]
|
---|
1252 | ;
|
---|
1253 |
|
---|
1254 | if (!s.isClosed)
|
---|
1255 | $R
|
---|
1256 | .attr("title", o.resizerTip)
|
---|
1257 | .css("cursor", o.resizerCursor) // n-resize, s-resize, etc
|
---|
1258 | ;
|
---|
1259 |
|
---|
1260 | $R.draggable({
|
---|
1261 | containment: $Container[0] // limit resizing to layout container
|
---|
1262 | , axis: (c[pane].dir=="horz" ? "y" : "x") // limit resizing to horz or vert axis
|
---|
1263 | , delay: 200
|
---|
1264 | , distance: 1
|
---|
1265 | // basic format for helper - style it using class: .ui-draggable-dragging
|
---|
1266 | , helper: "clone"
|
---|
1267 | , opacity: o.resizerDragOpacity
|
---|
1268 | //, iframeFix: o.draggableIframeFix // TODO: consider using when bug is fixed
|
---|
1269 | , zIndex: c.zIndex.resizing
|
---|
1270 |
|
---|
1271 | , start: function (e, ui) {
|
---|
1272 | // onresize_start callback - will CANCEL hide if returns false
|
---|
1273 | // TODO: CONFIRM that dragging can be cancelled like this???
|
---|
1274 | if (false === execUserCallback(pane, o.onresize_start)) return false;
|
---|
1275 |
|
---|
1276 | s.isResizing = true; // prevent pane from closing while resizing
|
---|
1277 | clearTimer(pane, "closeSlider"); // just in case already triggered
|
---|
1278 |
|
---|
1279 | $R.addClass( dragClass +" "+ dragPaneClass ); // add drag classes
|
---|
1280 | draggingClassSet = false; // reset logic var - see drag()
|
---|
1281 |
|
---|
1282 | // SET RESIZING LIMITS - used in drag()
|
---|
1283 | var resizerWidth = (pane=="east" || pane=="south" ? o.spacing_open : 0);
|
---|
1284 | setPaneMinMaxSizes(pane); // update pane-state
|
---|
1285 | s.minPosition -= resizerWidth;
|
---|
1286 | s.maxPosition -= resizerWidth;
|
---|
1287 | edge = (c[pane].dir=="horz" ? "top" : "left");
|
---|
1288 |
|
---|
1289 | // MASK PANES WITH IFRAMES OR OTHER TROUBLESOME ELEMENTS
|
---|
1290 | $(o.maskIframesOnResize === true ? "iframe" : o.maskIframesOnResize).each(function() {
|
---|
1291 | $('<div class="ui-layout-mask"/>')
|
---|
1292 | .css({
|
---|
1293 | background: "#fff"
|
---|
1294 | , opacity: "0.001"
|
---|
1295 | , zIndex: 9
|
---|
1296 | , position: "absolute"
|
---|
1297 | , width: this.offsetWidth+"px"
|
---|
1298 | , height: this.offsetHeight+"px"
|
---|
1299 | })
|
---|
1300 | .css($(this).offset()) // top & left
|
---|
1301 | .appendTo(this.parentNode) // put div INSIDE pane to avoid zIndex issues
|
---|
1302 | ;
|
---|
1303 | });
|
---|
1304 | }
|
---|
1305 |
|
---|
1306 | , drag: function (e, ui) {
|
---|
1307 | if (!draggingClassSet) { // can only add classes after clone has been added to the DOM
|
---|
1308 | $(".ui-draggable-dragging")
|
---|
1309 | .addClass( draggingClass +" "+ draggingPaneClass ) // add dragging classes
|
---|
1310 | .children().css("visibility","hidden") // hide toggler inside dragged resizer-bar
|
---|
1311 | ;
|
---|
1312 | draggingClassSet = true;
|
---|
1313 | // draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane!
|
---|
1314 | if (s.isSliding) $Ps[pane].css("zIndex", c.zIndex.sliding);
|
---|
1315 | }
|
---|
1316 | // CONTAIN RESIZER-BAR TO RESIZING LIMITS
|
---|
1317 | if (ui.position[edge] < s.minPosition) ui.position[edge] = s.minPosition;
|
---|
1318 | else if (ui.position[edge] > s.maxPosition) ui.position[edge] = s.maxPosition;
|
---|
1319 | }
|
---|
1320 |
|
---|
1321 | , stop: function (e, ui) {
|
---|
1322 | var
|
---|
1323 | dragPos = ui.position
|
---|
1324 | , resizerPos
|
---|
1325 | , newSize
|
---|
1326 | ;
|
---|
1327 | $R.removeClass( dragClass +" "+ dragPaneClass ); // remove drag classes
|
---|
1328 |
|
---|
1329 | switch (pane) {
|
---|
1330 | case "north": resizerPos = dragPos.top; break;
|
---|
1331 | case "west": resizerPos = dragPos.left; break;
|
---|
1332 | case "south": resizerPos = cDims.outerHeight - dragPos.top - $R.outerHeight(); break;
|
---|
1333 | case "east": resizerPos = cDims.outerWidth - dragPos.left - $R.outerWidth(); break;
|
---|
1334 | }
|
---|
1335 | // remove container margin from resizer position to get the pane size
|
---|
1336 | newSize = resizerPos - cDims[ c[pane].edge ];
|
---|
1337 |
|
---|
1338 | sizePane(pane, newSize);
|
---|
1339 |
|
---|
1340 | // UN-MASK PANES MASKED IN drag.start
|
---|
1341 | $("div.ui-layout-mask").remove(); // Remove iframe masks
|
---|
1342 |
|
---|
1343 | s.isResizing = false;
|
---|
1344 | }
|
---|
1345 |
|
---|
1346 | });
|
---|
1347 | });
|
---|
1348 | };
|
---|
1349 |
|
---|
1350 |
|
---|
1351 |
|
---|
1352 | /*
|
---|
1353 | * ###########################
|
---|
1354 | * ACTION METHODS
|
---|
1355 | * ###########################
|
---|
1356 | */
|
---|
1357 |
|
---|
1358 | /**
|
---|
1359 | * hide / show
|
---|
1360 | *
|
---|
1361 | * Completely 'hides' a pane, including its spacing - as if it does not exist
|
---|
1362 | * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it
|
---|
1363 | *
|
---|
1364 | * @param String pane The pane being hidden, ie: north, south, east, or west
|
---|
1365 | */
|
---|
1366 | var hide = function (pane, onInit) {
|
---|
1367 | var
|
---|
1368 | o = options[pane]
|
---|
1369 | , s = state[pane]
|
---|
1370 | , $P = $Ps[pane]
|
---|
1371 | , $R = $Rs[pane]
|
---|
1372 | ;
|
---|
1373 | if (!$P || s.isHidden) return; // pane does not exist OR is already hidden
|
---|
1374 |
|
---|
1375 | // onhide_start callback - will CANCEL hide if returns false
|
---|
1376 | if (false === execUserCallback(pane, o.onhide_start)) return;
|
---|
1377 |
|
---|
1378 | s.isSliding = false; // just in case
|
---|
1379 |
|
---|
1380 | // now hide the elements
|
---|
1381 | if ($R) $R.hide(); // hide resizer-bar
|
---|
1382 | if (onInit || s.isClosed) {
|
---|
1383 | s.isClosed = true; // to trigger open-animation on show()
|
---|
1384 | s.isHidden = true;
|
---|
1385 | $P.hide(); // no animation when loading page
|
---|
1386 | sizeMidPanes(c[pane].dir == "horz" ? "all" : "center");
|
---|
1387 | execUserCallback(pane, o.onhide_end || o.onhide);
|
---|
1388 | }
|
---|
1389 | else {
|
---|
1390 | s.isHiding = true; // used by onclose
|
---|
1391 | close(pane, false); // adjust all panes to fit
|
---|
1392 | //s.isHidden = true; - will be set by close - if not cancelled
|
---|
1393 | }
|
---|
1394 | };
|
---|
1395 |
|
---|
1396 | var show = function (pane, openPane) {
|
---|
1397 | var
|
---|
1398 | o = options[pane]
|
---|
1399 | , s = state[pane]
|
---|
1400 | , $P = $Ps[pane]
|
---|
1401 | , $R = $Rs[pane]
|
---|
1402 | ;
|
---|
1403 | if (!$P || !s.isHidden) return; // pane does not exist OR is not hidden
|
---|
1404 |
|
---|
1405 | // onhide_start callback - will CANCEL hide if returns false
|
---|
1406 | if (false === execUserCallback(pane, o.onshow_start)) return;
|
---|
1407 |
|
---|
1408 | s.isSliding = false; // just in case
|
---|
1409 | s.isShowing = true; // used by onopen/onclose
|
---|
1410 | //s.isHidden = false; - will be set by open/close - if not cancelled
|
---|
1411 |
|
---|
1412 | // now show the elements
|
---|
1413 | if ($R && o.spacing_open > 0) $R.show();
|
---|
1414 | if (openPane === false)
|
---|
1415 | close(pane, true); // true = force
|
---|
1416 | else
|
---|
1417 | open(pane); // adjust all panes to fit
|
---|
1418 | };
|
---|
1419 |
|
---|
1420 |
|
---|
1421 | /**
|
---|
1422 | * toggle
|
---|
1423 | *
|
---|
1424 | * Toggles a pane open/closed by calling either open or close
|
---|
1425 | *
|
---|
1426 | * @param String pane The pane being toggled, ie: north, south, east, or west
|
---|
1427 | */
|
---|
1428 | var toggle = function (pane) {
|
---|
1429 | var s = state[pane];
|
---|
1430 | if (s.isHidden)
|
---|
1431 | show(pane); // will call 'open' after unhiding it
|
---|
1432 | else if (s.isClosed)
|
---|
1433 | open(pane);
|
---|
1434 | else
|
---|
1435 | close(pane);
|
---|
1436 | };
|
---|
1437 |
|
---|
1438 | /**
|
---|
1439 | * close
|
---|
1440 | *
|
---|
1441 | * Close the specified pane (animation optional), and resize all other panes as needed
|
---|
1442 | *
|
---|
1443 | * @param String pane The pane being closed, ie: north, south, east, or west
|
---|
1444 | */
|
---|
1445 | var close = function (pane, force, noAnimation) {
|
---|
1446 | var
|
---|
1447 | $P = $Ps[pane]
|
---|
1448 | , $R = $Rs[pane]
|
---|
1449 | , $T = $Ts[pane]
|
---|
1450 | , o = options[pane]
|
---|
1451 | , s = state[pane]
|
---|
1452 | , doFX = !noAnimation && !s.isClosed && (o.fxName_close != "none")
|
---|
1453 | , edge = c[pane].edge
|
---|
1454 | , rClass = o.resizerClass
|
---|
1455 | , tClass = o.togglerClass
|
---|
1456 | , _pane = "-"+ pane // used for classNames
|
---|
1457 | , _open = "-open"
|
---|
1458 | , _sliding= "-sliding"
|
---|
1459 | , _closed = "-closed"
|
---|
1460 | // transfer logic vars to temp vars
|
---|
1461 | , isShowing = s.isShowing
|
---|
1462 | , isHiding = s.isHiding
|
---|
1463 | ;
|
---|
1464 | // now clear the logic vars
|
---|
1465 | delete s.isShowing;
|
---|
1466 | delete s.isHiding;
|
---|
1467 |
|
---|
1468 | if (!$P || (!o.resizable && !o.closable)) return; // invalid request
|
---|
1469 | else if (!force && s.isClosed && !isShowing) return; // already closed
|
---|
1470 |
|
---|
1471 | if (c.isLayoutBusy) { // layout is 'busy' - probably with an animation
|
---|
1472 | setFlowCallback("close", pane, force); // set a callback for this action, if possible
|
---|
1473 | return; // ABORT
|
---|
1474 | }
|
---|
1475 |
|
---|
1476 | // onclose_start callback - will CANCEL hide if returns false
|
---|
1477 | // SKIP if just 'showing' a hidden pane as 'closed'
|
---|
1478 | if (!isShowing && false === execUserCallback(pane, o.onclose_start)) return;
|
---|
1479 |
|
---|
1480 | // SET flow-control flags
|
---|
1481 | c[pane].isMoving = true;
|
---|
1482 | c.isLayoutBusy = true;
|
---|
1483 |
|
---|
1484 | s.isClosed = true;
|
---|
1485 | // update isHidden BEFORE sizing panes
|
---|
1486 | if (isHiding) s.isHidden = true;
|
---|
1487 | else if (isShowing) s.isHidden = false;
|
---|
1488 |
|
---|
1489 | // sync any 'pin buttons'
|
---|
1490 | syncPinBtns(pane, false);
|
---|
1491 |
|
---|
1492 | // resize panes adjacent to this one
|
---|
1493 | if (!s.isSliding) sizeMidPanes(c[pane].dir == "horz" ? "all" : "center");
|
---|
1494 |
|
---|
1495 | // if this pane has a resizer bar, move it now
|
---|
1496 | if ($R) {
|
---|
1497 | $R
|
---|
1498 | .css(edge, cDims[edge]) // move the resizer bar
|
---|
1499 | .removeClass( rClass+_open +" "+ rClass+_pane+_open )
|
---|
1500 | .removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding )
|
---|
1501 | .addClass( rClass+_closed +" "+ rClass+_pane+_closed )
|
---|
1502 | ;
|
---|
1503 | // DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent
|
---|
1504 | if (o.resizable)
|
---|
1505 | $R
|
---|
1506 | .draggable("disable")
|
---|
1507 | .css("cursor", "default")
|
---|
1508 | .attr("title","")
|
---|
1509 | ;
|
---|
1510 | // if pane has a toggler button, adjust that too
|
---|
1511 | if ($T) {
|
---|
1512 | $T
|
---|
1513 | .removeClass( tClass+_open +" "+ tClass+_pane+_open )
|
---|
1514 | .addClass( tClass+_closed +" "+ tClass+_pane+_closed )
|
---|
1515 | .attr("title", o.togglerTip_closed) // may be blank
|
---|
1516 | ;
|
---|
1517 | }
|
---|
1518 | sizeHandles(); // resize 'length' and position togglers for adjacent panes
|
---|
1519 | }
|
---|
1520 |
|
---|
1521 | // ANIMATE 'CLOSE' - if no animation, then was ALREADY shown above
|
---|
1522 | if (doFX) {
|
---|
1523 | lockPaneForFX(pane, true); // need to set left/top so animation will work
|
---|
1524 | $P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () {
|
---|
1525 | lockPaneForFX(pane, false); // undo
|
---|
1526 | if (!s.isClosed) return; // pane was opened before animation finished!
|
---|
1527 | close_2();
|
---|
1528 | });
|
---|
1529 | }
|
---|
1530 | else {
|
---|
1531 | $P.hide(); // just hide pane NOW
|
---|
1532 | close_2();
|
---|
1533 | }
|
---|
1534 |
|
---|
1535 | // SUBROUTINE
|
---|
1536 | function close_2 () {
|
---|
1537 | bindStartSlidingEvent(pane, true); // will enable if state.PANE.isSliding = true
|
---|
1538 |
|
---|
1539 | // onclose callback - UNLESS just 'showing' a hidden pane as 'closed'
|
---|
1540 | if (!isShowing) execUserCallback(pane, o.onclose_end || o.onclose);
|
---|
1541 | // onhide OR onshow callback
|
---|
1542 | if (isShowing) execUserCallback(pane, o.onshow_end || o.onshow);
|
---|
1543 | if (isHiding) execUserCallback(pane, o.onhide_end || o.onhide);
|
---|
1544 |
|
---|
1545 | // internal flow-control callback
|
---|
1546 | execFlowCallback(pane);
|
---|
1547 | }
|
---|
1548 | };
|
---|
1549 |
|
---|
1550 | /**
|
---|
1551 | * open
|
---|
1552 | *
|
---|
1553 | * Open the specified pane (animation optional), and resize all other panes as needed
|
---|
1554 | *
|
---|
1555 | * @param String pane The pane being opened, ie: north, south, east, or west
|
---|
1556 | */
|
---|
1557 | var open = function (pane, slide, noAnimation) {
|
---|
1558 | var
|
---|
1559 | $P = $Ps[pane]
|
---|
1560 | , $R = $Rs[pane]
|
---|
1561 | , $T = $Ts[pane]
|
---|
1562 | , o = options[pane]
|
---|
1563 | , s = state[pane]
|
---|
1564 | , doFX = !noAnimation && s.isClosed && (o.fxName_open != "none")
|
---|
1565 | , edge = c[pane].edge
|
---|
1566 | , rClass = o.resizerClass
|
---|
1567 | , tClass = o.togglerClass
|
---|
1568 | , _pane = "-"+ pane // used for classNames
|
---|
1569 | , _open = "-open"
|
---|
1570 | , _closed = "-closed"
|
---|
1571 | , _sliding= "-sliding"
|
---|
1572 | // transfer logic var to temp var
|
---|
1573 | , isShowing = s.isShowing
|
---|
1574 | ;
|
---|
1575 | // now clear the logic var
|
---|
1576 | delete s.isShowing;
|
---|
1577 |
|
---|
1578 | if (!$P || (!o.resizable && !o.closable)) return; // invalid request
|
---|
1579 | else if (!s.isClosed && !s.isSliding) return; // already open
|
---|
1580 |
|
---|
1581 | // pane can ALSO be unhidden by just calling show(), so handle this scenario
|
---|
1582 | if (s.isHidden && !isShowing) {
|
---|
1583 | show(pane, true);
|
---|
1584 | return;
|
---|
1585 | }
|
---|
1586 |
|
---|
1587 | if (c.isLayoutBusy) { // layout is 'busy' - probably with an animation
|
---|
1588 | setFlowCallback("open", pane, slide); // set a callback for this action, if possible
|
---|
1589 | return; // ABORT
|
---|
1590 | }
|
---|
1591 |
|
---|
1592 | // onopen_start callback - will CANCEL hide if returns false
|
---|
1593 | if (false === execUserCallback(pane, o.onopen_start)) return;
|
---|
1594 |
|
---|
1595 | // SET flow-control flags
|
---|
1596 | c[pane].isMoving = true;
|
---|
1597 | c.isLayoutBusy = true;
|
---|
1598 |
|
---|
1599 | // 'PIN PANE' - stop sliding
|
---|
1600 | if (s.isSliding && !slide) // !slide = 'open pane normally' - NOT sliding
|
---|
1601 | bindStopSlidingEvents(pane, false); // will set isSliding=false
|
---|
1602 |
|
---|
1603 | s.isClosed = false;
|
---|
1604 | // update isHidden BEFORE sizing panes
|
---|
1605 | if (isShowing) s.isHidden = false;
|
---|
1606 |
|
---|
1607 | // Container size may have changed - shrink the pane if now 'too big'
|
---|
1608 | setPaneMinMaxSizes(pane); // update pane-state
|
---|
1609 | if (s.size > s.maxSize) // pane is too big! resize it before opening
|
---|
1610 | $P.css( c[pane].sizeType, max(1, cssSize(pane, s.maxSize)) );
|
---|
1611 |
|
---|
1612 | bindStartSlidingEvent(pane, false); // remove trigger event from resizer-bar
|
---|
1613 |
|
---|
1614 | if (doFX) { // ANIMATE
|
---|
1615 | lockPaneForFX(pane, true); // need to set left/top so animation will work
|
---|
1616 | $P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() {
|
---|
1617 | lockPaneForFX(pane, false); // undo
|
---|
1618 | if (s.isClosed) return; // pane was closed before animation finished!
|
---|
1619 | open_2(); // continue
|
---|
1620 | });
|
---|
1621 | }
|
---|
1622 | else {// no animation
|
---|
1623 | $P.show(); // just show pane and...
|
---|
1624 | open_2(); // continue
|
---|
1625 | }
|
---|
1626 |
|
---|
1627 | // SUBROUTINE
|
---|
1628 | function open_2 () {
|
---|
1629 | // NOTE: if isSliding, then other panes are NOT 'resized'
|
---|
1630 | if (!s.isSliding) // resize all panes adjacent to this one
|
---|
1631 | sizeMidPanes(c[pane].dir=="vert" ? "center" : "all");
|
---|
1632 |
|
---|
1633 | // if this pane has a toggler, move it now
|
---|
1634 | if ($R) {
|
---|
1635 | $R
|
---|
1636 | .css(edge, cDims[edge] + getPaneSize(pane)) // move the toggler
|
---|
1637 | .removeClass( rClass+_closed +" "+ rClass+_pane+_closed )
|
---|
1638 | .addClass( rClass+_open +" "+ rClass+_pane+_open )
|
---|
1639 | .addClass( !s.isSliding ? "" : rClass+_sliding +" "+ rClass+_pane+_sliding )
|
---|
1640 | ;
|
---|
1641 | if (o.resizable)
|
---|
1642 | $R
|
---|
1643 | .draggable("enable")
|
---|
1644 | .css("cursor", o.resizerCursor)
|
---|
1645 | .attr("title", o.resizerTip)
|
---|
1646 | ;
|
---|
1647 | else
|
---|
1648 | $R.css("cursor", "default"); // n-resize, s-resize, etc
|
---|
1649 | // if pane also has a toggler button, adjust that too
|
---|
1650 | if ($T) {
|
---|
1651 | $T
|
---|
1652 | .removeClass( tClass+_closed +" "+ tClass+_pane+_closed )
|
---|
1653 | .addClass( tClass+_open +" "+ tClass+_pane+_open )
|
---|
1654 | .attr("title", o.togglerTip_open) // may be blank
|
---|
1655 | ;
|
---|
1656 | }
|
---|
1657 | sizeHandles("all"); // resize resizer & toggler sizes for all panes
|
---|
1658 | }
|
---|
1659 |
|
---|
1660 | // resize content every time pane opens - to be sure
|
---|
1661 | sizeContent(pane);
|
---|
1662 |
|
---|
1663 | // sync any 'pin buttons'
|
---|
1664 | syncPinBtns(pane, !s.isSliding);
|
---|
1665 |
|
---|
1666 | // onopen callback
|
---|
1667 | execUserCallback(pane, o.onopen_end || o.onopen);
|
---|
1668 |
|
---|
1669 | // onshow callback
|
---|
1670 | if (isShowing) execUserCallback(pane, o.onshow_end || o.onshow);
|
---|
1671 |
|
---|
1672 | // internal flow-control callback
|
---|
1673 | execFlowCallback(pane);
|
---|
1674 | }
|
---|
1675 | };
|
---|
1676 |
|
---|
1677 |
|
---|
1678 | /**
|
---|
1679 | * lockPaneForFX
|
---|
1680 | *
|
---|
1681 | * Must set left/top on East/South panes so animation will work properly
|
---|
1682 | *
|
---|
1683 | * @param String pane The pane to lock, 'east' or 'south' - any other is ignored!
|
---|
1684 | * @param Boolean doLock true = set left/top, false = remove
|
---|
1685 | */
|
---|
1686 | var lockPaneForFX = function (pane, doLock) {
|
---|
1687 | var $P = $Ps[pane];
|
---|
1688 | if (doLock) {
|
---|
1689 | $P.css({ zIndex: c.zIndex.animation }); // overlay all elements during animation
|
---|
1690 | if (pane=="south")
|
---|
1691 | $P.css({ top: cDims.top + cDims.innerHeight - $P.outerHeight() });
|
---|
1692 | else if (pane=="east")
|
---|
1693 | $P.css({ left: cDims.left + cDims.innerWidth - $P.outerWidth() });
|
---|
1694 | }
|
---|
1695 | else {
|
---|
1696 | if (!state[pane].isSliding) $P.css({ zIndex: c.zIndex.pane_normal });
|
---|
1697 | if (pane=="south")
|
---|
1698 | $P.css({ top: "auto" });
|
---|
1699 | else if (pane=="east")
|
---|
1700 | $P.css({ left: "auto" });
|
---|
1701 | }
|
---|
1702 | };
|
---|
1703 |
|
---|
1704 |
|
---|
1705 | /**
|
---|
1706 | * bindStartSlidingEvent
|
---|
1707 | *
|
---|
1708 | * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger
|
---|
1709 | *
|
---|
1710 | * @callers open(), close()
|
---|
1711 | * @param String pane The pane to enable/disable, 'north', 'south', etc.
|
---|
1712 | * @param Boolean enable Enable or Disable sliding?
|
---|
1713 | */
|
---|
1714 | var bindStartSlidingEvent = function (pane, enable) {
|
---|
1715 | var
|
---|
1716 | o = options[pane]
|
---|
1717 | , $R = $Rs[pane]
|
---|
1718 | , trigger = o.slideTrigger_open
|
---|
1719 | ;
|
---|
1720 | if (!$R || !o.slidable) return;
|
---|
1721 | // make sure we have a valid event
|
---|
1722 | if (trigger != "click" && trigger != "dblclick" && trigger != "mouseover") trigger = "click";
|
---|
1723 | $R
|
---|
1724 | // add or remove trigger event
|
---|
1725 | [enable ? "bind" : "unbind"](trigger, slideOpen)
|
---|
1726 | // set the appropriate cursor & title/tip
|
---|
1727 | .css("cursor", (enable ? o.sliderCursor: "default"))
|
---|
1728 | .attr("title", (enable ? o.sliderTip : ""))
|
---|
1729 | ;
|
---|
1730 | };
|
---|
1731 |
|
---|
1732 | /**
|
---|
1733 | * bindStopSlidingEvents
|
---|
1734 | *
|
---|
1735 | * Add or remove 'mouseout' events to 'slide close' when pane is 'sliding' open or closed
|
---|
1736 | * Also increases zIndex when pane is sliding open
|
---|
1737 | * See bindStartSlidingEvent for code to control 'slide open'
|
---|
1738 | *
|
---|
1739 | * @callers slideOpen(), slideClosed()
|
---|
1740 | * @param String pane The pane to process, 'north', 'south', etc.
|
---|
1741 | * @param Boolean isOpen Is pane open or closed?
|
---|
1742 | */
|
---|
1743 | var bindStopSlidingEvents = function (pane, enable) {
|
---|
1744 | var
|
---|
1745 | o = options[pane]
|
---|
1746 | , s = state[pane]
|
---|
1747 | , trigger = o.slideTrigger_close
|
---|
1748 | , action = (enable ? "bind" : "unbind") // can't make 'unbind' work! - see disabled code below
|
---|
1749 | , $P = $Ps[pane]
|
---|
1750 | , $R = $Rs[pane]
|
---|
1751 | ;
|
---|
1752 |
|
---|
1753 | s.isSliding = enable; // logic
|
---|
1754 | clearTimer(pane, "closeSlider"); // just in case
|
---|
1755 |
|
---|
1756 | // raise z-index when sliding
|
---|
1757 | $P.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.pane_normal) });
|
---|
1758 | $R.css({ zIndex: (enable ? c.zIndex.sliding : c.zIndex.resizer_normal) });
|
---|
1759 |
|
---|
1760 | // make sure we have a valid event
|
---|
1761 | if (trigger != "click" && trigger != "mouseout") trigger = "mouseout";
|
---|
1762 |
|
---|
1763 | // when trigger is 'mouseout', must cancel timer when mouse moves between 'pane' and 'resizer'
|
---|
1764 | if (enable) { // BIND trigger events
|
---|
1765 | $P.bind(trigger, slideClosed );
|
---|
1766 | $R.bind(trigger, slideClosed );
|
---|
1767 | if (trigger = "mouseout") {
|
---|
1768 | $P.bind("mouseover", cancelMouseOut );
|
---|
1769 | $R.bind("mouseover", cancelMouseOut );
|
---|
1770 | }
|
---|
1771 | }
|
---|
1772 | else { // UNBIND trigger events
|
---|
1773 | // TODO: why does unbind of a 'single function' not work reliably?
|
---|
1774 | //$P[action](trigger, slideClosed );
|
---|
1775 | $P.unbind(trigger);
|
---|
1776 | $R.unbind(trigger);
|
---|
1777 | if (trigger = "mouseout") {
|
---|
1778 | //$P[action]("mouseover", cancelMouseOut );
|
---|
1779 | $P.unbind("mouseover");
|
---|
1780 | $R.unbind("mouseover");
|
---|
1781 | clearTimer(pane, "closeSlider");
|
---|
1782 | }
|
---|
1783 | }
|
---|
1784 |
|
---|
1785 | // SUBROUTINE for mouseout timer clearing
|
---|
1786 | function cancelMouseOut (evt) {
|
---|
1787 | clearTimer(pane, "closeSlider");
|
---|
1788 | evt.stopPropagation();
|
---|
1789 | }
|
---|
1790 | };
|
---|
1791 |
|
---|
1792 | var slideOpen = function () {
|
---|
1793 | var pane = $(this).attr("resizer"); // attr added by initHandles
|
---|
1794 | if (state[pane].isClosed) { // skip if already open!
|
---|
1795 | bindStopSlidingEvents(pane, true); // pane is opening, so BIND trigger events to close it
|
---|
1796 | open(pane, true); // true = slide - ie, called from here!
|
---|
1797 | }
|
---|
1798 | };
|
---|
1799 |
|
---|
1800 | var slideClosed = function () {
|
---|
1801 | var
|
---|
1802 | $E = $(this)
|
---|
1803 | , pane = $E.attr("pane") || $E.attr("resizer")
|
---|
1804 | , o = options[pane]
|
---|
1805 | , s = state[pane]
|
---|
1806 | ;
|
---|
1807 | if (s.isClosed || s.isResizing)
|
---|
1808 | return; // skip if already closed OR in process of resizing
|
---|
1809 | else if (o.slideTrigger_close == "click")
|
---|
1810 | close_NOW(); // close immediately onClick
|
---|
1811 | else // trigger = mouseout - use a delay
|
---|
1812 | setTimer(pane, "closeSlider", close_NOW, 300); // .3 sec delay
|
---|
1813 |
|
---|
1814 | // SUBROUTINE for timed close
|
---|
1815 | function close_NOW () {
|
---|
1816 | bindStopSlidingEvents(pane, false); // pane is being closed, so UNBIND trigger events
|
---|
1817 | if (!s.isClosed) close(pane); // skip if already closed!
|
---|
1818 | }
|
---|
1819 | };
|
---|
1820 |
|
---|
1821 |
|
---|
1822 | /**
|
---|
1823 | * sizePane
|
---|
1824 | *
|
---|
1825 | * @callers initResizable.stop()
|
---|
1826 | * @param String pane The pane being resized - usually west or east, but potentially north or south
|
---|
1827 | * @param Integer newSize The new size for this pane - will be validated
|
---|
1828 | */
|
---|
1829 | var sizePane = function (pane, size) {
|
---|
1830 | // TODO: accept "auto" as size, and size-to-fit pane content
|
---|
1831 | var
|
---|
1832 | edge = c[pane].edge
|
---|
1833 | , dir = c[pane].dir
|
---|
1834 | , o = options[pane]
|
---|
1835 | , s = state[pane]
|
---|
1836 | , $P = $Ps[pane]
|
---|
1837 | , $R = $Rs[pane]
|
---|
1838 | ;
|
---|
1839 | // calculate 'current' min/max sizes
|
---|
1840 | setPaneMinMaxSizes(pane); // update pane-state
|
---|
1841 | // compare/update calculated min/max to user-options
|
---|
1842 | s.minSize = max(s.minSize, o.minSize);
|
---|
1843 | if (o.maxSize > 0) s.maxSize = min(s.maxSize, o.maxSize);
|
---|
1844 | // validate passed size
|
---|
1845 | size = max(size, s.minSize);
|
---|
1846 | size = min(size, s.maxSize);
|
---|
1847 | s.size = size; // update state
|
---|
1848 |
|
---|
1849 | // move the resizer bar and resize the pane
|
---|
1850 | $R.css( edge, size + cDims[edge] );
|
---|
1851 | $P.css( c[pane].sizeType, max(1, cssSize(pane, size)) );
|
---|
1852 |
|
---|
1853 | // resize all the adjacent panes, and adjust their toggler buttons
|
---|
1854 | if (!s.isSliding) sizeMidPanes(dir=="horz" ? "all" : "center");
|
---|
1855 | sizeHandles();
|
---|
1856 | sizeContent(pane);
|
---|
1857 | execUserCallback(pane, o.onresize_end || o.onresize);
|
---|
1858 | };
|
---|
1859 |
|
---|
1860 | /**
|
---|
1861 | * sizeMidPanes
|
---|
1862 | *
|
---|
1863 | * @callers create(), open(), close(), onWindowResize()
|
---|
1864 | */
|
---|
1865 | var sizeMidPanes = function (panes, overrideDims, onInit) {
|
---|
1866 | if (!panes || panes == "all") panes = "east,west,center";
|
---|
1867 |
|
---|
1868 | var d = getPaneDims();
|
---|
1869 | if (overrideDims) $.extend( d, overrideDims );
|
---|
1870 |
|
---|
1871 | $.each(panes.split(","), function() {
|
---|
1872 | if (!$Ps[this]) return; // NO PANE - skip
|
---|
1873 | var
|
---|
1874 | pane = str(this)
|
---|
1875 | , o = options[pane]
|
---|
1876 | , s = state[pane]
|
---|
1877 | , $P = $Ps[pane]
|
---|
1878 | , $R = $Rs[pane]
|
---|
1879 | , hasRoom = true
|
---|
1880 | , CSS = {}
|
---|
1881 | ;
|
---|
1882 |
|
---|
1883 | if (pane == "center") {
|
---|
1884 | d = getPaneDims(); // REFRESH Dims because may have just 'unhidden' East or West pane after a 'resize'
|
---|
1885 | CSS = $.extend( {}, d ); // COPY ALL of the paneDims
|
---|
1886 | CSS.width = max(1, cssW(pane, CSS.width));
|
---|
1887 | CSS.height = max(1, cssH(pane, CSS.height));
|
---|
1888 | hasRoom = (CSS.width > 1 && CSS.height > 1);
|
---|
1889 | /*
|
---|
1890 | * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes
|
---|
1891 | * Normally these panes have only 'left' & 'right' positions so pane auto-sizes
|
---|
1892 | */
|
---|
1893 | if ($.browser.msie && (!$.boxModel || $.browser.version < 7)) {
|
---|
1894 | if ($Ps.north) $Ps.north.css({ width: cssW($Ps.north, cDims.innerWidth) });
|
---|
1895 | if ($Ps.south) $Ps.south.css({ width: cssW($Ps.south, cDims.innerWidth) });
|
---|
1896 | }
|
---|
1897 | }
|
---|
1898 | else { // for east and west, set only the height
|
---|
1899 | CSS.top = d.top;
|
---|
1900 | CSS.bottom = d.bottom;
|
---|
1901 | CSS.height = max(1, cssH(pane, d.height));
|
---|
1902 | hasRoom = (CSS.height > 1);
|
---|
1903 | }
|
---|
1904 |
|
---|
1905 | if (hasRoom) {
|
---|
1906 | $P.css(CSS);
|
---|
1907 | if (s.noRoom) {
|
---|
1908 | s.noRoom = false;
|
---|
1909 | if (s.isHidden) return;
|
---|
1910 | else show(pane, !s.isClosed);
|
---|
1911 | /* OLD CODE - keep until sure line above works right!
|
---|
1912 | if (!s.isClosed) $P.show(); // in case was previously hidden due to NOT hasRoom
|
---|
1913 | if ($R) $R.show();
|
---|
1914 | */
|
---|
1915 | }
|
---|
1916 | if (!onInit) {
|
---|
1917 | sizeContent(pane);
|
---|
1918 | execUserCallback(pane, o.onresize_end || o.onresize);
|
---|
1919 | }
|
---|
1920 | }
|
---|
1921 | else if (!s.noRoom) { // no room for pane, so just hide it (if not already)
|
---|
1922 | s.noRoom = true; // update state
|
---|
1923 | if (s.isHidden) return;
|
---|
1924 | if (onInit) { // skip onhide callback and other logic onLoad
|
---|
1925 | $P.hide();
|
---|
1926 | if ($R) $R.hide();
|
---|
1927 | }
|
---|
1928 | else hide(pane);
|
---|
1929 | }
|
---|
1930 | });
|
---|
1931 | };
|
---|
1932 |
|
---|
1933 |
|
---|
1934 | var sizeContent = function (panes) {
|
---|
1935 | if (!panes || panes == "all") panes = c.allPanes;
|
---|
1936 |
|
---|
1937 | $.each(panes.split(","), function() {
|
---|
1938 | if (!$Cs[this]) return; // NO CONTENT - skip
|
---|
1939 | var
|
---|
1940 | pane = str(this)
|
---|
1941 | , ignore = options[pane].contentIgnoreSelector
|
---|
1942 | , $P = $Ps[pane]
|
---|
1943 | , $C = $Cs[pane]
|
---|
1944 | , e_C = $C[0] // DOM element
|
---|
1945 | , height = cssH($P); // init to pane.innerHeight
|
---|
1946 | ;
|
---|
1947 | $P.children().each(function() {
|
---|
1948 | if (this == e_C) return; // Content elem - skip
|
---|
1949 | var $E = $(this);
|
---|
1950 | if (!ignore || !$E.is(ignore))
|
---|
1951 | height -= $E.outerHeight();
|
---|
1952 | });
|
---|
1953 | if (height > 0)
|
---|
1954 | height = cssH($C, height);
|
---|
1955 | if (height < 1)
|
---|
1956 | $C.hide(); // no room for content!
|
---|
1957 | else
|
---|
1958 | $C.css({ height: height }).show();
|
---|
1959 | });
|
---|
1960 | };
|
---|
1961 |
|
---|
1962 |
|
---|
1963 | /**
|
---|
1964 | * sizeHandles
|
---|
1965 | *
|
---|
1966 | * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary
|
---|
1967 | *
|
---|
1968 | * @callers initHandles(), open(), close(), resizeAll()
|
---|
1969 | */
|
---|
1970 | var sizeHandles = function (panes, onInit) {
|
---|
1971 | if (!panes || panes == "all") panes = c.borderPanes;
|
---|
1972 |
|
---|
1973 | $.each(panes.split(","), function() {
|
---|
1974 | var
|
---|
1975 | pane = str(this)
|
---|
1976 | , o = options[pane]
|
---|
1977 | , s = state[pane]
|
---|
1978 | , $P = $Ps[pane]
|
---|
1979 | , $R = $Rs[pane]
|
---|
1980 | , $T = $Ts[pane]
|
---|
1981 | ;
|
---|
1982 | if (!$P || !$R || (!o.resizable && !o.closable)) return; // skip
|
---|
1983 |
|
---|
1984 | var
|
---|
1985 | dir = c[pane].dir
|
---|
1986 | , _state = (s.isClosed ? "_closed" : "_open")
|
---|
1987 | , spacing = o["spacing"+ _state]
|
---|
1988 | , togAlign = o["togglerAlign"+ _state]
|
---|
1989 | , togLen = o["togglerLength"+ _state]
|
---|
1990 | , paneLen
|
---|
1991 | , offset
|
---|
1992 | , CSS = {}
|
---|
1993 | ;
|
---|
1994 | if (spacing == 0) {
|
---|
1995 | $R.hide();
|
---|
1996 | return;
|
---|
1997 | }
|
---|
1998 | else if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason
|
---|
1999 | $R.show(); // in case was previously hidden
|
---|
2000 |
|
---|
2001 | // Resizer Bar is ALWAYS same width/height of pane it is attached to
|
---|
2002 | if (dir == "horz") { // north/south
|
---|
2003 | paneLen = $P.outerWidth();
|
---|
2004 | $R.css({
|
---|
2005 | width: max(1, cssW($R, paneLen)) // account for borders & padding
|
---|
2006 | , height: max(1, cssH($R, spacing)) // ditto
|
---|
2007 | , left: cssNum($P, "left")
|
---|
2008 | });
|
---|
2009 | }
|
---|
2010 | else { // east/west
|
---|
2011 | paneLen = $P.outerHeight();
|
---|
2012 | $R.css({
|
---|
2013 | height: max(1, cssH($R, paneLen)) // account for borders & padding
|
---|
2014 | , width: max(1, cssW($R, spacing)) // ditto
|
---|
2015 | , top: cDims.top + getPaneSize("north", true)
|
---|
2016 | //, top: cssNum($Ps["center"], "top")
|
---|
2017 | });
|
---|
2018 |
|
---|
2019 | }
|
---|
2020 |
|
---|
2021 | if ($T) {
|
---|
2022 | if (togLen == 0 || (s.isSliding && o.hideTogglerOnSlide)) {
|
---|
2023 | $T.hide(); // always HIDE the toggler when 'sliding'
|
---|
2024 | return;
|
---|
2025 | }
|
---|
2026 | else
|
---|
2027 | $T.show(); // in case was previously hidden
|
---|
2028 |
|
---|
2029 | if (!(togLen > 0) || togLen == "100%" || togLen > paneLen) {
|
---|
2030 | togLen = paneLen;
|
---|
2031 | offset = 0;
|
---|
2032 | }
|
---|
2033 | else { // calculate 'offset' based on options.PANE.togglerAlign_open/closed
|
---|
2034 | if (typeof togAlign == "string") {
|
---|
2035 | switch (togAlign) {
|
---|
2036 | case "top":
|
---|
2037 | case "left": offset = 0;
|
---|
2038 | break;
|
---|
2039 | case "bottom":
|
---|
2040 | case "right": offset = paneLen - togLen;
|
---|
2041 | break;
|
---|
2042 | case "middle":
|
---|
2043 | case "center":
|
---|
2044 | default: offset = Math.floor((paneLen - togLen) / 2); // 'default' catches typos
|
---|
2045 | }
|
---|
2046 | }
|
---|
2047 | else { // togAlign = number
|
---|
2048 | var x = parseInt(togAlign); //
|
---|
2049 | if (togAlign >= 0) offset = x;
|
---|
2050 | else offset = paneLen - togLen + x; // NOTE: x is negative!
|
---|
2051 | }
|
---|
2052 | }
|
---|
2053 |
|
---|
2054 | var
|
---|
2055 | $TC_o = (o.togglerContent_open ? $T.children(".content-open") : false)
|
---|
2056 | , $TC_c = (o.togglerContent_closed ? $T.children(".content-closed") : false)
|
---|
2057 | , $TC = (s.isClosed ? $TC_c : $TC_o)
|
---|
2058 | ;
|
---|
2059 | if ($TC_o) $TC_o.css("display", s.isClosed ? "none" : "block");
|
---|
2060 | if ($TC_c) $TC_c.css("display", s.isClosed ? "block" : "none");
|
---|
2061 |
|
---|
2062 | if (dir == "horz") { // north/south
|
---|
2063 | var width = cssW($T, togLen);
|
---|
2064 | $T.css({
|
---|
2065 | width: max(0, width) // account for borders & padding
|
---|
2066 | , height: max(1, cssH($T, spacing)) // ditto
|
---|
2067 | , left: offset // TODO: VERIFY that toggler positions correctly for ALL values
|
---|
2068 | });
|
---|
2069 | if ($TC) // CENTER the toggler content SPAN
|
---|
2070 | $TC.css("marginLeft", Math.floor((width-$TC.outerWidth())/2)); // could be negative
|
---|
2071 | }
|
---|
2072 | else { // east/west
|
---|
2073 | var height = cssH($T, togLen);
|
---|
2074 | $T.css({
|
---|
2075 | height: max(0, height) // account for borders & padding
|
---|
2076 | , width: max(1, cssW($T, spacing)) // ditto
|
---|
2077 | , top: offset // POSITION the toggler
|
---|
2078 | });
|
---|
2079 | if ($TC) // CENTER the toggler content SPAN
|
---|
2080 | $TC.css("marginTop", Math.floor((height-$TC.outerHeight())/2)); // could be negative
|
---|
2081 | }
|
---|
2082 |
|
---|
2083 |
|
---|
2084 | }
|
---|
2085 |
|
---|
2086 | // DONE measuring and sizing this resizer/toggler, so can be 'hidden' now
|
---|
2087 | if (onInit && o.initHidden) {
|
---|
2088 | $R.hide();
|
---|
2089 | if ($T) $T.hide();
|
---|
2090 | }
|
---|
2091 | });
|
---|
2092 | };
|
---|
2093 |
|
---|
2094 |
|
---|
2095 | /**
|
---|
2096 | * resizeAll
|
---|
2097 | *
|
---|
2098 | * @callers window.onresize(), callbacks or custom code
|
---|
2099 | */
|
---|
2100 | var resizeAll = function () {
|
---|
2101 | var
|
---|
2102 | oldW = cDims.innerWidth
|
---|
2103 | , oldH = cDims.innerHeight
|
---|
2104 | ;
|
---|
2105 | cDims = state.container = getElemDims($Container); // UPDATE container dimensions
|
---|
2106 |
|
---|
2107 | var
|
---|
2108 | checkH = (cDims.innerHeight < oldH)
|
---|
2109 | , checkW = (cDims.innerWidth < oldW)
|
---|
2110 | , s, dir
|
---|
2111 | ;
|
---|
2112 |
|
---|
2113 | if (checkH || checkW)
|
---|
2114 | // NOTE special order for sizing: S-N-E-W
|
---|
2115 | $.each(["south","north","east","west"], function(i,pane) {
|
---|
2116 | s = state[pane];
|
---|
2117 | dir = c[pane].dir;
|
---|
2118 | if (!s.isClosed && ((checkH && dir=="horz") || (checkW && dir=="vert"))) {
|
---|
2119 | setPaneMinMaxSizes(pane); // update pane-state
|
---|
2120 | // shrink pane if 'too big' to fit
|
---|
2121 | if (s.size > s.maxSize)
|
---|
2122 | sizePane(pane, s.maxSize);
|
---|
2123 | }
|
---|
2124 | });
|
---|
2125 |
|
---|
2126 | sizeMidPanes("all");
|
---|
2127 | sizeHandles("all"); // reposition the toggler elements
|
---|
2128 | };
|
---|
2129 |
|
---|
2130 |
|
---|
2131 | /**
|
---|
2132 | * keyDown
|
---|
2133 | *
|
---|
2134 | * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed
|
---|
2135 | *
|
---|
2136 | * @callers document.keydown()
|
---|
2137 | */
|
---|
2138 | function keyDown (evt) {
|
---|
2139 | if (!evt) return true;
|
---|
2140 | var code = evt.keyCode;
|
---|
2141 | if (code < 33) return true; // ignore special keys: ENTER, TAB, etc
|
---|
2142 |
|
---|
2143 | var
|
---|
2144 | PANE = {
|
---|
2145 | 38: "north" // Up Cursor
|
---|
2146 | , 40: "south" // Down Cursor
|
---|
2147 | , 37: "west" // Left Cursor
|
---|
2148 | , 39: "east" // Right Cursor
|
---|
2149 | }
|
---|
2150 | , isCursorKey = (code >= 37 && code <= 40)
|
---|
2151 | , ALT = evt.altKey // no worky!
|
---|
2152 | , SHIFT = evt.shiftKey
|
---|
2153 | , CTRL = evt.ctrlKey
|
---|
2154 | , pane = false
|
---|
2155 | , s, o, k, m, el
|
---|
2156 | ;
|
---|
2157 |
|
---|
2158 | if (!CTRL && !SHIFT)
|
---|
2159 | return true; // no modifier key - abort
|
---|
2160 | else if (isCursorKey && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey
|
---|
2161 | pane = PANE[code];
|
---|
2162 | else // check to see if this matches a custom-hotkey
|
---|
2163 | $.each(c.borderPanes.split(","), function(i,p) { // loop each pane to check its hotkey
|
---|
2164 | o = options[p];
|
---|
2165 | k = o.customHotkey;
|
---|
2166 | m = o.customHotkeyModifier; // if missing or invalid, treated as "CTRL+SHIFT"
|
---|
2167 | if ((SHIFT && m=="SHIFT") || (CTRL && m=="CTRL") || (CTRL && SHIFT)) { // Modifier matches
|
---|
2168 | if (k && code == (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches
|
---|
2169 | pane = p;
|
---|
2170 | return false; // BREAK
|
---|
2171 | }
|
---|
2172 | }
|
---|
2173 | });
|
---|
2174 |
|
---|
2175 | if (!pane) return true; // no hotkey - abort
|
---|
2176 |
|
---|
2177 | // validate pane
|
---|
2178 | o = options[pane]; // get pane options
|
---|
2179 | s = state[pane]; // get pane options
|
---|
2180 | if (!o.enableCursorHotkey || s.isHidden || !$Ps[pane]) return true;
|
---|
2181 |
|
---|
2182 | // see if user is in a 'form field' because may be 'selecting text'!
|
---|
2183 | el = evt.target || evt.srcElement;
|
---|
2184 | if (el && SHIFT && isCursorKey && (el.tagName=="TEXTAREA" || (el.tagName=="INPUT" && (code==37 || code==39))))
|
---|
2185 | return true; // allow text-selection
|
---|
2186 |
|
---|
2187 | // SYNTAX NOTES
|
---|
2188 | // use "returnValue=false" to abort keystroke but NOT abort function - can run another command afterwards
|
---|
2189 | // use "return false" to abort keystroke AND abort function
|
---|
2190 | toggle(pane);
|
---|
2191 | evt.stopPropagation();
|
---|
2192 | evt.returnValue = false; // CANCEL key
|
---|
2193 | return false;
|
---|
2194 | };
|
---|
2195 |
|
---|
2196 |
|
---|
2197 | /*
|
---|
2198 | * ###########################
|
---|
2199 | * UTILITY METHODS
|
---|
2200 | * called externally only
|
---|
2201 | * ###########################
|
---|
2202 | */
|
---|
2203 |
|
---|
2204 | function allowOverflow (elem) {
|
---|
2205 | if (this && this.tagName) elem = this; // BOUND to element
|
---|
2206 | var $P;
|
---|
2207 | if (typeof elem=="string")
|
---|
2208 | $P = $Ps[elem];
|
---|
2209 | else {
|
---|
2210 | if ($(elem).attr("pane")) $P = $(elem);
|
---|
2211 | else $P = $(elem).parents("div[pane]:first");
|
---|
2212 | }
|
---|
2213 | if (!$P.length) return; // INVALID
|
---|
2214 |
|
---|
2215 | var
|
---|
2216 | pane = $P.attr("pane")
|
---|
2217 | , s = state[pane]
|
---|
2218 | ;
|
---|
2219 |
|
---|
2220 | // if pane is already raised, then reset it before doing it again!
|
---|
2221 | // this would happen if allowOverflow is attached to BOTH the pane and an element
|
---|
2222 | if (s.cssSaved)
|
---|
2223 | resetOverflow(pane); // reset previous CSS before continuing
|
---|
2224 |
|
---|
2225 | // if pane is raised by sliding or resizing, or it's closed, then abort
|
---|
2226 | if (s.isSliding || s.isResizing || s.isClosed) {
|
---|
2227 | s.cssSaved = false;
|
---|
2228 | return;
|
---|
2229 | }
|
---|
2230 |
|
---|
2231 | var
|
---|
2232 | newCSS = { zIndex: (c.zIndex.pane_normal + 1) }
|
---|
2233 | , curCSS = {}
|
---|
2234 | , of = $P.css("overflow")
|
---|
2235 | , ofX = $P.css("overflowX")
|
---|
2236 | , ofY = $P.css("overflowY")
|
---|
2237 | ;
|
---|
2238 | // determine which, if any, overflow settings need to be changed
|
---|
2239 | if (of != "visible") {
|
---|
2240 | curCSS.overflow = of;
|
---|
2241 | newCSS.overflow = "visible";
|
---|
2242 | }
|
---|
2243 | if (ofX && ofX != "visible" && ofX != "auto") {
|
---|
2244 | curCSS.overflowX = ofX;
|
---|
2245 | newCSS.overflowX = "visible";
|
---|
2246 | }
|
---|
2247 | if (ofY && ofY != "visible" && ofY != "auto") {
|
---|
2248 | curCSS.overflowY = ofX;
|
---|
2249 | newCSS.overflowY = "visible";
|
---|
2250 | }
|
---|
2251 |
|
---|
2252 | // save the current overflow settings - even if blank!
|
---|
2253 | s.cssSaved = curCSS;
|
---|
2254 |
|
---|
2255 | // apply new CSS to raise zIndex and, if necessary, make overflow 'visible'
|
---|
2256 | $P.css( newCSS );
|
---|
2257 |
|
---|
2258 | // make sure the zIndex of all other panes is normal
|
---|
2259 | $.each(c.allPanes.split(","), function(i, p) {
|
---|
2260 | if (p != pane) resetOverflow(p);
|
---|
2261 | });
|
---|
2262 |
|
---|
2263 | };
|
---|
2264 |
|
---|
2265 | function resetOverflow (elem) {
|
---|
2266 | if (this && this.tagName) elem = this; // BOUND to element
|
---|
2267 | var $P;
|
---|
2268 | if (typeof elem=="string")
|
---|
2269 | $P = $Ps[elem];
|
---|
2270 | else {
|
---|
2271 | if ($(elem).hasClass("ui-layout-pane")) $P = $(elem);
|
---|
2272 | else $P = $(elem).parents("div[pane]:first");
|
---|
2273 | }
|
---|
2274 | if (!$P.length) return; // INVALID
|
---|
2275 |
|
---|
2276 | var
|
---|
2277 | pane = $P.attr("pane")
|
---|
2278 | , s = state[pane]
|
---|
2279 | , CSS = s.cssSaved || {}
|
---|
2280 | ;
|
---|
2281 | // reset the zIndex
|
---|
2282 | if (!s.isSliding && !s.isResizing)
|
---|
2283 | $P.css("zIndex", c.zIndex.pane_normal);
|
---|
2284 |
|
---|
2285 | // reset Overflow - if necessary
|
---|
2286 | $P.css( CSS );
|
---|
2287 |
|
---|
2288 | // clear var
|
---|
2289 | s.cssSaved = false;
|
---|
2290 | };
|
---|
2291 |
|
---|
2292 |
|
---|
2293 | /**
|
---|
2294 | * getBtn
|
---|
2295 | *
|
---|
2296 | * Helper function to validate params received by addButton utilities
|
---|
2297 | *
|
---|
2298 | * @param String selector jQuery selector for button, eg: ".ui-layout-north .toggle-button"
|
---|
2299 | * @param String pane Name of the pane the button is for: 'north', 'south', etc.
|
---|
2300 | * @returns If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise 'false'
|
---|
2301 | */
|
---|
2302 | function getBtn(selector, pane, action) {
|
---|
2303 | var
|
---|
2304 | $E = $(selector)
|
---|
2305 | , err = "Error Adding Button \n\nInvalid "
|
---|
2306 | ;
|
---|
2307 | if (!$E.length) // element not found
|
---|
2308 | alert(err+"selector: "+ selector);
|
---|
2309 | else if (c.borderPanes.indexOf(pane) == -1) // invalid 'pane' sepecified
|
---|
2310 | alert(err+"pane: "+ pane);
|
---|
2311 | else { // VALID
|
---|
2312 | var btn = options[pane].buttonClass +"-"+ action;
|
---|
2313 | $E.addClass( btn +" "+ btn +"-"+ pane );
|
---|
2314 | return $E;
|
---|
2315 | }
|
---|
2316 | return false; // INVALID
|
---|
2317 | };
|
---|
2318 |
|
---|
2319 |
|
---|
2320 | /**
|
---|
2321 | * addToggleBtn
|
---|
2322 | *
|
---|
2323 | * Add a custom Toggler button for a pane
|
---|
2324 | *
|
---|
2325 | * @param String selector jQuery selector for button, eg: ".ui-layout-north .toggle-button"
|
---|
2326 | * @param String pane Name of the pane the button is for: 'north', 'south', etc.
|
---|
2327 | */
|
---|
2328 | function addToggleBtn (selector, pane) {
|
---|
2329 | var $E = getBtn(selector, pane, "toggle");
|
---|
2330 | if ($E)
|
---|
2331 | $E
|
---|
2332 | .attr("title", state[pane].isClosed ? "Open" : "Close")
|
---|
2333 | .click(function (evt) {
|
---|
2334 | toggle(pane);
|
---|
2335 | evt.stopPropagation();
|
---|
2336 | })
|
---|
2337 | ;
|
---|
2338 | };
|
---|
2339 |
|
---|
2340 | /**
|
---|
2341 | * addOpenBtn
|
---|
2342 | *
|
---|
2343 | * Add a custom Open button for a pane
|
---|
2344 | *
|
---|
2345 | * @param String selector jQuery selector for button, eg: ".ui-layout-north .open-button"
|
---|
2346 | * @param String pane Name of the pane the button is for: 'north', 'south', etc.
|
---|
2347 | */
|
---|
2348 | function addOpenBtn (selector, pane) {
|
---|
2349 | var $E = getBtn(selector, pane, "open");
|
---|
2350 | if ($E)
|
---|
2351 | $E
|
---|
2352 | .attr("title", "Open")
|
---|
2353 | .click(function (evt) {
|
---|
2354 | open(pane);
|
---|
2355 | evt.stopPropagation();
|
---|
2356 | })
|
---|
2357 | ;
|
---|
2358 | };
|
---|
2359 |
|
---|
2360 | /**
|
---|
2361 | * addCloseBtn
|
---|
2362 | *
|
---|
2363 | * Add a custom Close button for a pane
|
---|
2364 | *
|
---|
2365 | * @param String selector jQuery selector for button, eg: ".ui-layout-north .close-button"
|
---|
2366 | * @param String pane Name of the pane the button is for: 'north', 'south', etc.
|
---|
2367 | */
|
---|
2368 | function addCloseBtn (selector, pane) {
|
---|
2369 | var $E = getBtn(selector, pane, "close");
|
---|
2370 | if ($E)
|
---|
2371 | $E
|
---|
2372 | .attr("title", "Close")
|
---|
2373 | .click(function (evt) {
|
---|
2374 | close(pane);
|
---|
2375 | evt.stopPropagation();
|
---|
2376 | })
|
---|
2377 | ;
|
---|
2378 | };
|
---|
2379 |
|
---|
2380 | /**
|
---|
2381 | * addPinBtn
|
---|
2382 | *
|
---|
2383 | * Add a custom Pin button for a pane
|
---|
2384 | *
|
---|
2385 | * Four classes are added to the element, based on the paneClass for the associated pane...
|
---|
2386 | * Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin:
|
---|
2387 | * - ui-layout-pane-pin
|
---|
2388 | * - ui-layout-pane-west-pin
|
---|
2389 | * - ui-layout-pane-pin-up
|
---|
2390 | * - ui-layout-pane-west-pin-up
|
---|
2391 | *
|
---|
2392 | * @param String selector jQuery selector for button, eg: ".ui-layout-north .ui-layout-pin"
|
---|
2393 | * @param String pane Name of the pane the pin is for: 'north', 'south', etc.
|
---|
2394 | */
|
---|
2395 | function addPinBtn (selector, pane) {
|
---|
2396 | var $E = getBtn(selector, pane, "pin");
|
---|
2397 | if ($E) {
|
---|
2398 | var s = state[pane];
|
---|
2399 | $E.click(function (evt) {
|
---|
2400 | setPinState($(this), pane, (s.isSliding || s.isClosed));
|
---|
2401 | if (s.isSliding || s.isClosed) open( pane ); // change from sliding to open
|
---|
2402 | else close( pane ); // slide-closed
|
---|
2403 | evt.stopPropagation();
|
---|
2404 | });
|
---|
2405 | // add up/down pin attributes and classes
|
---|
2406 | setPinState ($E, pane, (!s.isClosed && !s.isSliding));
|
---|
2407 | // add this pin to the pane data so we can 'sync it' automatically
|
---|
2408 | // PANE.pins key is an array so we can store multiple pins for each pane
|
---|
2409 | c[pane].pins.push( selector ); // just save the selector string
|
---|
2410 | }
|
---|
2411 | };
|
---|
2412 |
|
---|
2413 | /**
|
---|
2414 | * syncPinBtns
|
---|
2415 | *
|
---|
2416 | * INTERNAL function to sync 'pin buttons' when pane is opened or closed
|
---|
2417 | * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes
|
---|
2418 | *
|
---|
2419 | * @callers open(), close()
|
---|
2420 | * @params pane These are the params returned to callbacks by layout()
|
---|
2421 | * @params doPin True means set the pin 'down', False means 'up'
|
---|
2422 | */
|
---|
2423 | function syncPinBtns (pane, doPin) {
|
---|
2424 | $.each(c[pane].pins, function (i, selector) {
|
---|
2425 | setPinState($(selector), pane, doPin);
|
---|
2426 | });
|
---|
2427 | };
|
---|
2428 |
|
---|
2429 | /**
|
---|
2430 | * setPinState
|
---|
2431 | *
|
---|
2432 | * Change the class of the pin button to make it look 'up' or 'down'
|
---|
2433 | *
|
---|
2434 | * @callers addPinBtn(), syncPinBtns()
|
---|
2435 | * @param Element $Pin The pin-span element in a jQuery wrapper
|
---|
2436 | * @param Boolean doPin True = set the pin 'down', False = set it 'up'
|
---|
2437 | * @param String pinClass The root classname for pins - will add '-up' or '-down' suffix
|
---|
2438 | */
|
---|
2439 | function setPinState ($Pin, pane, doPin) {
|
---|
2440 | var updown = $Pin.attr("pin");
|
---|
2441 | if (updown && doPin == (updown=="down")) return; // already in correct state
|
---|
2442 | var
|
---|
2443 | root = options[pane].buttonClass
|
---|
2444 | , class1 = root +"-pin"
|
---|
2445 | , class2 = class1 +"-"+ pane
|
---|
2446 | , UP1 = class1 + "-up"
|
---|
2447 | , UP2 = class2 + "-up"
|
---|
2448 | , DN1 = class1 + "-down"
|
---|
2449 | , DN2 = class2 + "-down"
|
---|
2450 | ;
|
---|
2451 | $Pin
|
---|
2452 | .attr("pin", doPin ? "down" : "up") // logic
|
---|
2453 | .attr("title", doPin ? "Un-Pin" : "Pin")
|
---|
2454 | .removeClass( doPin ? UP1 : DN1 )
|
---|
2455 | .removeClass( doPin ? UP2 : DN2 )
|
---|
2456 | .addClass( doPin ? DN1 : UP1 )
|
---|
2457 | .addClass( doPin ? DN2 : UP2 )
|
---|
2458 | ;
|
---|
2459 | };
|
---|
2460 |
|
---|
2461 |
|
---|
2462 | /*
|
---|
2463 | * ###########################
|
---|
2464 | * CREATE/RETURN BORDER-LAYOUT
|
---|
2465 | * ###########################
|
---|
2466 | */
|
---|
2467 |
|
---|
2468 | // init global vars
|
---|
2469 | var
|
---|
2470 | $Container = $(this).css({ overflow: "hidden" }) // Container elem
|
---|
2471 | , $Ps = {} // Panes x4 - set in initPanes()
|
---|
2472 | , $Cs = {} // Content x4 - set in initPanes()
|
---|
2473 | , $Rs = {} // Resizers x4 - set in initHandles()
|
---|
2474 | , $Ts = {} // Togglers x4 - set in initHandles()
|
---|
2475 | // object aliases
|
---|
2476 | , c = config // alias for config hash
|
---|
2477 | , cDims = state.container // alias for easy access to 'container dimensions'
|
---|
2478 | ;
|
---|
2479 |
|
---|
2480 | // create the border layout NOW
|
---|
2481 | create();
|
---|
2482 |
|
---|
2483 | // return object pointers to expose data & option Properties, and primary action Methods
|
---|
2484 | return {
|
---|
2485 | options: options // property - options hash
|
---|
2486 | , state: state // property - dimensions hash
|
---|
2487 | , panes: $Ps // property - object pointers for ALL panes: panes.north, panes.center
|
---|
2488 | , toggle: toggle // method - pass a 'pane' ("north", "west", etc)
|
---|
2489 | , open: open // method - ditto
|
---|
2490 | , close: close // method - ditto
|
---|
2491 | , hide: hide // method - ditto
|
---|
2492 | , show: show // method - ditto
|
---|
2493 | , resizeContent: sizeContent // method - ditto
|
---|
2494 | , sizePane: sizePane // method - pass a 'pane' AND a 'size' in pixels
|
---|
2495 | , resizeAll: resizeAll // method - no parameters
|
---|
2496 | , addToggleBtn: addToggleBtn // utility - pass element selector and 'pane'
|
---|
2497 | , addOpenBtn: addOpenBtn // utility - ditto
|
---|
2498 | , addCloseBtn: addCloseBtn // utility - ditto
|
---|
2499 | , addPinBtn: addPinBtn // utility - ditto
|
---|
2500 | , allowOverflow: allowOverflow // utility - pass calling element
|
---|
2501 | , resetOverflow: resetOverflow // utility - ditto
|
---|
2502 | , cssWidth: cssW
|
---|
2503 | , cssHeight: cssH
|
---|
2504 | };
|
---|
2505 |
|
---|
2506 | }
|
---|
2507 | })( jQuery ); |
---|