includes/clientside/static/messagebox.js
changeset 582 a38876c0793c
child 628 ab6f55abb17e
equal deleted inserted replaced
581:5e8fd89c02ea 582:a38876c0793c
       
     1 // Message box and visual effect system
       
     2 
       
     3 /**
       
     4  * The ultimate message box framework for Javascript
       
     5  * Syntax is (almost) identical to the MessageBox command in NSIS
       
     6  * @param int type - a bitfield consisting of the MB_* constants
       
     7  * @param string title - the blue text at the top of the window
       
     8  * @param string text - HTML for the body of the message box
       
     9  * Properties:
       
    10  *   onclick - an array of functions to be called on button click events
       
    11  *             NOTE: key names are to be strings, and they must be the value of the input, CaSe-SeNsItIvE
       
    12  *   onbeforeclick - same as onclick but called before the messagebox div is destroyed
       
    13  * Methods:
       
    14  *   destroy: kills the running message box
       
    15  * Example:
       
    16  *   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');
       
    17  *   my_message.onclick['OK'] = function() {
       
    18  *       document.getElementById('password').value = '';
       
    19  *     };
       
    20  * Deps:
       
    21  *   Modern browser that supports DOM
       
    22  *   darken() and enlighten() (above)
       
    23  *   opacity() - required for darken() and enlighten()
       
    24  *   MB_* constants are defined in enano-lib-basic.js
       
    25  */
       
    26 
       
    27 var mb_current_obj;
       
    28 var mb_previously_had_darkener = false;
       
    29 
       
    30 function MessageBox(type, title, message)
       
    31 {
       
    32   if ( !aclDisableTransitionFX )
       
    33   {
       
    34     load_component('flyin');
       
    35   }
       
    36   
       
    37   var y = getScrollOffset();
       
    38   
       
    39   // Prevent multiple instances
       
    40   if ( document.getElementById('messageBox') )
       
    41     return;
       
    42   
       
    43   if ( document.getElementById('specialLayer_darkener') )
       
    44     if ( document.getElementById('specialLayer_darkener').style.display == 'block' )
       
    45       mb_previously_had_darkener = true;
       
    46   if ( !mb_previously_had_darkener )
       
    47     darken(true);
       
    48   if ( aclDisableTransitionFX )
       
    49   {
       
    50     document.getElementById('specialLayer_darkener').style.zIndex = '5';
       
    51   }
       
    52   var master_div = document.createElement('div');
       
    53   master_div.style.zIndex = String(getHighestZ() + 5);
       
    54   var mydiv = document.createElement('div');
       
    55   mydiv.style.height = '200px';
       
    56   w = getWidth();
       
    57   h = getHeight();
       
    58   if ( aclDisableTransitionFX )
       
    59   {
       
    60     master_div.style.left = ((w / 2) - 200)+'px';
       
    61     master_div.style.top = ((h / 2) + y - 120)+'px';
       
    62     master_div.style.position = 'absolute';
       
    63   }
       
    64   else
       
    65   {
       
    66     master_div.style.top = '-10000px';
       
    67     master_div.style.position = ( IE ) ? 'absolute' : 'fixed';
       
    68   }
       
    69   z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex : getHighestZ();
       
    70   mydiv.style.backgroundColor = '#FFFFFF';
       
    71   mydiv.style.padding = '10px';
       
    72   mydiv.style.marginBottom = '1px';
       
    73   mydiv.id = 'messageBox';
       
    74   mydiv.style.overflow = 'auto';
       
    75   
       
    76   var buttondiv = document.createElement('div');
       
    77   
       
    78   mydiv.style.width = '400px';
       
    79   buttondiv.style.width = '400px';
       
    80   
       
    81   w = getWidth();
       
    82   h = getHeight();
       
    83   if ( aclDisableTransitionFX )
       
    84   {
       
    85     //buttondiv.style.left = ((w / 2) - 200)+'px';
       
    86     //buttondiv.style.top = ((h / 2) + y + 101)+'px';
       
    87   }
       
    88   //buttondiv.style.position = ( IE ) ? 'absolute' : 'fixed';
       
    89   z = ( aclDisableTransitionFX ) ? document.getElementById('specialLayer_darkener').style.zIndex : getHighestZ();
       
    90   buttondiv.style.backgroundColor = '#C0C0C0';
       
    91   buttondiv.style.padding = '10px';
       
    92   buttondiv.style.textAlign = 'right';
       
    93   buttondiv.style.verticalAlign = 'middle';
       
    94   buttondiv.id = 'messageBoxButtons';
       
    95   
       
    96   this.clickHandler = function() { messagebox_click(this, mb_current_obj); };
       
    97   
       
    98   if( ( type & MB_ICONINFORMATION || type & MB_ICONSTOP || type & MB_ICONQUESTION || type & MB_ICONEXCLAMATION ) && !(type & MB_ICONLOCK) )
       
    99   {
       
   100     mydiv.style.paddingLeft = '50px';
       
   101     mydiv.style.width = '360px';
       
   102     mydiv.style.backgroundRepeat = 'no-repeat';
       
   103     mydiv.style.backgroundPosition = '8px 8px';
       
   104   }
       
   105   else if ( type & MB_ICONLOCK )
       
   106   {
       
   107     mydiv.style.paddingLeft = '50px';
       
   108     mydiv.style.width = '360px';
       
   109     mydiv.style.backgroundRepeat = 'no-repeat';
       
   110   }
       
   111   
       
   112   if(type & MB_ICONINFORMATION)
       
   113   {
       
   114     mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/info.png\')';
       
   115   }
       
   116   
       
   117   if(type & MB_ICONQUESTION)
       
   118   {
       
   119     mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/question.png\')';
       
   120   }
       
   121   
       
   122   if(type & MB_ICONSTOP)
       
   123   {
       
   124     mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/error.png\')';
       
   125   }
       
   126   
       
   127   if(type & MB_ICONEXCLAMATION)
       
   128   {
       
   129     mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/warning.png\')';
       
   130   }
       
   131   
       
   132   if(type & MB_ICONLOCK)
       
   133   {
       
   134     mydiv.style.backgroundImage = 'url(\''+scriptPath+'/images/lock.png\')';
       
   135   }
       
   136   
       
   137   if(type & MB_OK)
       
   138   {
       
   139     btn = document.createElement('input');
       
   140     btn.type = 'button';
       
   141     btn.value = $lang.get('etc_ok');
       
   142     btn._GenericName = 'OK';
       
   143     btn.onclick = this.clickHandler;
       
   144     btn.style.margin = '0 3px';
       
   145     buttondiv.appendChild(btn);
       
   146   }
       
   147   
       
   148   if(type & MB_OKCANCEL)
       
   149   {
       
   150     btn = document.createElement('input');
       
   151     btn.type = 'button';
       
   152     btn.value = $lang.get('etc_ok');
       
   153     btn._GenericName = 'OK';
       
   154     btn.onclick = this.clickHandler;
       
   155     btn.style.margin = '0 3px';
       
   156     buttondiv.appendChild(btn);
       
   157     
       
   158     btn = document.createElement('input');
       
   159     btn.type = 'button';
       
   160     btn.value = $lang.get('etc_cancel');
       
   161     btn._GenericName = 'Cancel';
       
   162     btn.onclick = this.clickHandler;
       
   163     btn.style.margin = '0 3px';
       
   164     buttondiv.appendChild(btn);
       
   165   }
       
   166   
       
   167   if(type & MB_YESNO)
       
   168   {
       
   169     btn = document.createElement('input');
       
   170     btn.type = 'button';
       
   171     btn.value = $lang.get('etc_yes');
       
   172     btn._GenericName = 'Yes';
       
   173     btn.onclick = this.clickHandler;
       
   174     btn.style.margin = '0 3px';
       
   175     buttondiv.appendChild(btn);
       
   176     
       
   177     btn = document.createElement('input');
       
   178     btn.type = 'button';
       
   179     btn.value = $lang.get('etc_no');
       
   180     btn._GenericName = 'No';
       
   181     btn.onclick = this.clickHandler;
       
   182     btn.style.margin = '0 3px';
       
   183     buttondiv.appendChild(btn);
       
   184   }
       
   185   
       
   186   if(type & MB_YESNOCANCEL)
       
   187   {
       
   188     btn = document.createElement('input');
       
   189     btn.type = 'button';
       
   190     btn.value = $lang.get('etc_yes');
       
   191     btn._GenericName = 'Yes';
       
   192     btn.onclick = this.clickHandler;
       
   193     btn.style.margin = '0 3px';
       
   194     buttondiv.appendChild(btn);
       
   195     
       
   196     btn = document.createElement('input');
       
   197     btn.type = 'button';
       
   198     btn.value = $lang.get('etc_no');
       
   199     btn._GenericName = 'No';
       
   200     btn.onclick = this.clickHandler;
       
   201     btn.style.margin = '0 3px';
       
   202     buttondiv.appendChild(btn);
       
   203     
       
   204     btn = document.createElement('input');
       
   205     btn.type = 'button';
       
   206     btn.value = $lang.get('etc_cancel');
       
   207     btn._GenericName = 'Cancel';
       
   208     btn.onclick = this.clickHandler;
       
   209     btn.style.margin = '0 3px';
       
   210     buttondiv.appendChild(btn);
       
   211   }
       
   212   
       
   213   heading = document.createElement('h2');
       
   214   heading.innerHTML = title;
       
   215   heading.style.color = '#50A0D0';
       
   216   heading.style.fontFamily = 'trebuchet ms, verdana, arial, helvetica, sans-serif';
       
   217   heading.style.fontSize = '12pt';
       
   218   heading.style.fontWeight = 'lighter';
       
   219   heading.style.textTransform = 'lowercase';
       
   220   heading.style.marginTop = '0';
       
   221   mydiv.appendChild(heading);
       
   222   
       
   223   var text = document.createElement('div');
       
   224   text.innerHTML = String(message);
       
   225   this.text_area = text;
       
   226   mydiv.appendChild(text);
       
   227   
       
   228   this.updateContent = function(text)
       
   229     {
       
   230       this.text_area.innerHTML = text;
       
   231     };
       
   232     
       
   233   this.destroy = function()
       
   234     {
       
   235       var mbdiv = document.getElementById('messageBox');
       
   236       mbdiv.parentNode.removeChild(mbdiv.nextSibling);
       
   237       mbdiv.parentNode.removeChild(mbdiv);
       
   238       if ( !mb_previously_had_darkener )
       
   239         enlighten(true);
       
   240     };
       
   241   
       
   242   //domObjChangeOpac(0, mydiv);
       
   243   //domObjChangeOpac(0, master_div);
       
   244   
       
   245   body = document.getElementsByTagName('body');
       
   246   body = body[0];
       
   247   master_div.appendChild(mydiv);
       
   248   master_div.appendChild(buttondiv);
       
   249   
       
   250   body.appendChild(master_div);
       
   251   
       
   252   if ( !aclDisableTransitionFX )
       
   253     setTimeout('mb_runFlyIn();', 100);
       
   254   
       
   255   this.onclick = new Array();
       
   256   this.onbeforeclick = new Array();
       
   257   mb_current_obj = this;
       
   258 }
       
   259 
       
   260 var messagebox = MessageBox;
       
   261 
       
   262 function mb_runFlyIn()
       
   263 {
       
   264   var mydiv = document.getElementById('messageBox');
       
   265   var maindiv = mydiv.parentNode;
       
   266   fly_in_top(maindiv, true, false);
       
   267 }
       
   268 
       
   269 function messagebox_click(obj, mb)
       
   270 {
       
   271   val = ( typeof ( obj._GenericName ) == 'string' ) ? obj._GenericName : obj.value;
       
   272   if(typeof mb.onbeforeclick[val] == 'function')
       
   273   {
       
   274     var o = mb.onbeforeclick[val];
       
   275     var resp = o();
       
   276     if ( resp )
       
   277       return false;
       
   278     o = false;
       
   279   }
       
   280   
       
   281   var mydiv = document.getElementById('messageBox');
       
   282   var maindiv = mydiv.parentNode;
       
   283   
       
   284   if ( aclDisableTransitionFX )
       
   285   {
       
   286     var mbdiv = document.getElementById('messageBox');
       
   287     mbdiv.parentNode.removeChild(mbdiv.nextSibling);
       
   288     mbdiv.parentNode.removeChild(mbdiv);
       
   289     if ( !mb_previously_had_darkener )
       
   290       enlighten(true);
       
   291   }
       
   292   else
       
   293   {
       
   294     var to = fly_out_top(maindiv, true, false);
       
   295     setTimeout("var mbdiv = document.getElementById('messageBox'); mbdiv.parentNode.removeChild(mbdiv.nextSibling); mbdiv.parentNode.removeChild(mbdiv); if ( !mb_previously_had_darkener ) enlighten(true);", to);
       
   296   }
       
   297   if(typeof mb.onclick[val] == 'function')
       
   298   {
       
   299     o = mb.onclick[val];
       
   300     o();
       
   301     o = false;
       
   302   }
       
   303 }
       
   304 
       
   305 function testMessageBox()
       
   306 {
       
   307   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');
       
   308   mb.onclick['OK'] = function()
       
   309     {
       
   310       alert('You clicked OK!');
       
   311     }
       
   312   mb.onbeforeclick['Cancel'] = function()
       
   313     {
       
   314       alert('You clicked Cancel!');
       
   315     }
       
   316 }
       
   317 
       
   318 /**
       
   319  * The miniPrompt function, for creating small prompts and dialogs. The window will be flown in and the window darkened with opac=0.4.
       
   320  * @param function Will be passed an HTMLElement that is the body of the prompt window; the function can do with this as it pleases
       
   321  */
       
   322 
       
   323 function miniPrompt(call_on_create)
       
   324 {
       
   325   if ( !aclDisableTransitionFX )
       
   326   {
       
   327     load_component('flyin');
       
   328   }
       
   329   if ( document.getElementById('specialLayer_darkener') )
       
   330   {
       
   331     if ( document.getElementById('specialLayer_darkener').style.display != 'none' )
       
   332     {
       
   333       var opac = parseFloat(document.getElementById('specialLayer_darkener').style.opacity);
       
   334       opac = opac * 100;
       
   335       darken(aclDisableTransitionFX, opac);
       
   336     }
       
   337     else
       
   338     {
       
   339       darken(aclDisableTransitionFX, 40);
       
   340     }
       
   341   }
       
   342   else
       
   343   {
       
   344     darken(aclDisableTransitionFX, 40);
       
   345   }
       
   346   
       
   347   var wrapper = document.createElement('div');
       
   348   wrapper.className = 'miniprompt';
       
   349   var top = document.createElement('div');
       
   350   top.className = 'mp-top';
       
   351   var body = document.createElement('div');
       
   352   body.className = 'mp-body';
       
   353   var bottom = document.createElement('div');
       
   354   bottom.className = 'mp-bottom';
       
   355   if ( typeof(call_on_create) == 'function' )
       
   356   {
       
   357     call_on_create(body);
       
   358   }
       
   359   wrapper.appendChild(top);
       
   360   wrapper.appendChild(body);
       
   361   wrapper.appendChild(bottom);
       
   362   var left = ( getWidth() / 2 ) - ( 388 / 2 );
       
   363   wrapper.style.left = left + 'px';
       
   364   var top = getScrollOffset() - 27;
       
   365   wrapper.style.top = top + 'px';
       
   366   domObjChangeOpac(0, wrapper);
       
   367   var realbody = document.getElementsByTagName('body')[0];
       
   368   realbody.appendChild(wrapper);
       
   369   
       
   370   if ( aclDisableTransitionFX )
       
   371   {
       
   372     domObjChangeOpac(100, wrapper);
       
   373   }
       
   374   else
       
   375   {
       
   376     fly_in_top(wrapper, true, true);
       
   377     
       
   378     setTimeout(function()
       
   379       {
       
   380         domObjChangeOpac(100, wrapper);
       
   381       }, 40);
       
   382   }
       
   383 }
       
   384 
       
   385 /**
       
   386  * 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.
       
   387  * @param object:HTMLElement Child node to scan
       
   388  * @return object
       
   389  */
       
   390 
       
   391 function miniPromptGetParent(obj)
       
   392 {
       
   393   while ( true )
       
   394   {
       
   395     // prevent infinite loops
       
   396     if ( !obj || obj.tagName == 'BODY' )
       
   397       return false;
       
   398     
       
   399     if ( $dynano(obj).hasClass('miniprompt') )
       
   400     {
       
   401       return obj;
       
   402     }
       
   403     obj = obj.parentNode;
       
   404   }
       
   405   return false;
       
   406 }
       
   407 
       
   408 /**
       
   409  * Destroys the first miniPrompt div encountered by recursively checking all parent nodes.
       
   410  * Usage: <a href="javascript:miniPromptDestroy(this);">click</a>
       
   411  * @param object:HTMLElement a child of the div.miniprompt
       
   412  * @param bool If true, does not call enlighten().
       
   413  */
       
   414 
       
   415 function miniPromptDestroy(obj, nofade)
       
   416 {
       
   417   obj = miniPromptGetParent(obj);
       
   418   if ( !obj )
       
   419     return false;
       
   420   
       
   421   // found it
       
   422   var parent = obj.parentNode;
       
   423   if ( !nofade )
       
   424     enlighten(aclDisableTransitionFX);
       
   425   if ( aclDisableTransitionFX )
       
   426   {
       
   427     parent.removeChild(obj);
       
   428   }
       
   429   else
       
   430   {
       
   431     var timeout = fly_out_top(obj, true, true);
       
   432     setTimeout(function()
       
   433       {
       
   434         parent.removeChild(obj);
       
   435       }, timeout);
       
   436   }
       
   437 }
       
   438 
       
   439 /**
       
   440  * Simple test case
       
   441  */
       
   442 
       
   443 function miniPromptTest()
       
   444 {
       
   445   miniPrompt(function(div) { div.innerHTML = 'hello world! <a href="#" onclick="miniPromptDestroy(this); return false;">destroy me</a>'; });
       
   446 }
       
   447 
       
   448 /**
       
   449  * Message box system for miniPrompts. Less customization but easier to scale than the regular messageBox framework.
       
   450  * @example
       
   451  <code>
       
   452  miniPromptMessage({
       
   453    title: 'Delete page',
       
   454    message: 'Do you really want to delete this page? This is reversible unless you clear the page logs.',
       
   455    buttons: [
       
   456      {
       
   457        text: 'Delete',
       
   458        color: 'red',
       
   459        style: {
       
   460          fontWeight: 'bold'
       
   461        },
       
   462        onclick: function() {
       
   463          ajaxDeletePage();
       
   464          miniPromptDestroy(this);
       
   465        }
       
   466      },
       
   467      {
       
   468        text: 'cancel',
       
   469        onclick: function() {
       
   470          miniPromptDestroy(this);
       
   471        }
       
   472      }
       
   473    ]
       
   474  });
       
   475  </code>
       
   476  */
       
   477 
       
   478 function miniPromptMessage(parms)
       
   479 {
       
   480   if ( !parms.title || !parms.message || !parms.buttons )
       
   481     return false;
       
   482   
       
   483   return miniPrompt(function(parent)
       
   484     {
       
   485       try
       
   486       {
       
   487         var h3 = document.createElement('h3');
       
   488         h3.appendChild(document.createTextNode(parms.title));
       
   489         var body = document.createElement('p');
       
   490         var message = parms.message.split(unescape('%0A'));
       
   491         for ( var i = 0; i < message.length; i++ )
       
   492         {
       
   493           body.appendChild(document.createTextNode(message[i]));
       
   494           if ( i + 1 < message.length )
       
   495             body.appendChild(document.createElement('br'));
       
   496         }
       
   497         
       
   498         parent.style.textAlign = 'center';
       
   499         
       
   500         parent.appendChild(h3);
       
   501         parent.appendChild(body);
       
   502         parent.appendChild(document.createElement('br'));
       
   503         
       
   504         // construct buttons
       
   505         for ( var i = 0; i < parms.buttons.length; i++ )
       
   506         {
       
   507           var button = parms.buttons[i];
       
   508           button.input = document.createElement('a');
       
   509           button.input.href = '#';
       
   510           button.input.clickAction = button.onclick;
       
   511           button.input.className = 'abutton';
       
   512           if ( button.color )
       
   513           {
       
   514             button.input.className += ' abutton_' + button.color;
       
   515           }
       
   516           button.input.appendChild(document.createTextNode(button.text));
       
   517           if ( button.style )
       
   518           {
       
   519             for ( var j in button.style )
       
   520             {
       
   521               button.input.style[j] = button.style[j];
       
   522             }
       
   523           }
       
   524           button.input.onclick = function(e)
       
   525           {
       
   526             try
       
   527             {
       
   528               this.clickAction(e);
       
   529             }
       
   530             catch(e)
       
   531             {
       
   532               console.error(e);
       
   533             }
       
   534             return false;
       
   535           }
       
   536           parent.appendChild(button.input);
       
   537         }
       
   538         if ( parms.buttons[0] )
       
   539         {
       
   540           setTimeout(function()
       
   541             {
       
   542               parms.buttons[0].input.focus();
       
   543             }, 300);
       
   544         }
       
   545       }
       
   546       catch ( e )
       
   547       {
       
   548         console.error(e);
       
   549       }
       
   550     });
       
   551 }
       
   552 
       
   553 function testMPMessageBox()
       
   554 {
       
   555   miniPromptMessage({
       
   556     title: 'The Game of LIFE question #73',
       
   557     message: 'You just got your girlfriend pregnant. Please select an option:',
       
   558     buttons: [
       
   559       {
       
   560         text: 'Abort',
       
   561         color: 'red',
       
   562         style: {
       
   563           fontWeight: 'bold'
       
   564         },
       
   565         onclick: function() {
       
   566           miniPromptDestroy(this);
       
   567         }
       
   568       },
       
   569       {
       
   570         text: 'Retry',
       
   571         color: 'blue',
       
   572         onclick: function() {
       
   573           miniPromptDestroy(this);
       
   574         }
       
   575       },
       
   576       {
       
   577         text: 'Ignore',
       
   578         color: 'green',
       
   579         onclick: function() {
       
   580           miniPromptDestroy(this);
       
   581         }
       
   582       }
       
   583     ]
       
   584   });
       
   585 }
       
   586