|
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 |