jsgem-jquery-layout 1.2.0.pre1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +28 -0
- data/Rakefile +1 -0
- data/jsgem-jquery-layout.gemspec +21 -0
- data/lib/jsgem-jquery-layout/version.rb +7 -0
- data/lib/jsgem-jquery-layout.rb +10 -0
- data/vendor/assets/javascripts/jquery-layout.js +2507 -0
- data/vendor/assets/stylesheets/jquery-layout.css +121 -0
- metadata +71 -0
|
@@ -0,0 +1,2507 @@
|
|
|
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 );
|