(function Menu($,win,doc, undefined) { var self = this; this.attachOneShot = function() { $(doc).on('click', function(e) { self.update('log', 'clicked: ' + ((e.target.id) ? '#' + e.target.id : e.target)); if (!$(e.target).is('#innerContainer, #innerContainer *')) { self.update('ui', 'warning'); self.toggleMenu('up'); } else { e.stopPropagation(); } }); }; this.toggleMenu = function(dir) { if (dir === 'down') { $('#inner').slideDown(1500); } if (dir === 'up') { $('#inner').slideUp(1000, function() { $(doc).off('click'); $('#eTargetStatus label').text('Status :'); self.update('ui', ''); self.update('log', 'document-wide click event listener removed'); }); } }; this.update = function(type, status, data) { switch (type) { case 'ui': $('body').removeClass('warning error success info').addClass(status); $('#eTargetStatus label').text('Status:'); break; case 'log': $('#eTargetStatus input').val(status); if (data !== 'undefined') { $('#eTargetStatus label').text(data); } break; default: break; } } this.init = (function() { $('#trigger').on('click', function() { self.update('ui', 'info'); self.toggleMenu('down'); self.attachOneShot(); }); // FORM SUBMISSION $('form').submit(function(e) { e.preventDefault(); var d; // data were are going to send via fake POST request var input = { user: $('input[name=user]').val(), pass: $('input[name=pass]').val() }; // form inputs // check dem form inputs!!! if (input['user'] === '' || (input['pass']) === '') { self.update('log', 'no input!', 'Error!'); self.update('ui', 'error'); return false; } else { // let's get it on! // form attributes var form_url = $(this).attr("action"); var form_method = $(this).attr("method").toUpperCase(); /* Input form data */ d = { "json": JSON.stringify({ user: $('input[name=user]').val(), pass: $('input[name=pass]').val() }), delay: 1.5 // fake server response delay }; $("#loadImg").show(); // AJAX SPINNER! // the main event $.ajax({ url: form_url, type: form_method, data: d, success: function(data) { $('#loadImg').hide(); // hide spinner! self.update('ui', 'success'); self.update('log', JSON.stringify(data), 'Data: '); self.toggleMenu('up'); }, error: function(e) { self.update('ui', 'error'); console.log('error', e) } }); } }); }()); }(jQuery,window,document));
<div id="outer">#outer <div id="innerContainer"> <span style="font-size: 10px;">#innerContainer</span> <div id="inner"> <span style="font-size: 10px;">#inner</span> <form action="/echo/json/" method="post" ajax="true"> <label>Username:</label> <input type="text" name="user" /> <label>Password:</label> <input type="text" name="pass" /> <hr /> <button type="submit">Submit</button> </form> </div> <hr /> <button id="trigger">#trigger</button> </div> </div> <div id="instructions"> <p>Button opens a hidden div and attaches a document-wide event handler. <br />Clicking anywhere other than inside #innerContainer (#outer or higher up the DOM tree) will hide the original hidden div (#inner) and remove the document-wide event handler</p> </div> <div id="eTargetStatus"> <label>Status:</label> <input type="text" /> <img id="loadImg" width="20" src="http://opengraphicdesign.com/wp-content/uploads/2009/01/loader64.gif" /> </div> <div class="info success error" id="result"></div>
body { font-family: Helvetica, Arial, sans-serif; } #instructions { width: 200px; height: auto; position: absolute; top: 10px; right: 50px; border: 2px solid #000; padding: 0 14px; background-color: #fff; } .error { background-color:#FFBABA; color:#D8000C; background-image:url('data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJPSURBVDjLpZPLS5RhFMYfv9QJlelTQZwRb2OKlKuINuHGLlBEBEOLxAu46oL0F0QQFdWizUCrWnjBaDHgThCMoiKkhUONTqmjmDp2GZ0UnWbmfc/ztrC+GbM2dXbv4ZzfeQ7vefKMMfifyP89IbevNNCYdkN2kawkCZKfSPZTOGTf6Y/m1uflKlC3LvsNTWArr9BT2LAf+W73dn5jHclIBFZyfYWU3or7T4K7AJmbl/yG7EtX1BQXNTVCYgtgbAEAYHlqYHlrsTEVQWr63RZFuqsfDAcdQPrGRR/JF5nKGm9xUxMyr0YBAEXXHgIANq/3ADQobD2J9fAkNiMTMSFb9z8ambMAQER3JC1XttkYGGZXoyZEGyTHRuBuPgBTUu7VSnUAgAUAWutOV2MjZGkehgYUA6O5A0AlkAyRnotiX3MLlFKduYCqAtuGXpyH0XQmOj+TIURt51OzURTYZdBKV2UBSsOIcRp/TVTT4ewK6idECAihtUKOArWcjq/B8tQ6UkUR31+OYXP4sTOdisivrkMyHodWejlXwcC38Fvs8dY5xaIId89VlJy7ACpCNCFCuOp8+BJ6A631gANQSg1mVmOxxGQYRW2nHMha4B5WA3chsv22T5/B13AIicWZmNZ6cMchTXUe81Okzz54pLi0uQWp+TmkZqMwxsBV74Or3od4OISPr0e3SHa3PX0f3HXKofNH/UIG9pZ5PeUth+CyS2EMkEqs4fPEOBJLsyske48/+xD8oxcAYPzs4QaS7RR2kbLTTOTQieczfzfTv8QPldGvTGoF6/8AAAAASUVORK5CYII='); } .success { background-color:#DFF2BF; color:#4F8A10; background-image:url('data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKfSURBVDjLpZPrS1NhHMf9O3bOdmwDCWREIYKEUHsVJBI7mg3FvCxL09290jZj2EyLMnJexkgpLbPUanNOberU5taUMnHZUULMvelCtWF0sW/n7MVMEiN64AsPD8/n83uucQDi/id/DBT4Dolypw/qsz0pTMbj/WHpiDgsdSUyUmeiPt2+V7SrIM+bSss8ySGdR4abQQv6lrui6VxsRonrGCS9VEjSQ9E7CtiqdOZ4UuTqnBHO1X7YXl6Daa4yGq7vWO1D40wVDtj4kWQbn94myPGkCDPdSesczE2sCZShwl8CzcwZ6NiUs6n2nYX99T1cnKqA2EKui6+TwphA5k4yqMayopU5mANV3lNQTBdCMVUA9VQh3GuDMHiVcLCS3J4jSLhCGmKCjBEx0xlshjXYhApfMZRP5CyYD+UkG08+xt+4wLVQZA1tzxthm2tEfD3JxARH7QkbD1ZuozaggdZbxK5kAIsf5qGaKMTY2lAU/rH5HW3PLsEwUYy+YCcERmIjJpDcpzb6l7th9KtQ69fi09ePUej9l7cx2DJbD7UrG3r3afQHOyCo+V3QQzE35pvQvnAZukk5zL5qRL59jsKbPzdheXoBZc4saFhBS6AO7V4zqCpiawuptwQG+UAa7Ct3UT0hh9p9EnXT5Vh6t4C22QaUDh6HwnECOmcO7K+6kW49DKqS2DrEZCtfuI+9GrNHg4fMHVSO5kE7nAPVkAxKBxcOzsajpS4Yh4ohUPPWKTUh3PaQEptIOr6BiJjcZXCwktaAGfrRIpwblqOV3YKdhfXOIvBLeREWpnd8ynsaSJoyESFphwTtfjN6X1jRO2+FxWtCWksqBApeiFIR9K6fiTpPiigDoadqCEag5YUFKl6Yrciw0VOlhOivv/Ff8wtn0KzlebrUYwAAAABJRU5ErkJggg=='); } .warning { background-color:#FEEFB3; color:#9F6000; background-image:url('data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIsSURBVDjLpVNLSJQBEP7+h6uu62vLVAJDW1KQTMrINQ1vPQzq1GOpa9EppGOHLh0kCEKL7JBEhVCHihAsESyJiE4FWShGRmauu7KYiv6Pma+DGoFrBQ7MzGFmPr5vmDFIYj1mr1WYfrHPovA9VVOqbC7e/1rS9ZlrAVDYHig5WB0oPtBI0TNrUiC5yhP9jeF4X8NPcWfopoY48XT39PjjXeF0vWkZqOjd7LJYrmGasHPCCJbHwhS9/F8M4s8baid764Xi0Ilfp5voorpJfn2wwx/r3l77TwZUvR+qajXVn8PnvocYfXYH6k2ioOaCpaIdf11ivDcayyiMVudsOYqFb60gARJYHG9DbqQFmSVNjaO3K2NpAeK90ZCqtgcrjkP9aUCXp0moetDFEeRXnYCKXhm+uTW0CkBFu4JlxzZkFlbASz4CQGQVBFeEwZm8geyiMuRVntzsL3oXV+YMkvjRsydC1U+lhwZsWXgHb+oWVAEzIwvzyVlk5igsi7DymmHlHsFQR50rjl+981Jy1Fw6Gu0ObTtnU+cgs28AKgDiy+Awpj5OACBAhZ/qh2HOo6i+NeA73jUAML4/qWux8mt6NjW1w599CS9xb0mSEqQBEDAtwqALUmBaG5FV3oYPnTHMjAwetlWksyByaukxQg2wQ9FlccaK/OXA3/uAEUDp3rNIDQ1ctSk6kHh1/jRFoaL4M4snEMeD73gQx4M4PsT1IZ5AfYH68tZY7zv/ApRMY9mnuVMvAAAAAElFTkSuQmCC'); } .info { background-color:#BDE5F8; color:#00529B; background-image:url('data:image/png; base64, iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKcSURBVDjLpZPLa9RXHMU/d0ysZEwmMQqZiTaP0agoaKGJUiwIxU0hUjtUQaIuXHSVbRVc+R8ICj5WvrCldJquhVqalIbOohuZxjDVxDSP0RgzyST9zdzvvffrQkh8tBs9yy9fPhw45xhV5X1U8+Yhc3U0LcEdVxdOVq20OA0ooQjhpnfhzuDZTx6++m9edfDFlZGMtXKxI6HJnrZGGtauAWAhcgwVnnB/enkGo/25859l3wIcvpzP2EhuHNpWF9/dWs/UnKW4EOGDkqhbQyqxjsKzMgM/P1ymhlO5C4ezK4DeS/c7RdzQoa3x1PaWenJjJZwT9rQ1gSp/js1jYoZdyfX8M1/mp7uFaTR8mrt29FEMQILr62jQ1I5kA8OF59jIItVA78dJertTiBNs1ZKfLNG+MUHX1oaURtIHEAOw3p/Y197MWHEJEUGCxwfHj8MTZIcnsGKxzrIURYzPLnJgbxvG2hMrKdjItjbV11CYKeG8R7ygIdB3sBMFhkem0RAAQ3Fuka7UZtRHrasOqhYNilOwrkrwnhCU/ON5/q04vHV48ThxOCuoAbxnBQB+am65QnO8FqMxNCjBe14mpHhxBBGCWBLxD3iyWMaYMLUKsO7WYH6Stk1xCAGccmR/Ozs/bKJuXS39R/YgIjgROloSDA39Deit1SZWotsjD8pfp5ONqZ6uTfyWn+T7X0f59t5fqDhUA4ry0fYtjJcWeZQvTBu4/VqRuk9/l9Fy5cbnX+6Od26s58HjWWaflwkusKGxjm1bmhkvLXHvh1+WMbWncgPfZN+qcvex6xnUXkzvSiYP7EvTvH4toDxdqDD4+ygT+cKMMbH+3MCZ7H9uAaDnqytpVX8cDScJlRY0YIwpAjcNcuePgXP/P6Z30QuoP4J7WbYhuQAAAABJRU5ErkJggg=='); } #outer { padding: 10px; float: left; background-color: #dea; width: 300px; height: auto; color: #000; text-align: center; } #innerContainer { color: #fff; width: auto; padding: 5px; background-color: #f00; } #inner { display: none; padding: 10px; background-color: #222; width: 200px; margin: auto; } #inner input { clear: both; display: block; width: 50%; margin: auto; } #inner h3 { margin: 0; } #eTargetStatus { position: absolute; top: 350px; height: auto; width: 500px; background-color: #fafafa; border: 1px solid #000; padding: 5px; } #eTargetStatus label { float: left; display: block; width: 60px; } #eTargetStatus input { width: 75%; float: left; display: block; } #loadImg { width: 20px; height: 20px; display: none; float: left; }