/////////////////////////////////////////////
// Javascript library, for "Adventuring" //
// Currently Version 2.1 //
// //
// Gump system, in javascript. //
// //
// - some files are external //
// progressbars.js //
// //
/////////////////////////////////////////////
////////////////
// Changelog //
////////////////
// (most recent)
// Promoted options panel (opacity sliders) to main library.
// Speedup code is all in, and working - though it doesn't make things seem any better
// Made a big chunk of the speedup code (panelevent.js)
// Remove 'loading' background onLoad and put it back on fail to load
// Fixed bug 103
// Fixed bug 108
// findposx / findposy (from quirksmode.org)
// Added options panel test
// Added sliders control
// Fixed bug 112
// V2.1 checkpointed
// Opacity can be varied at runtime (see bug 112 though)
// Fixed bug 105
// Changed scrolling to use new event model (see bug 101 though)
// Event logging (See bugs 108 and 109 though)
// Fixed bug 102
// Addition of logging messages, as well as Debug
// Support for opacity of panels (on mouse over)
// Support for panels created by javascript as long as it's done before the document.onLoad event (see bug 110)
// Support for creations of progress bars (same restriction) (same bug)
// Proper time ticks (unlimited number of timers)
// Organised document into sections. Progress bars split out into own file. (ongoing, see bug 106)
// V2 released
// Panels, all main functionality there
// Progress bars - don't yet show percentage
// V1 Released
// (started keeping a changelog)
// Known Outstanding Bugs
// 101 When you resize a scrolling panel, the position moves quite a lot - and unpredictably.
// 106 Should split out bits of this file for different classes of things, rather than having one monolithic file
// 109 Event module bug: If an event wraps round time and ends up at T=0, then it will be terminated
// ... and due to the round numbers involved, this will happen EVERY time period.
// 110 Really ought to allow dynamic creation, using the DOM or otherwise
// 113 Need a way to notify back to user app when a scroll completes.
// 116 TODO: 'only-one' event (eg. redraw) a second event of the same time doens't add a new slot if one already exists
// 117 Performance is terrible... Improve, urgently.
// 118 TODO: Find a way to constrain things into a smaller window. (An IFRAME perhaps?)
// Old bugs (in case of regression, smash head into desk)
// 102 FIXED No need to use innerHTML for img - simply replace with 'loading' image and THEN replace with target image (Works better that way, anyway)
// 105 FIXED Minimise then drag out should unhide the content (now does so)
// 111 WORKAROUND Make translucency a switchable option rather than always happening (setting CFG_Panel_MinOpacity and CFG_Panel_MaxOpacity to the same value will do this)
// 114 FIXED IE Bug - the image panel starts up too small (set 'overflow=hidden')
// 115 WORKAROUND IE Bug, box model - the outer div needs sizing up a few pixels in each direction (see 114)
// 108 FIXED Event module bug: I have seen an erroneous event in the queue - no notify, but a timeslot set. (was a real logic bug. Fixed it in Event_Tick.)
// 103 FIXED Add "+substyle+" to button src attributes (for skinning)? (easily enough acheived)
// 112 FIXED No way to make global opacity changes take effect straight away (in general - no global list of panels) (added such a list)
// And stuff I'm not going to do
// 104 POSTPONED Consider using +skin+ as well/instead? (forget about it - substyle is sufficient)
// 107 POSTPONED Add different Various debugging levels / debug per module? (Don't think I actually need this, now I have logging as well as alerts)
///////////////////////////
// Functionality control //
///////////////////////////
var DISABLE_PANEL_STRETCHING = false;
var DISABLE_PANEL_MOVING = false;
var DISABLE_PANEL_OPACITY = false;
var DISABLE_PANELEVENT = true; // PanelEvent collapses redraw type event down.
var DISABLE_PROGRESS_BARS = false;
var DISABLE_CONTROL_SLIDERS = false;
var DEBUGGING_ENABLED = false;
var LOGGING_ENABLED = true;
var CFG_LOGGING_Logfile = 'logfile';
var CFG_LOGGING_EVENTS = false;
var CFG_Panel_MinOpacity = 0.4; // Gump opacity - probably set via options panel
var CFG_Panel_MaxOpacity = 1;
var CFG_Panel_LoadingImageURL = "Loading.gif"; // The default 'I have no image' image.
var CFG_Panel_MinStretchWidth = 0; // When resizing a panel, stop it getting too small to be able to see the title.
var CFG_Panel_MinStretchHeight = 0;
var CFG_Event_MaxTime = 2* 24 * 60 * 60 * 1000; // 2 days
var CFG_Event_Interval = 100; // TODO: Is 5fps reasonable?
var CFG_Progress_TickSize = 2; // How far to move each frame
/////////////////
// Real Core //
/////////////////
// These are used to track WHICH action is in progress - since we now use a single event handler
// and dispatch to the different routines.
var Panel_CurrentAction = "None";
var Panel_CurrentTarget = null;
// This should be attached to document.onMouseMove
function Panel_MouseMove(evt)
{
// Note that target is not actually used.
if ( Panel_CurrentAction == "Moving" )
Panel_ToMoveWhilstMoving(evt,Panel_CurrentTarget);
else if ( Panel_CurrentAction == "Sizing" )
Panel_ToMoveWhilstResizing(evt,Panel_CurrentTarget);
// else undefined (maybe no) motion - do NOTHING
}
// This should be attached to document.onClick
function Panel_MouseClick(evt)
{
Panel_UnlockButtons();
}
// You should probably call this in the onLoad of the document
tag
function CORE_Init()
{
Event_Init();
}
function findPosX(obj)
{
var curleft = 0;
if(obj.offsetParent)
while(1)
{
curleft += obj.offsetLeft;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
else if(obj.x)
curleft += obj.x;
return curleft;
}
function findPosY(obj)
{
var curtop = 0;
if(obj.offsetParent)
while(1)
{
curtop += obj.offsetTop;
if(!obj.offsetParent)
break;
obj = obj.offsetParent;
}
else if(obj.y)
curtop += obj.y;
return curtop;
}
////////////////////
// Event Handling //
////////////////////
var Event_Initialised = false; // Has the Event module been init'd?
var Event_Interval; // This is the actual javascript setInterval
var Event_Time = 0; // The currnet time (in ms)
var Event_Notification = null; // The function array
var Event_TimeSlot = null; // the time array
var Event_Recur = null; // the 'when does this notification happen again' array
var Event_Alive = true; // Set this false to turn off events but KEEP TICKING.
// (ie. events are cleared without activating)
var Event_ThisEvent = 0; // Functions being called on a tick may need to know which event they are (for example, in order to delete themselves)
// These functions are for convenience, to be as much like javascript set functions as possible
function Event_setInterval( notify, delay )
{
return Event_Add ( notify, delay, delay );
}
// These functions are for convenience, to be as much like javascript set functions as possible
function Event_setTimeout( notify, delay )
{
return Event_Add ( notify, delay, false );
}
function Event_FindEmpty ()
{
var i = 0;
if ( !Event_TimeSlot )
return 0;
while ( Event_TimeSlot[i] && Event_TimeSlot[i] > 0 )
i++;
return i;
}
function Event_Init()
{
// Note: Whilst the 'better' event handler is running,
// setInterval must NOT be used.
Event_Time = 0;
Event_Notification = new Array();
Event_TimeSlot = new Array();
Event_Recur = new Array();
Event_Initialised = true;
Event_Resume();
}
// NOTE: This function can create notifications which examine their arguments immediately upon creation
// or when they are actually run (USE GLOBALS!)
// The formats are:
// Event_Add ( "Function(argument);", ... ) -- this will evaluate its argument only when the tick times out
// Event_Add ( "Function(" + argument + ");", ... ) -- and this will evaluate it immediately
function Event_Add ( call, delay, recurring )
{
if ( !delay ) delay = 0;
if ( !recurring ) recrring = 0;
if ( !Event_Initialised )
Event_Init();
// Debug ( "Event_Add ( call=\""+call+"\", delay="+delay+", recurring="+recurring+" )");
// This uses the more impressive syntax - so you can call it with any chunk of javascript
// rather than just being able to call functions with no arguments.
var freeslot = Event_FindEmpty();
Event_Notification[freeslot] = call;
if ( recurring )
Event_Recur[freeslot] = recurring;
else
Event_Recur[freeslot] = 0;
Event_TimeSlot[freeslot] = (delay + Event_Time) % CFG_Event_MaxTime;
return freeslot;
}
function Event_Quit()
{
Event_Pause();
if ( Event_TimeSlot )
delete Event_TimeSlot;
if ( Event_Recur )
delete Event_TimeSlot;
if ( Event_Notification )
delete Event_Notification;
}
function Event_DeleteSelf()
{
Event_Delete( Event_ThisEvent );
}
function Event_Delete( id )
{
if ( !Event_TimeSlot || !Event_Recur || !Event_Notification )
return;
Event_TimeSlot[id] = 0;
Event_Recur[id] = 0;
Event_Notification[id] = ";";
}
function Event_Alert(text)
{
// This function is required since tick events tend to stack up whilst
// a user notification is acive.
Event_Pause();
alert(text);
Event_Resume();
}
function Event_Tick()
{
Event_Time = ( parseInt ( Event_Time ) + CFG_Event_Interval) % CFG_Event_MaxTime;
if ( !Event_Alive || !Event_TimeSlot || !Event_Recur || !Event_Notification )
return;
for ( i in Event_TimeSlot )
{
if ( Event_TimeSlot[i] < parseInt( Event_Time ) && Event_TimeSlot[i] > 0 && Event_Notification[i]!=null )
{
if ( Event_Recur[i] > 0 )
{
Event_TimeSlot[i] = (Event_Time + Event_Recur[i]) % CFG_Event_MaxTime;
// Note that bad BAD things happen if the thing being eval'd lasts long enough that another tick goes off...
Event_ThisEvent = i;
if ( CFG_LOGGING_EVENTS ) AppendLog ( "Time: "+Event_Time+" Event: "+Event_Notification[i]+"
" );
eval ( Event_Notification[i] );
}
else
{
Event_TimeSlot[i] = 0;
Event_ThisEvent = i;
var func = Event_Notification[i]; // Fix for bug 108 - you have to clear it here before you execute it.
Event_Notification[i] = null;
eval ( func );
}
}
}
}
function Event_Resume()
{
Event_Interval = setInterval ( "Event_Tick();", CFG_Event_Interval );
}
function Event_Pause()
{
clearInterval(Event_Interval); // Not that there's more than one actual interval allowed.
}
// This prints out a debug message (or doesn't if debug is turned off above)
function Debug(text)
{
// DEBUGGING_ENABLED = true;
if ( DEBUGGING_ENABLED == true )
{
Event_Alert(text);
}
}
// This logs debug to the page.
function AppendLog ( text )
{
if ( LOGGING_ENABLED == true )
{
var logfile = FindElementById ( CFG_LOGGING_Logfile );
if ( logfile )
{
logfile.innerHTML = "" + text + "
" + logfile.innerHTML;
}
else
Debug ( text );
}
}
// And this creates a log panel
function DEBUG_CreateLogFile(x,y)
{
if ( LOGGING_ENABLED == true )
{
Panel_StaticCreate ( "holds_the_logfile", x, y, 300, 150, true, true, true, true, true, "", "LOG", "Log begins here.
Dump Events | KILL EVENTS", false );
// Let the log start minimised
Div_Resize("holds_the_logfile_content",null,'1px');
Div_SetVisibility("holds_the_logfile_content", 'hidden');
}
}
////////////////////////
// Browser Detection //
////////////////////////
// TODO: Expand this to a more complete version
var BROWSER_DETECTION__IS_IE = 0;
if ( navigator.appName.indexOf('Microsoft Internet Explorer') != -1)
BROWSER_DETECTION__IS_IE = 1;
/////////////////////////
// Panel Functionality //
/////////////////////////
var Panel_FrontIndex = 100; // When bringing to front, how FAR do you need to bring it?
// This is used to prevent more than one layer responding to a button click
// any click handler should set this, and the body should clear it
var Panel_ButtonInFrontClicked = false;
// This marks that a window drag/resize is in action, and holds offsets used to continue it correctly
var Panel_OffsetX = 0;
var Panel_OffsetY = 0;
// This is the object (NOT THE ID) that is being affectd (as above)
// Panel_ObjMoveOrStretchY!=null is used to test whether an action is in progress or not.
var Panel_ObjMoveOrStretchY = null;
var Panel_ObjStretchX = null; // Drag is used, ,whilst stretching, for height
// but because of panel layout, we need a second object for width
// and stretch is used for that.
// And that's STILL not enough - if a click handler sets the document.onclick then that MAY
// immediately fire (putting the thing you picked up, back down) - to cope, set this Panel_Debounce
// and check it in any document onclick handler.
var Panel_Debounce = false;
var Panel_List = new Array();
function Panel_Add(id)
{
AppendLog ( "Panel_Add("+id+");" );
Panel_List[Panel_List.length] = id;
}
function Panel_Remove(id)
{
for ( i in Panel_List )
{
if ( Panel_List[i] == id )
{
Panel_List.splice(i, 1 );
}
}
}
function Panel_SetAllOpacity ( level )
{
for ( i in Panel_List )
{
var target = Panel_List[i];
Div_SetOpacity ( target, level );
}
}
function Panel_Display( target, hide )
{
var text = "inherit";
if ( hide )
{
text = "hidden";
}
Div_SetVisibility( target, text );
}
function Panel_Resize ( target, w, h )
{
Div_Resize ( target, w, null );
Div_Resize ( target+"_content", null, h );
}
function Panel_Move ( target, x, y )
{
Div_Move ( target, x, y );
}
function Panel_StartStopDrag(evt,idToMove)
{
if ( DISABLE_PANEL_MOVING != false )
return;
Debug("Panel_StartStopDrag(evt=" + evt + "idToMove=" + idToMove + ") : BIFC=" + Panel_ButtonInFrontClicked );
if (Panel_ButtonInFrontClicked)
{
// Handled by the button already - next press might go anywhere
}
else
{
Div_MoveToFront(idToMove);
Panel_ButtonInFrontClicked = true;
// Ok - we've been picked up, or put down
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_StopDraggingPanel();
}
else
{
Debug("Grabbing");
// Not up, so pick it up.
Panel_ObjMoveOrStretchY = FindElementById(idToMove);
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_CurrentAction = "Moving";
Panel_CurrentTarget = idToMove;
if ( !DISABLE_PANELEVENT )
{
PanelEvent_Attach();
}
// TODO: Might it be worth catching the escape kay, as well?
else
document.onclick = Panel_StopDraggingPanel;
// AppendLog ( "Mouse at " + evt.clientX + "," + evt.clientY );
// AppendLog ( "Bar at " + Panel_ObjMoveOrStretchY.style.left + "," + Panel_ObjMoveOrStretchY.style.top );
// Ok - a problem remains. We're setting positions as 160px
// and then we want to treat it as a number. parseInt fixes this.
Panel_OffsetX = evt.clientX - parseInt(Panel_ObjMoveOrStretchY.style.left);
Panel_OffsetY = evt.clientY - parseInt(Panel_ObjMoveOrStretchY.style.top);
Panel_ObjMoveOrStretchY.style.position = 'absolute'; // Should already be set
Panel_Debounce = true;
// AppendLog("Should now be moving, relative " + Panel_OffsetX + "," + Panel_OffsetY);
}
}
}
}
// Put that panel back down
function Panel_StopDraggingPanel()
{
if ( DISABLE_PANEL_MOVING != false )
return;
if ( Panel_Debounce )
{
Panel_Debounce = false;
return;
}
Debug("Panel_StopDraggingPanel()");
// Were up, put us down - nothing to do, except to stop tracking the mouse.
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_CurrentAction = "None";
Panel_CurrentTarget = null;
if ( !DISABLE_PANELEVENT )
{
PanelEvent_Detach();
}
else
document.onlick = null;
Panel_ObjMoveOrStretchY = null; // Panel_ObjMoveOrStretchY null is used to mark 'no action'
}
}
// Start stretching the panel
// Something a bit funny here - IE will let you downsize the width of the titlebar
// too far - though it caps the whole size. Not sure WHAT is going on.
// But it does keep everything that needs to be within the bar, and caps it to that size
// - so we're probably ok.
// Leaving some leeway (200px instead of 150) seems to make it all ok.
function Panel_StartStretchingPanel(evt, idToSizeHorizontal, idToSizeVertical, minWidth, minHeight )
{
if ( DISABLE_PANEL_STRETCHING != false )
return;
if (Panel_ButtonInFrontClicked)
{
// Handled by the button already - next press might go anywhere
}
else
{
// This fixes a silly: When you hit minimise then stretch it visible again we DO want to be able to see it.
Div_SetVisibility(idToSizeVertical, 'inherit');
Debug ( "Panel_StartStretchingPanel(evt=" + evt + ", idToSizeVertical=" + idToSizeVertical + ", idToSizeHorizontal=" + idToSizeHorizontal + " ) : BIFC=" + Panel_ButtonInFrontClicked );
Div_MoveToFront(idToSizeHorizontal);
Panel_ButtonInFrontClicked = true;
// Ok - we've been picked up, or put down
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_StopStretching();
}
else
{
// Default minimum sizes for panels
if ( minWidth < 1 ) minWidth = 200;
if ( minHeight < 1 ) minHeight = 1;
CFG_Panel_MinStretchWidth = minWidth;
CFG_Panel_MinStretchHeight = minHeight;
Panel_ObjStretchX = FindElementById(idToSizeHorizontal);
if ( Panel_ObjStretchX != null )
{
Panel_CurrentAction = "Sizing";
Panel_CurrentTarget = idToSizeHorizontal;
if ( !DISABLE_PANELEVENT )
{
PanelEvent_Attach();
}
else
{
AppendLog("Doc onclick= stopstretch");
document.onclick = Panel_StopStretching;
}
Debug ( "Horizontal: Mouse at " + evt.clientX + "," + evt.clientY );
Debug ( "Sized " + Panel_ObjStretchX.style.width );
Panel_OffsetX = parseInt(Panel_ObjStretchX.style.width) - evt.clientX;
Panel_Debounce = true;
Debug("Should now be moving, relative " + Panel_OffsetX + "," + Panel_OffsetY);
}
Panel_ObjMoveOrStretchY = FindElementById(idToSizeVertical);
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_CurrentAction = "Sizing";
Panel_CurrentTarget = idToSizeVertical;
Debug ( "Vertical: Mouse at " + evt.clientX + "," + evt.clientY );
Debug ( "Sized " + Panel_ObjMoveOrStretchY.style.height );
Panel_OffsetY = parseInt(Panel_ObjMoveOrStretchY.style.height) - evt.clientY;
Panel_Debounce = true;
// document.onmousemove doesn't seem to WORK for firefox. Argh.
// .. .is it possible that FireFox doesn't allow you to dynamically assign handler? Argh.
if ( !DISABLE_PANELEVENT )
{
PanelEvent_Attach();
}
else
{
AppendLog("Doc onclick= stopstretch");
document.onclick = Panel_StopStretching;
}
// TODO: It might be worth having 'escape' put down the bar too?
Debug("Should now be moving, relative " + Panel_OffsetX + "," + Panel_OffsetY);
}
}
}
}
// Stop the resize
function Panel_StopStretching()
{
//AppendLog("Stop stretch");
if ( DISABLE_PANEL_STRETCHING != false )
return;
if ( Panel_Debounce )
{
Panel_Debounce = false;
return;
}
Debug ( "Panel_StopStretching()" );
// Were up, put us down - nothing to do, except to stop trakcing the mouse.
if ( Panel_ObjMoveOrStretchY != null )
{
Panel_CurrentAction = "None";
Panel_CurrentTarget = null;
if ( !DISABLE_PANELEVENT )
{
PanelEvent_Detach();
}
document.onclick = null;
Panel_ObjMoveOrStretchY = null; // This marks 'no activity'
Panel_ObjStretchX = null;
}
}
// Actually do the resize (called on document.onmousemove)
function Panel_ToMoveWhilstResizing(evt,target,x,y)
{
if ( !x && !y )
{
x = evt.clientX;
y = evt.clientY;
}
// NOTE THAT TARGET IS NOT USED
// This is kinda important, since (up to) two targets exist for a resize.
if ( DISABLE_PANEL_STRETCHING != false )
return;
// Be VERY sure you want to turn on full debug, and print out on every tick
// Debug ( "Resize to " + x + ", " + y + " from " + Panel_OffsetX + ", " + Panel_OffsetY );
if ( evt != null && Panel_ObjMoveOrStretchY != null )
{
var size = y + Panel_OffsetY;
// Check we're not trying to go negative
// (Throws an exception, and in IE causes us to go 100%)
if ( size < CFG_Panel_MinStretchHeight ) size = CFG_Panel_MinStretchHeight;
Panel_ObjMoveOrStretchY.style.height = size;
}
if ( evt != null && Panel_ObjStretchX != null )
{
var size = x + Panel_OffsetX;
if ( size < CFG_Panel_MinStretchWidth ) size = CFG_Panel_MinStretchWidth;
Panel_ObjStretchX.style.width = size;
}
}
function Panel_ToMoveWhilstMoving(evt, target,x,y)
{
if ( !x && !y )
{
x = evt.clientX;
y = evt.clientY;
}
// Note that target is not actually used.
if ( DISABLE_PANEL_MOVING != false )
return;
// alert ( "Panel_ToMoveWhilstMoving(evt="+evt+")" );
// Firefox problem - IE uses 'event' to represent the thing that fires the event
// (i.e. the mouse) - but this doesn't WORK in firefox.
if ( evt != null && Panel_ObjMoveOrStretchY != null)
{
// Be REALLY sure that you want to print out on EVERY tick!
// Debug( x + "," + y + " from " + Panel_OffsetX + "," + Panel_OffsetY );
Panel_ObjMoveOrStretchY.style.left = x - Panel_OffsetX;
Panel_ObjMoveOrStretchY.style.top = y - Panel_OffsetY;
}
}
// If you don't want any layers behind you to handle a click (ie. you've handled it, or you're
// something like a text pane that wants to stop everything) then call this
function Panel_BlockButtons()
{
Panel_ButtonInFrontClicked = true;
}
function Panel_UnlockButtons()
{
Debug ( "UnlockButtons()" );
Panel_ButtonInFrontClicked = false;
}
function Panel_BringUp ( target )
{
Div_MoveToFront ( target );
}
function Panel_Maximise ( panel_name )
{
Debug ( "Panel_Maximise( panel_name="+panel_name+" )" );
Div_Resize( panel_name+"_content" ,null, "100%");
Div_SetVisibility(panel_name+"_content", "inherit");
}
function Panel_SetTitle ( panel_name, title )
{
var target = panel_name + "_title";
var obj = FindElementById ( target );
if ( obj )
{
obj.innerHTML = title;
}
}
function Panel_StaticCreate( panel_name, x, y, w, h, allow_close, allow_max, allow_min, allow_move, allow_resize, substyle, title, content, suppress_output, stay_small )
{
var output = "";
// NOTE: This function is almost certain not to work if invoked after the documents onLoad method
// In fact, in both firefox and IE it takes you to a page consisting SOLELY of that panel (with no css or anything)
// TODO: Really ought to create using the DOM. Maybe try that next
Debug( "Panel_StaticCreate( panel_name="+panel_name+", x="+x+", y="+y+", w="+w+", h="+h+", a_c="+allow_close+", a_m="+allow_max+", a_i="+allow_min+", a_v="+allow_move+", a_r="+allow_resize+", substyle="+substyle+", title="+title+", content )" );
// Outermost level of panel - and resize
output += ( "\n" );
// Title bar - and movement
output += ( "
\n");
// Actual title
output += ( "
" );
output += ( title );
output += ( "
\n" );
// Button 1 - close
if ( allow_close )
{
output += ( "
\n" );
}
if ( allow_max )
{
output += ( "
\n" );
}
if ( allow_min )
{
output += ( "
\n" );
}
// Close the title bar
output += ( "
" );
// Body
output += ( "
" );
// Content
output += ( "
\n" );
output +=( content );
output += ( "\n
\n");
// And close everything - content, then body then panel
output += ( "
\n");
output += ( "
\n");
// alert ( output );
if ( !suppress_output )
{
Debug ( "Actually printing" );
document.writeln ( output );
Panel_Resize ( panel_name, w, h );
Panel_Move ( panel_name, x, y );
if ( !stay_small )
Panel_Maximise ( panel_name );
}
// Record the panels creation (for later targetting)
Panel_Add ( panel_name );
return output;
}
function Panel_CreateImagePanel( id, title, substyle, x, y, w, h, url )
{
var content = "\n";
content += "
\n";
content += "
\n";
content += "
\n";
content += "
\n";
content += "
\n";
Panel_StaticCreate( id, x, y, w, h, true, false, false, true, true, "_img"+substyle, title, content, false, false );
// Remove the scrollbars (Bug 114, 115)
var obj = FindElementById( id+"_content");
if ( obj )
{
obj.style.overflow = "hidden";
obj.style.height = h;
}
}
function Panel_ClearBackground()
{
// COULD get it via DOM - it's a sibling of the parent.
var target = this.id.replace(/_img/ ,"_loading");
Panel_SetDivBackground ( target, null );
this.onload = null;
}
function Panel_SetDivBackground( target, value )
{
Debug ( "Panel_SetDivBackground( target="+target+", value="+value+" )" );
var obj = FindElementById(target);
if ( obj != null )
{
obj.style.background = value;
}
}
function Panel_KeepBackground()
{
var target = this.id.replace(/_img/ ,"_loading");
// COULD get it via DOM - it's a sibling of the parent.
var val = "url(" + CFG_Panel_LoadingImageURL+")";
Panel_SetDivBackground ( target, val );
this.onload = null;
this.onerror = null;
}
function Panel_SetImagePanel ( id, title, url, w, h, resize, stretch )
{
var obj = FindElementById ( id + "_img" );
var bgobj = FindElementById ( id + "_loading" );
if ( obj )
{
// Load in the 'no image' image - so that if loading in the real image fails, at least we see something change
// (And NOT The old image just staying there)
obj.src = CFG_Panel_LoadingImageURL;
if ( bgobj != null ) bgobj.style.background = "url("+CFG_Panel_LoadingImageURL+")";
if ( !w )
obj.width = "100%";
else
obj.width = w;
if ( !h )
obj.height = "100%";
else
obj.height = h;
// Prepare to remove the 'loading' background
obj.onerror = Panel_KeepBackground;
obj.onload = Panel_ClearBackground;
// And load in the real image
obj.src = url;
}
if ( resize )
{
Panel_Resize ( id, w, h );
obj = FindElementById ( id + "_loading" );
if ( obj )
{
obj.style.width = w;
obj.style.height = h;
}
}
if ( title )
{
Panel_SetTitle ( id, title );
}
}
////////////////////////////////////////////////////////////
// DIV functions
// These should work on any object in the DOM with an id //
// But they're mainly intended for panels. //
////////////////////////////////////////////////////////////
// Quicky function to check whether an id has a corresponding object, and that object is visible
// (due to being explicitly visible, or inheriting visibility from a container)
// NOTE: IE (perhaps wrongly?) says that a visible object inside a hidden container is visible!
function Div_IsVisible( idToCheck )
{
var objToCheck = FindElementById(idToCheck);
var rval = false;
// Should, ideally, check parents if inherit...
while ( objToCheck != null )
{
if ( objToCheck.style.visibility == 'hidden' || objToCheck.style.visibility == 'hide' )
{
rval = false;
objToCheck = null;
}
else if ( objToCheck.style.visibility == 'visible' || objToCheck.style.visibility == 'show' )
{
rval = true;
objToCheck = null;
}
else
{
objToCheck = objToCheck.parentNode;
}
}
return rval;
}
// This shows, or hides, an object
function Div_SetVisibility(idToHide, show)
{
Debug( "Div_SetVisibility(idToHide=" + idToHide + ", show=" + show + ")");
var objToHide = FindElementById(idToHide);
if ( objToHide != null )
{
var parent = objToHide.parentNode;
if ( parent != null && parent.style.visibility == 'hidden' )
{
Debug ( "Parent hidden, not altering child (breaks relations)");
}
else
{
objToHide.style.visibility = show;
}
}
else
{
Debug ( "No such object " + idToHide + "?" )
}
}
function Div_SetOpacity( target, level )
{
if ( DISABLE_PANEL_OPACITY != false )
return;
Debug ( "Div_SetOpacity( target="+target+", level="+level+" )" );
var obj = FindElementById ( target );
if ( obj && obj.style )
{
obj.style.opacity = level;
// And for IE...
obj.style.filter = 'alpha(opacity=' + (level *100)+ ')';
Debug ( ""+target+".style.opacity:" + obj.style.opacity + " IE gets "+target+".style.filter:" + obj.style.filter );
}
else
Debug ( "No such object" );
}
function Div_SetBackground(target,color)
{
Debug( "Div_SetBackground(target="+target+",color="+color+")" );
var obj = FindElementById(target);
if ( obj && obj.style )
obj.style.background=color;
}
function Div_Move ( target, x, y )
{
var obj = FindElementById ( target );
if ( obj )
{
obj.style.left = x;
obj.style.top = y;
}
}
// Resize an object
function Div_Resize(idToSize, x, y )
{
Debug("Div_Resize( id=" + idToSize + ", x=" + x + ", y=" + y + " );" );
objToSize = FindElementById(idToSize);
if ( objToSize != null )
{
if ( x != null )
{
Debug ( "setting " + idToSize + ".width = " + x );
objToSize.style.width = x;
}
if ( y != null )
{
Debug ( "setting " + idToSize + ".height = " + y );
objToSize.style.height = y;
}
}
else
{
Debug ( "No such object" + idToSize + "?" );
}
}
function Div_MoveToFront( target )
{
obj = FindElementById(target)
if ( obj != null )
{
Panel_FrontIndex = Panel_FrontIndex + 1;
obj.style.zIndex = Panel_FrontIndex;
}
}
function Div_Scroll (target, dx, x_units, dy, y_units, loop, reset)
{
var notify = null;
var obj = FindElementById(target);
if ( obj )
{
if ( reset )
{
obj.style.top = 0;
obj.style.left = 0;
}
var arguments = "\'"+target+"\', "+dx+", \'"+x_units+"\', "+dy+", \'"+y_units+"\'";
if ( loop )
{
notify = "\"Div_Scroll("+arguments+",true,true);\"";
}
Event_Add ( "Div_ScrollTick ( "+arguments+","+notify+" );", CFG_Event_Interval, CFG_Event_Interval );
}
}
function Div_ScrollTick ( target, dx, x_units, dy, y_units, localNotifyScrollingComplete )
{
Debug ( "MoveDown( target=" + target + ", dx="+dx+", x_units="+x_units+", dy="+dy+", y_units="+y_units+" )" );
var obj = FindElementById(target);
if ( obj != null )
{
if ( dx )
{
var pos = 0;
if ( obj.style && obj.style.left )
{
pos = parseInt ( obj.style.left );
}
pos = pos + dx;
pos = pos + x_units;
if ( pos < - obj.offsetWidth )
{
Event_Delete(this);
if ( localNotifyScrollingComplete )
{
AppendLog ( "Ending scroll of "+target+" due to x-pos");
Event_Add( localNotifyScrollingComplete, 1 );
}
}
obj.style.left = pos;
}
if ( dy )
{
var pos = 0;
if ( obj.style && obj.style.top )
{
pos = parseInt ( obj.style.top );
}
pos = pos + dy;
pos = pos + y_units;
if ( (0-parseInt(pos)) > parseInt(obj.offsetHeight) )
{
Event_Delete(this);
if ( localNotifyScrollingComplete )
{
AppendLog ( "Ending scroll of "+target+" due to y-pos");
Event_Add( localNotifyScrollingComplete, 1 );
}
}
obj.style.top = pos;
}
}
}
/////////////////////////
// Progress Bars //
/////////////////////////
// These are now included in "progressbar.js" since few files need them.
/////////////////////
// Alerts //
/////////////////////
function BlinkOn(target, style, offset)
{
if ( style == null )
style = "3px double #ff9933";
var obj = FindElementById(target);
if ( obj != null )
{
obj.style.border = style;
// Flashing the opacity - I'm not sure whether or not I like this effect
// obj.style.opacity = .3;
// Offset is used because the box model is STUPID and targetsthe corner outside the border as the top/left
if ( offset && obj.style && obj.style.top && obj.style.left )
{
obj.style.top = parseInt(obj.style.top) - offset;
obj.style.left = parseInt(obj.style.left) - offset;
// TODO: IE needs you to increment the width as well, but that's a box-model bug - so I'm not fixing it.
}
}
}
function BlinkOff(target,offset)
{
// Debug("BlinkOff(target="+target+")" );
var obj = FindElementById(target);
if ( obj != null )
{
obj.style.border = "0px none #000000";
// obj.style.opacity = 1;
if ( obj.style && obj.style.top && obj.style.left )
{
obj.style.top = parseInt(obj.style.top ) + offset;
obj.style.left = parseInt(obj.style.left) + offset;
}
}
}
// NOTE: There is nothing (at this level) stopping you from setting a panel
// from flshing multiple times, possibly with different styles or offsets.
// This will look very very strange - but should settle itself out in the end.
// NOTE: Offsets will end up culmulative!
function StartBlinking(target,style,offset,onTime,offTime,numBlinks)
{
BlinkOn ( target, style, offset);
Event_Add ( "BlinkOff( \""+target+"\","+offset+" );", offTime, false );
if ( numBlinks > 1 )
{
numBlinks = parseInt(numBlinks) - 1;
if ( style != null )
style = "\""+style+"\"";
var n = "StartBlinking(\""+target+"\","+style+","+offset+","+onTime+","+offTime+","+numBlinks+");";
// alert ( n );
Event_Add( n, onTime + offTime, false);
}
}
/////////////////////
// Controls //
/////////////////////
/////////////////////
// Slider //
/////////////////////
function Control_Slider_StaticCreate( SliderName, title, tleft, tright, substyle, w, value, notify, suppress )
{
if ( DISABLE_CONTROL_SLIDERS != false )
return null;
var output = "";
output += "\n";
output += "
\n";
output += title;
output += "\n
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += "
\n";
output += tleft;
output += "\n
\n";
output += "
\n";
output += tright;
output += "\n
\n
\n";
//alert ( output );
if ( !suppress )
document.write ( output );
return output;
}
function Control_Slider_DoClick(evt, slider, notify)
{
if ( DISABLE_CONTROL_SLIDERS != false )
return;
var slide = slider + "_SliderTick";
var sobj = FindElementById(slide);
var back = slider + "_SliderBackground";
var bobj = FindElementById(back);
var text = slider + "_Value";
var tobj = FindElementById( text );
if ( !tobj || !sobj || !bobj )
return;
var left = evt.clientX - findPosX(bobj);
sobj.style.left = left;
var pos = ( left * 100 ) / bobj.clientWidth
tobj.value = parseInt(pos);
Event_Add ( notify, 1, false );
}
function Control_Slider_ChangeValue(event, slider, notify)
{
if ( DISABLE_CONTROL_SLIDERS != false )
return;
var slide = slider + "_SliderTick";
var sobj = FindElementById(slide);
var back = slider + "_SliderBackground";
var bobj = FindElementById(back);
var text = slider + "_Value";
var tobj = FindElementById( text );
if ( !tobj || !sobj || !bobj )
return;
var pos = parseInt(tobj.value);
tobj.value = pos;
var left = ( bobj.clientWidth * pos ) / 100;
sobj.style.left = left;
Event_Add ( notify, 1, false );
}
////////////////////////////////
// Options panel
////////////////////////////////
function OPTION_SetPassiveTrans()
{
var text = "slider_passivetrans_Value";
var tobj = FindElementById( text );
if ( tobj )
{
var pos = parseInt(tobj.value);
Debug( "slider_passive set to " + pos );
CFG_Panel_MinOpacity = pos / 100;
Panel_SetAllOpacity ( CFG_Panel_MinOpacity );
Div_SetOpacity ( PanelEvent_ActivePanel, CFG_Panel_MaxOpacity );
}
}
function OPTION_SetActiveTrans()
{
var text = "slider_activetrans_Value";
var tobj = FindElementById( text );
if ( tobj )
{
var pos = parseInt(tobj.value);
if ( pos < 20 )
{
pos = 20;
tobj.value = 20;
}
Debug ( "slider_activetrans set to " + pos );
CFG_Panel_MaxOpacity = pos / 100;
Div_SetOpacity ( PanelEvent_ActivePanel, CFG_Panel_MaxOpacity );
}
}
function OPTION_CreateStaticOptionsPanel( id, title, substyle, x, y, w, h, suppress_creation )
{
var slider_min = ""; var slider_max="";
if ( DISABLE_CONTROL_SLIDERS == false )
slider_min = Control_Slider_StaticCreate( "slider_passivetrans", "Inactive Panel Transparency", "", "", "", "95%", 40, "OPTION_SetPassiveTrans();", true );
if ( DISABLE_CONTROL_SLIDERS == false )
slider_max = Control_Slider_StaticCreate( "slider_activetrans", "Active Panel Transparency", "Fully Transparent (0)", "Fully Opaque (100)", "", "95%", 100, "OPTION_SetActiveTrans();", true );
var output = Panel_StaticCreate( id, x, y, w, h, true, true, true, true, true, substyle, title, slider_min+slider_max, suppress_creation, false );
OPTION_SetActiveTrans();
OPTION_SetPassiveTrans();
return output;
}
// This will get an outer element, if possible
function GetOuterElementById(target)
{
var outer;
if ( parent ) outer = parent.document;
if ( !outer ) outer = document;
return outer.getElementById ( target );
}
// This will get an inner element - or look for it in the outer, if none exists
// (You can use this globally - though it doubles the time taken finding objects)
function FindElementById(target)
{
var obj = document.getElementById ( target );
if ( !obj && parent && parent.document ) obj = parent.document.getElementById ( target );
return obj;
}