[7209] | 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 ); |
---|