--- trunk/web/iwf/iwfgui.js 2005/11/14 16:16:57 54 +++ trunk/web/iwf/iwfgui.js 2005/11/15 14:29:45 55 @@ -1,51 +1,65 @@ -// ----------------------------------------------------------------------------- -// IWF - Interactive Website Framework. Javascript library for creating -// responsive thin client interfaces. -// -// Copyright (C) 2005 Brock Weaver brockweaver@gmail.com -// -// This library is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -// License for more details. +// -------------------------------------------------------------------------- +/// IWF - Interactive Website Framework. Javascript library for creating +/// responsive thin client interfaces. +/// +/// Copyright (C) 2005 Brock Weaver brockweaver@users.sourceforge.net +/// +/// This library is free software; you can redistribute it and/or modify +/// it under the terms of the GNU Lesser General Public License as published +/// by the Free Software Foundation; either version 2.1 of the License, or +/// (at your option) any later version. +/// +/// This library is distributed in the hope that it will be useful, but +/// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +/// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +/// License for more details. +/// +/// You should have received a copy of the GNU Lesser General Public License +/// along with this library; if not, write to the Free Software Foundation, +/// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/// +/// Brock Weaver +/// brockweaver@users.sourceforge.net +/// 1605 NW Maple Pl +/// Ankeny, IA 50021 +/// +//! http://iwf.sourceforge.net/ +// -------------------------------------------------------------------------- +//! NOTE: To minimize file size, strip all fluffy comments (except the LGPL, of course!) +//! using the following regex (global flag and multiline on): +//! ^\t*//([^/!].*|$) // -// You should have received a copy of the GNU Lesser General Public License -// along with this library; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// This reduces file size by about 30%, give or take. // -// Brock Weaver -// brockweaver@gmail.com -// 1605 NW Maple Pl -// Ankeny, IA 50021 -// ----------------------------------------------------------------------------- +//! To rip out only logging statements (commented or uncommented): +//! ^/{0,2}iwfLog.* +// -------------------------------------------------------------------------- // -------------------------------------------------------------------------- -// iwfgui.js +//! iwfgui.js // // GUI inspection and manipulation functions // -// Dependencies: -// iwfcore.js +//! Dependencies: +//! iwfcore.js // -// Brock Weaver - brockweaver@sourceforge.net - iwf.sourceforge.net -// v 0.1 - 2005-06-05 -// Initial release. +//! Brock Weaver - brockweaver@users.sourceforge.net +//! v 0.2 - 2005-11-14 +//! core bug patch +// -------------------------------------------------------------------------- +//! v 0.1 - 2005-06-05 +//! Initial release. // -------------------------------------------------------------------------- // Issues: // Timeouts have hiccups sometimes when they begin to overlap -// Not tested on Safari -- I need an iMac! +// Not tested on Safari -- I need a Mac! // _iwfMoveTo() has some calculation problems with certain motionType values // -------------------------------------------------------------------------- // ----------------------------------- // Dependency Check if (!window.iwfGetById){ - alert("IWF Dependency Error: you must set a reference to the iwfcore.js file *before* iwfgui.js! I.E.:\n\n\n"); + iwfLog("IWF Dependency Error: you must set a reference to the iwfcore.js file *before* iwfgui.js! I.E.:\n\n\n", true); } // ----------------------------------- @@ -339,12 +353,12 @@ } -// BROCK function iwfDelay(ms, fpOrString){ + // note this inner function creates a closure... function _iwfDelayExpired(){ if (localIsString){ // passed a string. eval it. -iwfLog("_iwfDelayExpired: calling string of:\n" + localFpOrString, true); +//iwfLog("_iwfDelayExpired: calling string of:\n" + localFpOrString, true); eval(localFpOrString); } else { // they passed a function pointer. @@ -526,11 +540,13 @@ function iwfZIndex(id, z){ var el = iwfGetById(id); + if (!el) return 0; + if (iwfExists(el)){ if (iwfExists(z)){ el.style.zIndex = z; } - return parseInt(el.style.zIndex); + return iwfToInt(el.style.zIndex, true); } return 0; } @@ -599,7 +615,7 @@ var elX = iwfX1(el); var elY = iwfY1(el); - // hack for floating point anomolies -- stops animation when element is "close enough" + //! hack for floating point anomolies -- stops animation when element is "close enough" var epsilon = 0.001; var xDone = false; @@ -625,7 +641,7 @@ } if (ticksLeft <= 0 || (xDone && yDone)){ - // time is up. / motion is done + //! time is up / motion is "close enough" //iwfLog("_iwfMoveTo time is up / motion is done."); iwfX1(el, xDest); iwfY1(el, yDest); @@ -871,6 +887,36 @@ // Begin: Size // ----------------------------------- +function iwfClientHeight(){ + var vHeight = 0; + if(document.compatMode == 'CSS1Compat' && document.documentElement && document.documentElement.clientHeight) { + vHeight = document.documentElement.clientHeight; + } else if(document.body && document.body.clientHeight) { + vHeight = document.body.clientHeight; + } else if(iwfExists(window.innerWidth,window.innerHeight,document.width)) { + vHeight = window.innerHeight; + if(document.width>window.innerWidth) { + vHeight -= 16; + } + } + return vHeight; +} + +function iwfClientWidth(){ + var vWidth = 0; + if(document.compatMode == 'CSS1Compat' && document.documentElement && document.documentElement.clientWidth) { + vWidth = document.documentElement.clientWidth; + } else if(document.body && document.body.clientWidth) { + vWidth = document.body.clientWidth; + } else if(iwfExists(window.innerWidth,window.innerHeight,document.height)) { + vWidth = window.innerWidth; + if(document.height>window.innerHeight) { + vWidth -= 16; + } + } + return vWidth; +} + function iwfWidth(id, neww){ @@ -904,23 +950,6 @@ -// var el = iwfGetById(id); -// var w = 0; -// if (iwfExists(el)){ -// if(iwfExists(el.style, el.offsetWidth) && iwfIsString(el.style.width)) { -// if(neww) iwfDetermineWidth(el, neww); -// w = el.offsetWidth; -// } -// else if(iwfExists(el.style) && iwfExists(el.style.pixelWidth)) { -// if(neww) el.style.pixelWidth = neww; -// w = el.style.pixelWidth; -// } -// else if(iwfExists(el.clip) && iwfExists(el.clip.right)) { -// if(neww) e.clip.right = neww; -// w = el.clip.right; -// } -// } -// return w; } function iwfHeight(id, newh){ @@ -953,8 +982,7 @@ if (iwfExists(el)) { var y1 = iwfY(el); if (iwfExists(y2)){ - var h = iwfHeight(el); - iwfHeight(el, y1 + h); + iwfHeight(el, y2 - y1); } return y1 + iwfHeight(el); } @@ -964,10 +992,9 @@ function iwfX2(id, x2){ var el = iwfGetById(id); if (iwfExists(el)) { - var x1 = iwfX(id); + var x1 = iwfX(el); if (iwfExists(x2)){ - var w = iwfWidth(id); - iwfWidth(id, x1 + h); + iwfWidth(el, x2 - x1); } return x1 + iwfWidth(el); } @@ -987,10 +1014,10 @@ } else if(iwfExists(el.currentStyle,document.compatMode)){ if(document.compatMode=='CSS1Compat'){ - padl = parseInt(el.currentStyle.paddingLeft); - padr = parseInt(el.currentStyle.paddingRight); - bdrl = parseInt(el.currentStyle.borderLeftWidth); - bdrr = parseInt(el.currentStyle.borderRightWidth); + padl = iwfToInt(el.currentStyle.paddingLeft, true); + padr = iwfToInt(el.currentStyle.paddingRight, true); + bdrl = iwfToInt(el.currentStyle.borderLeftWidth, true); + bdrr = iwfToInt(el.currentStyle.borderRightWidth, true); } } else if(iwfExists(el.offsetWidth,el.style.width)){ el.style.width = neww + 'px'; @@ -1016,10 +1043,10 @@ badb = iwfDetermineStyle(el,'border-bottom-height'); } else if(iwfExists(el.currentStyle,document.compatMode)){ if(document.compatMode=='CSS1Compat'){ - padt = parseInt(el.currentStyle.paddingTop); - padb = parseInt(el.currentStyle.paddingBottom); - bdrt = parseInt(el.currentStyle.borderTopHeight); - bdrb = parseInt(el.currentStyle.borderBottomHeight); + padt = iwfToInt(el.currentStyle.paddingTop, true); + padb = iwfToInt(el.currentStyle.paddingBottom, true); + bdrt = iwfToInt(el.currentStyle.borderTopHeight, true); + bdrb = iwfToInt(el.currentStyle.borderBottomHeight, true); } } else if(iwfExists(el.offsetHeight, el.style.height)){ el.style.height = newh + 'px'; @@ -1037,6 +1064,41 @@ else el.style.height = h2 + 'px'; } +function iwfOverlaps(id1, id2) { + var el1 = iwfGetById(id1); + var el2 = iwfGetById(id2); + + if (!el1 || !el2) return false; + + var x1a = iwfX(el1); + var x1b = iwfX2(el1); + var y1a = iwfY(el1); + var y1b = iwfY2(el1); + + var x2a = iwfX(el2); + var x2b = iwfX2(el2); + var y2a = iwfY(el2); + var y2b = iwfY2(el2); + + if(x1a > x2b || x1b < x2a || y1a > y2b || y1b < y2a) { + return false; + } else { + return true; + } + +} + +function iwfXCenter(id) { + var el = iwfGetById(id); + if (!el) return 0; + return iwfX(el) + iwfWidth(el) / 2; +} + +function iwfYCenter(id) { + var el = iwfGetById(id); + if (!el) return 0; + return iwfY(el) + iwfHeight(el) / 2; +} // ----------------------------------- // End: Size @@ -1046,21 +1108,73 @@ // Begin: Event // ----------------------------------- -function iwfAddEvent(id,eventName,callback) { +function iwfAddEvent(id, eventName,callback) { var el = iwfGetById(id); if (!el) return; - if (el.attachEvent) { + + var txt = callback; + if (iwfIsString(callback)){ + callback = function() { eval(txt);}; + } + + if (el.addEventListener) { + el.addEventListener(eventName.substr(2), callback, false); + } else if (el.attachEvent) { +//iwfLog('attaching event ' + eventName + ' to element ' + el.id + ' with the callback:\n' + callback, true); el.attachEvent(eventName, callback); } else { - el[eventName] = callback; + iwfLog("Couldn't add event " + eventName + " to element " + el.id + " because neither addEventListener nor attachEvent are implemented.", true); } } function iwfRemoveEvent(id, eventName, callback){ var el = iwfGetById(id); if (!el) return; - if (el.detachEvent) el.detachEvent(eventName, callback); - else eval('el.' + eventName + ' = null;'); + if (el.removeEventListener) { + el.removeEventListener(eventName.substr(2), callback, false); + } else if (el.detachEvent) { + el.detachEvent(eventName, callback); + } else { + iwfLog("Couldn't remove event " + eventName + " from element " + el.id + " because neither removeEventListener nor detachEvent are implemented.", true); + } +} + +function iwfCallAttribute(id, eventName, evt){ + var el = iwfGetById(id); + if (!el) return false; + + var val = iwfAttribute(el, eventName); +//iwfLog("calling attribute " + eventName + "=" + val, true); + if (val){ + eval(val); + } + + return; + + + + + if (el.fireEvent){ +iwfLog("firing event " + eventName + " on el " + el.id); + el.fireEvent(eventName, evt); + } else if (el.dispatchEvent){ + // chop off the "on" at the beginning... +// eventName = eventName.substr(2); +// iwfLog(eventName, true); + var newEvent = null; + if (document.createEvent){ + newEvent = document.createEvent("Events"); + } else { + newEvent = document.createEventObject(); + } + newEvent.initEvent(eventName, true, true); //, document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null); +iwfLog("dispatching event " + eventName + " on el " + el.id); + if (!el.dispatchEvent(newEvent)){ +iwfLog("Could not el.dispatchEvent failed!", true); + } + } else { +iwfLog("Could not el.fireEvent or el.dispatchEvent!", true); + } } function iwfEvent(ev) { @@ -1076,6 +1190,9 @@ if(evt.target) this.target = evt.target; else if(evt.srcElement) this.target = evt.srcElement; + this.X = iwfX(evt.target); + this.Y = iwfY(evt.target); + if(iwfExists(evt.clientX,evt.clientY)) { this.X = evt.clientX + iwfXScroll(); this.Y = evt.clientY + iwfYScroll(); @@ -1158,84 +1275,419 @@ // Begin: Drag-N-Drop // ----------------------------------- -var iwfDragger = {el:null, inUse:false}; +var iwfDragger = {el:null, curTarget:null, targets:new Array()}; var iwfHiZ = 2; -function iwfEnableDrag(id, startCallback, dragCallback, endCallback) { +var iwfResizer = {elSrc:null, elTgt:null}; + +function iwfResize(resizeId, targetId){ + var resizer = iwfGetById(resizeId); + if (!resizer) return; + + var target = iwfGetById(targetId); + if (!target) return; + + iwfResizer.elSrc = resizer; + iwfResizer.elTgt = target; + + + // set the drag start / move / stop + iwfAttribute(resizer, 'iwfdragbegin', 'iwfResizeStart()'); + iwfAttribute(resizer, 'iwfdragmove', 'iwfResizeMove()'); + iwfAttribute(resizer, 'iwfdragend', 'iwfResizeEnd()'); + + iwfDrag(resizer); + +} + +function iwfResizeStart(){ + +} + +function iwfResizeMove(resizeId, targetId){ + // elSrc should have already been moved to its new location. + // make elTgt fit to it. + var tgtX = iwfX(iwfResizer.elTgt); + var tgtY = iwfY(iwfResizer.elTgt); + + var srcX2 = iwfX2(iwfResizer.elSrc); + if (srcX2 - 100 < tgtX){ + srcX2 = tgtX + 100; + } + + var srcY2 = iwfY2(iwfResizer.elSrc); + if (srcY2 - 50 < tgtY){ + srcY2 = tgtY + 50; + } +//iwfLog("srcX2:" + srcX2 + "\tsrcY2:" + srcY2); +// iwfX1(iwfResizer.elSrc, srcX2 - iwfWidth(iwfResizer.elSrc)); +// iwfY1(iwfResizer.elSrc, srcY2 - iwfHeight(iwfResizer.elSrc)); + +// iwfX2(iwfResizer.elTgt, srcX2); +// iwfY2(iwfResizer.elTgt, srcY2); + + // if container exists, make it occupy all but titlebar space... + if (iwfResizer.elTgt){ + var elContainer = iwfGetById(iwfResizer.elTgt.id + 'Container'); + if (elContainer){ + iwfHeight(elContainer, iwfHeight(iwfResizer.elTgt) - iwfHeight(iwfResizer.elTgt.id + 'TitleBar') - 2); + } + } + + +} + +function iwfResizeEnd(){ + +iwfLog(iwfElementToString(iwfResizer.elSrc), true); + + iwfResizer.elSrc = null; + iwfResizer.elTgt = null; +} + +function iwfDrag(id) { + var el = iwfGetById(id); if (!el) return; - el.iwfDraggable = true; - el.iwfOnDragStart = startCallback; - el.iwfOnDrag = dragCallback; - el.iwfOnDragEnd = endCallback; - iwfAddEvent(el, 'onmousedown', iwfDragMouseDown); - if (!iwfDragger.inUse) { - iwfDragger.inUse = true; - iwfAddEvent(document, 'onmousemove', iwfDragMouseMove); + +//iwfLog(iwfElementToString(el), true); + if (!iwfDragger.el) { + el.iwfDragTarget = true; + iwfAddEvent(el, 'onmousedown', iwfDragMouseDown); + // BROCK: sync issues here in IE when there is no container. + // HACK: force a container always? hmmmm... +// iwfFireEvent(el, 'onmousedown'); } } function iwfDragMouseDown(ev){ + var evt = new iwfEvent(ev); var el = evt.target; - while(el && !el.iwfDraggable) { - el = iwfParent(el); + while(el && !el.iwfDragTarget) { + el = iwfGetParent(el); } if (el) { + + iwfDragger.el = el; + + iwfAddEvent(document, 'onmousemove', iwfDragMouseMove); + iwfAddEvent(document, 'onmouseup', iwfDragMouseUp); + + + if (ev && ev.preventDefault) ev.preventDefault(); else if (window.event) window.event.returnValue = false; - el.iwfDragX = evt.X; - el.iwfDragY = evt.Y; + else if (iwfExists(ev.cancelBubble)) ev.cancelBubble = true; + + el.iwfDragOrigX = iwfX(el); + el.iwfDragOrigY = iwfY(el); + el.iwfDragOffsetX = evt.X - iwfX(el); + el.iwfDragOffsetY = evt.Y - iwfY(el); + iwfZIndex(el, iwfHiZ++); - iwfDragger.el = el; - iwfAddEvent(document, 'onmouseup', iwfDragMouseUp, false); - if (el.iwfOnDragStart) { - el.iwfOnDragStart(el, evt.X, evt.Y); - } + iwfCallAttribute(el, 'iwfdragbegin'); } } function iwfDragMouseMove(ev){ var evt = new iwfEvent(ev); + if (iwfDragger.el) { - if (ev && ev.preventDefault) ev.preventDefault(); + if (evt && evt.preventDefault) evt.preventDefault(); else if (window.event) window.event.returnValue = false; + else if (iwfExists(ev.cancelBubble)) ev.cancelBubble = true; + var el = iwfDragger.el; - var dx = evt.X - el.iwfDragX; - var dy = evt.Y - el.iwfDragY; - el.iwfDragX = evt.X; - el.iwfDragY = evt.Y; - if (el.iwfOnDrag) { - el.iwfOnDrag(el, dx, dy); - } else { - iwfX(el, iwfX(el) + dx); - iwfY(el, iwfY(el) + dy); + + var newX = evt.X - el.iwfDragOffsetX; + if (newX > iwfClientWidth() - iwfWidth(el)){ + newX = iwfClientWidth() - iwfWidth(el); + } + if (newX < 0) { + newX = 0; + } + + var newY = evt.Y - el.iwfDragOffsetY; + if (newY > iwfClientHeight() - iwfHeight(el)){ + newY = iwfClientHeight() - iwfHeight(el); + } + if (newY < 0) { + newY = 0; } + + + iwfX(el, newX); + iwfY(el, newY); + + // and hilite any drop targets... + for(var i=0;i 0) { + // targets exist, but none were dropped on. return to original x/y + iwfMoveTo(tgt, iwfAttribute(iwfDragger.el, 'iwfDragOrigX'), iwfAttribute(iwfDragger.el, 'iwfDragOrigY'), 30); + } + } else { + // target found. dock to it. + iwfDockTo(tgt, src, "tl", "tl", 30); + } + } +} + +function iwfMapDropTargets(node) { + + if (!node || !node.childNodes) { +iwfLog('No childNodes found for ' + iwfElementToString(node), true); + return; + } + + for(var i=0; i