includes/clientside/static/messagebox.js
changeset 582 a38876c0793c
child 628 ab6f55abb17e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/static/messagebox.js	Tue Jun 24 23:37:23 2008 -0400
@@ -0,0 +1,586 @@
+// Message box and visual effect system
+
+/**
+ * The ultimate message box framework for Javascript
+ * Syntax is (almost) identical to the MessageBox command in NSIS
+ * @param int type - a bitfield consisting of the MB_* constants
+ * @param string title - the blue text at the top of the window
+ * @param string text - HTML for the body of the message box
+ * Properties:
+ *   onclick - an array of functions to be called on button click events
+ *             NOTE: key names are to be strings, and they must be the value of the input, CaSe-SeNsItIvE
+ *   onbeforeclick - same as onclick but called before the messagebox div is destroyed
+ * Methods:
+ *   destroy: kills the running message box
+ * Example:
+ *   var my_message = new MessageBox(MB_OK|MB_ICONSTOP, 'Error logging in', 'The username and/or password is incorrect. Please check the username and retype your password');
+ *   my_message.onclick['OK'] = function() {
+ *       document.getElementById('password').value = '';
+ *     };
+ * Deps:
+ *   Modern browser that supports DOM
+ *   darken() and enlighten() (above)
+ *   opacity() - required for darken() and enlighten()
+ *   MB_* constants are defined in enano-lib-basic.js
+ */
+
+var mb_current_obj;
+var mb_previously_had_darkener = false;
+
+function MessageBox(type, title, message)
+{
+  if ( !aclDisableTransitionFX )
+  {
+    load_component('flyin');
+  }
+  
+  var y = getScrollOffset();
+  
+  // Prevent multiple instances
+  if ( document.getElementById('messageBox') )
+    return;
+  
+  if ( document.getElementById('specialLayer_darkener') )
+    if ( document.getElementById('specialLayer_darkener').style.display == 'block' )
+      mb_previously_had_darkener = true;
+  if ( !mb_previously_had_darkener )
+    darken(true);
+  if ( aclDisableTransitionFX )
+  {
+    document.getElementById('specialLayer_darkener').style.zIndex = '5';
+  }
+  var master_div = document.createElement('div');
+  master_div.style.zIndex = String(getHighestZ() + 5);
+  var mydiv = document.createElement('div');
+  mydiv.style.height = '200px';
+  w = getWidth();
+  h = getHeight();
+  if ( aclDisableTransitionFX )
+  {
+    master_div.style.left = ((w / 2) - 200)+'px';
+    master_div.style.top = ((h / 2) + y - 120)+'px';
+    master_div.style.position = 'absolute';
+  }
+  else
+  {
+    master_div.style.top = '-10000px';
+    master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
+  }
+  z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex : getHighestZ();
+  mydiv.style.backgroundColor = '#FFFFFF';
+  mydiv.style.padding = '10px';
+  mydiv.style.marginBottom = '1px';
+  mydiv.id = 'messageBox';
+  mydiv.style.overflow = 'auto';
+  
+  var buttondiv = document.createElement('div');
+  
+  mydiv.style.width = '400px';
+  buttondiv.style.width = '400px';
+  
+  w = getWidth();
+  h = getHeight();
+  if ( aclDisableTransitionFX )
+  {
+    //buttondiv.style.left = ((w / 2) - 200)+'px';
+    //buttondiv.style.top = ((h / 2) + y + 101)+'px';
+  }
+  //buttondiv.style.position = ( IE ) ? 'absolute' : 'fixed';
+  z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex : getHighestZ();
+  buttondiv.style.backgroundColor = '#C0C0C0';
+  buttondiv.style.padding = '10px';
+  buttondiv.style.textAlign = 'right';
+  buttondiv.style.verticalAlign = 'middle';
+  buttondiv.id = 'messageBoxButtons';
+  
+  this.clickHandler = function() { messagebox_click(this, mb_current_obj); };
+  
+  if( ( type & MB_ICONINFORMATION || type & MB_ICONSTOP || type & MB_ICONQUESTION || type & MB_ICONEXCLAMATION ) && !(type & MB_ICONLOCK) )
+  {
+    mydiv.style.paddingLeft = '50px';
+    mydiv.style.width = '360px';
+    mydiv.style.backgroundRepeat = 'no-repeat';
+    mydiv.style.backgroundPosition = '8px 8px';
+  }
+  else if ( type & MB_ICONLOCK )
+  {
+    mydiv.style.paddingLeft = '50px';
+    mydiv.style.width = '360px';
+    mydiv.style.backgroundRepeat = 'no-repeat';
+  }
+  
+  if(type & MB_ICONINFORMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/info.png\')';
+  }
+  
+  if(type & MB_ICONQUESTION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/question.png\')';
+  }
+  
+  if(type & MB_ICONSTOP)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/error.png\')';
+  }
+  
+  if(type & MB_ICONEXCLAMATION)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/warning.png\')';
+  }
+  
+  if(type & MB_ICONLOCK)
+  {
+    mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/lock.png\')';
+  }
+  
+  if(type & MB_OK)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_ok');
+    btn._GenericName = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_OKCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_ok');
+    btn._GenericName = 'OK';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_cancel');
+    btn._GenericName = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNO)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_yes');
+    btn._GenericName = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_no');
+    btn._GenericName = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  if(type & MB_YESNOCANCEL)
+  {
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_yes');
+    btn._GenericName = 'Yes';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_no');
+    btn._GenericName = 'No';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+    
+    btn = document.createElement('input');
+    btn.type = 'button';
+    btn.value = $lang.get('etc_cancel');
+    btn._GenericName = 'Cancel';
+    btn.onclick = this.clickHandler;
+    btn.style.margin = '0 3px';
+    buttondiv.appendChild(btn);
+  }
+  
+  heading = document.createElement('h2');
+  heading.innerHTML = title;
+  heading.style.color = '#50A0D0';
+  heading.style.fontFamily = 'trebuchet ms, verdana, arial, helvetica, sans-serif';
+  heading.style.fontSize = '12pt';
+  heading.style.fontWeight = 'lighter';
+  heading.style.textTransform = 'lowercase';
+  heading.style.marginTop = '0';
+  mydiv.appendChild(heading);
+  
+  var text = document.createElement('div');
+  text.innerHTML = String(message);
+  this.text_area = text;
+  mydiv.appendChild(text);
+  
+  this.updateContent = function(text)
+    {
+      this.text_area.innerHTML = text;
+    };
+    
+  this.destroy = function()
+    {
+      var mbdiv = document.getElementById('messageBox');
+      mbdiv.parentNode.removeChild(mbdiv.nextSibling);
+      mbdiv.parentNode.removeChild(mbdiv);
+      if ( !mb_previously_had_darkener )
+        enlighten(true);
+    };
+  
+  //domObjChangeOpac(0, mydiv);
+  //domObjChangeOpac(0, master_div);
+  
+  body = document.getElementsByTagName('body');
+  body = body[0];
+  master_div.appendChild(mydiv);
+  master_div.appendChild(buttondiv);
+  
+  body.appendChild(master_div);
+  
+  if ( !aclDisableTransitionFX )
+    setTimeout('mb_runFlyIn();', 100);
+  
+  this.onclick = new Array();
+  this.onbeforeclick = new Array();
+  mb_current_obj = this;
+}
+
+var messagebox = MessageBox;
+
+function mb_runFlyIn()
+{
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  fly_in_top(maindiv, true, false);
+}
+
+function messagebox_click(obj, mb)
+{
+  val = ( typeof ( obj._GenericName ) == 'string' ) ? obj._GenericName : obj.value;
+  if(typeof mb.onbeforeclick[val] == 'function')
+  {
+    var o = mb.onbeforeclick[val];
+    var resp = o();
+    if ( resp )
+      return false;
+    o = false;
+  }
+  
+  var mydiv = document.getElementById('messageBox');
+  var maindiv = mydiv.parentNode;
+  
+  if ( aclDisableTransitionFX )
+  {
+    var mbdiv = document.getElementById('messageBox');
+    mbdiv.parentNode.removeChild(mbdiv.nextSibling);
+    mbdiv.parentNode.removeChild(mbdiv);
+    if ( !mb_previously_had_darkener )
+      enlighten(true);
+  }
+  else
+  {
+    var to = fly_out_top(maindiv, true, false);
+    setTimeout("var mbdiv = document.getElementById('messageBox'); mbdiv.parentNode.removeChild(mbdiv.nextSibling); mbdiv.parentNode.removeChild(mbdiv); if ( !mb_previously_had_darkener ) enlighten(true);", to);
+  }
+  if(typeof mb.onclick[val] == 'function')
+  {
+    o = mb.onclick[val];
+    o();
+    o = false;
+  }
+}
+
+function testMessageBox()
+{
+  mb = new MessageBox(MB_OKCANCEL|MB_ICONINFORMATION, 'Javascripted dynamic message boxes', 'This is soooooo coool, now if only document.createElement() worked in IE!<br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text<br /><br /><br /><br /><br />this is some more text');
+  mb.onclick['OK'] = function()
+    {
+      alert('You clicked OK!');
+    }
+  mb.onbeforeclick['Cancel'] = function()
+    {
+      alert('You clicked Cancel!');
+    }
+}
+
+/**
+ * The miniPrompt function, for creating small prompts and dialogs. The window will be flown in and the window darkened with opac=0.4.
+ * @param function Will be passed an HTMLElement that is the body of the prompt window; the function can do with this as it pleases
+ */
+
+function miniPrompt(call_on_create)
+{
+  if ( !aclDisableTransitionFX )
+  {
+    load_component('flyin');
+  }
+  if ( document.getElementById('specialLayer_darkener') )
+  {
+    if ( document.getElementById('specialLayer_darkener').style.display != 'none' )
+    {
+      var opac = parseFloat(document.getElementById('specialLayer_darkener').style.opacity);
+      opac = opac * 100;
+      darken(aclDisableTransitionFX, opac);
+    }
+    else
+    {
+      darken(aclDisableTransitionFX, 40);
+    }
+  }
+  else
+  {
+    darken(aclDisableTransitionFX, 40);
+  }
+  
+  var wrapper = document.createElement('div');
+  wrapper.className = 'miniprompt';
+  var top = document.createElement('div');
+  top.className = 'mp-top';
+  var body = document.createElement('div');
+  body.className = 'mp-body';
+  var bottom = document.createElement('div');
+  bottom.className = 'mp-bottom';
+  if ( typeof(call_on_create) == 'function' )
+  {
+    call_on_create(body);
+  }
+  wrapper.appendChild(top);
+  wrapper.appendChild(body);
+  wrapper.appendChild(bottom);
+  var left = ( getWidth() / 2 ) - ( 388 / 2 );
+  wrapper.style.left = left + 'px';
+  var top = getScrollOffset() - 27;
+  wrapper.style.top = top + 'px';
+  domObjChangeOpac(0, wrapper);
+  var realbody = document.getElementsByTagName('body')[0];
+  realbody.appendChild(wrapper);
+  
+  if ( aclDisableTransitionFX )
+  {
+    domObjChangeOpac(100, wrapper);
+  }
+  else
+  {
+    fly_in_top(wrapper, true, true);
+    
+    setTimeout(function()
+      {
+        domObjChangeOpac(100, wrapper);
+      }, 40);
+  }
+}
+
+/**
+ * For a given element, loops through the element and all of its ancestors looking for a miniPrompt div, and returns it. Returns false on failure.
+ * @param object:HTMLElement Child node to scan
+ * @return object
+ */
+
+function miniPromptGetParent(obj)
+{
+  while ( true )
+  {
+    // prevent infinite loops
+    if ( !obj || obj.tagName == 'BODY' )
+      return false;
+    
+    if ( $dynano(obj).hasClass('miniprompt') )
+    {
+      return obj;
+    }
+    obj = obj.parentNode;
+  }
+  return false;
+}
+
+/**
+ * Destroys the first miniPrompt div encountered by recursively checking all parent nodes.
+ * Usage: <a href="javascript:miniPromptDestroy(this);">click</a>
+ * @param object:HTMLElement a child of the div.miniprompt
+ * @param bool If true, does not call enlighten().
+ */
+
+function miniPromptDestroy(obj, nofade)
+{
+  obj = miniPromptGetParent(obj);
+  if ( !obj )
+    return false;
+  
+  // found it
+  var parent = obj.parentNode;
+  if ( !nofade )
+    enlighten(aclDisableTransitionFX);
+  if ( aclDisableTransitionFX )
+  {
+    parent.removeChild(obj);
+  }
+  else
+  {
+    var timeout = fly_out_top(obj, true, true);
+    setTimeout(function()
+      {
+        parent.removeChild(obj);
+      }, timeout);
+  }
+}
+
+/**
+ * Simple test case
+ */
+
+function miniPromptTest()
+{
+  miniPrompt(function(div) { div.innerHTML = 'hello world! <a href="#" onclick="miniPromptDestroy(this); return false;">destroy me</a>'; });
+}
+
+/**
+ * Message box system for miniPrompts. Less customization but easier to scale than the regular messageBox framework.
+ * @example
+ <code>
+ miniPromptMessage({
+   title: 'Delete page',
+   message: 'Do you really want to delete this page? This is reversible unless you clear the page logs.',
+   buttons: [
+     {
+       text: 'Delete',
+       color: 'red',
+       style: {
+         fontWeight: 'bold'
+       },
+       onclick: function() {
+         ajaxDeletePage();
+         miniPromptDestroy(this);
+       }
+     },
+     {
+       text: 'cancel',
+       onclick: function() {
+         miniPromptDestroy(this);
+       }
+     }
+   ]
+ });
+ </code>
+ */
+
+function miniPromptMessage(parms)
+{
+  if ( !parms.title || !parms.message || !parms.buttons )
+    return false;
+  
+  return miniPrompt(function(parent)
+    {
+      try
+      {
+        var h3 = document.createElement('h3');
+        h3.appendChild(document.createTextNode(parms.title));
+        var body = document.createElement('p');
+        var message = parms.message.split(unescape('%0A'));
+        for ( var i = 0; i < message.length; i++ )
+        {
+          body.appendChild(document.createTextNode(message[i]));
+          if ( i + 1 < message.length )
+            body.appendChild(document.createElement('br'));
+        }
+        
+        parent.style.textAlign = 'center';
+        
+        parent.appendChild(h3);
+        parent.appendChild(body);
+        parent.appendChild(document.createElement('br'));
+        
+        // construct buttons
+        for ( var i = 0; i < parms.buttons.length; i++ )
+        {
+          var button = parms.buttons[i];
+          button.input = document.createElement('a');
+          button.input.href = '#';
+          button.input.clickAction = button.onclick;
+          button.input.className = 'abutton';
+          if ( button.color )
+          {
+            button.input.className += ' abutton_' + button.color;
+          }
+          button.input.appendChild(document.createTextNode(button.text));
+          if ( button.style )
+          {
+            for ( var j in button.style )
+            {
+              button.input.style[j] = button.style[j];
+            }
+          }
+          button.input.onclick = function(e)
+          {
+            try
+            {
+              this.clickAction(e);
+            }
+            catch(e)
+            {
+              console.error(e);
+            }
+            return false;
+          }
+          parent.appendChild(button.input);
+        }
+        if ( parms.buttons[0] )
+        {
+          setTimeout(function()
+            {
+              parms.buttons[0].input.focus();
+            }, 300);
+        }
+      }
+      catch ( e )
+      {
+        console.error(e);
+      }
+    });
+}
+
+function testMPMessageBox()
+{
+  miniPromptMessage({
+    title: 'The Game of LIFE question #73',
+    message: 'You just got your girlfriend pregnant. Please select an option:',
+    buttons: [
+      {
+        text: 'Abort',
+        color: 'red',
+        style: {
+          fontWeight: 'bold'
+        },
+        onclick: function() {
+          miniPromptDestroy(this);
+        }
+      },
+      {
+        text: 'Retry',
+        color: 'blue',
+        onclick: function() {
+          miniPromptDestroy(this);
+        }
+      },
+      {
+        text: 'Ignore',
+        color: 'green',
+        onclick: function() {
+          miniPromptDestroy(this);
+        }
+      }
+    ]
+  });
+}
+