[extensions-web: 22/30] js: Introduce a common mechanism for bringing up a "modal" popup and clean up



commit 6562216b67872126102ed1acc9a53c0efcd2e9fa
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Jan 5 20:32:16 2012 -0500

    js: Introduce a common mechanism for bringing up a "modal" popup and clean up
    
    A "modal" popup is one that closes when you click on the document around it,
    like the clever "Shell Global Menu" or the filtering UI. While we're at it,
    take some time to clean up the implementation of the "Shell Global Menu", too.

 .../templates/registration/login_popup_form.html   |    2 +-
 sweettooth/static/css/sweettooth.css               |   25 -------
 sweettooth/static/css/template.css                 |    6 +-
 sweettooth/static/js/filter.js                     |   67 +++++++++-----------
 sweettooth/static/js/main.js                       |   50 ++++++---------
 sweettooth/static/js/modal.js                      |   36 +++++++++++
 sweettooth/templates/base.html                     |    2 +-
 7 files changed, 89 insertions(+), 99 deletions(-)
---
diff --git a/sweettooth/auth/templates/registration/login_popup_form.html b/sweettooth/auth/templates/registration/login_popup_form.html
index dcd49e0..1e8c87e 100644
--- a/sweettooth/auth/templates/registration/login_popup_form.html
+++ b/sweettooth/auth/templates/registration/login_popup_form.html
@@ -1,4 +1,4 @@
-<form action="{% url auth-login %}" method="POST" class="login_popup_form">
+<form action="{% url auth-login %}" method="POST" class="login_popup_form user_popup">
   {% csrf_token %}
   {{ login_popup_form.as_plain }}
   <input type="submit" value="Login">
diff --git a/sweettooth/static/css/sweettooth.css b/sweettooth/static/css/sweettooth.css
index 0ea926c..4ca24d0 100644
--- a/sweettooth/static/css/sweettooth.css
+++ b/sweettooth/static/css/sweettooth.css
@@ -21,31 +21,6 @@
 /* Login Area */
 /* ==================================================================== */
 
-#global_domain_bar .login_popup_form:before {
-    width: 20px;
-    height: 10px;
-    margin-top: -17px;
-    right: 10px;
-    position: absolute;
-    content: url(../images/globaldomain-popup-arrow.png);
-}
-
-#global_domain_bar .login_popup_form {
-    display: none;
-    z-index: 10;
-    position: absolute;
-    background: #000;
-    background: rgba(0, 0, 0, 0.9);
-    border: 2px solid rgba(100%, 100%, 100%, 0.2);
-    right: 0;
-    top: -10px;
-    margin: 32px 0;
-    min-width: 140px;
-    -moz-border-radius: 10px;
-    -webkit-border-radius: 10px;
-    border-radius: 10px;
-}
-
 #global_domain_bar .login_popup_form * {
     display: block;
     margin: 10px 5px;
diff --git a/sweettooth/static/css/template.css b/sweettooth/static/css/template.css
index cab22ad..230c4aa 100644
--- a/sweettooth/static/css/template.css
+++ b/sweettooth/static/css/template.css
@@ -115,7 +115,7 @@ a:visited {
 
 /* User settings */
 
-#global_domain_bar .user_settings:before {
+#global_domain_bar .user_popup:before {
     width: 20px;
     height: 10px;
     margin-top: -25px;
@@ -123,7 +123,7 @@ a:visited {
     position: absolute;
     content: url(../images/globaldomain-popup-arrow.png);
 }
-#global_domain_bar .user_settings {
+#global_domain_bar .user_popup {
     display: none;
     z-index: 10;
     position: absolute;
@@ -139,7 +139,7 @@ a:visited {
     -webkit-border-radius: 10px;
     border-radius: 10px;
 }
-#global_domain_bar .user_settings a {
+#global_domain_bar .user_popup a {
     color: #fff;
     text-decoration: none;
     display: block;
diff --git a/sweettooth/static/js/filter.js b/sweettooth/static/js/filter.js
index 62bf5f3..65dda13 100644
--- a/sweettooth/static/js/filter.js
+++ b/sweettooth/static/js/filter.js
@@ -1,6 +1,6 @@
 "use strict";
 
-require(['jquery', 'hashparamutils'], function($, hashparamutils) {
+require(['jquery', 'hashparamutils', 'modal'], function($, hashparamutils, modal) {
 
     function makeLink(name, value, text) {
         return $('<li>', {'class': 'filter-sort-ui-sort-link'}).
@@ -38,49 +38,40 @@ require(['jquery', 'hashparamutils'], function($, hashparamutils) {
             var $link = $('<a>', {'class': 'filter-ui-link'}).
                 text("Filtering and Sorting").
                 click(function() {
-                    if (closeUI()) {
-                        return false;
-                    } else {
-                        $(this).addClass('selected');
-                        var pos = $elem.offset();
-                        var $filterUI = $('<div>', {'class': 'filter-ui'}).
-                            css({'top': pos.top + $elem.outerHeight(),
-                                 'left': pos.left,
-                                 'width': $elem.outerWidth()}).
-                            appendTo(document.body).
-                            hide().
-                            slideDown('fast');
+                    $(this).addClass('selected');
+                    var pos = $elem.offset();
+                    var $filterUI = $('<div>', {'class': 'filter-ui'}).
+                        css({'top': pos.top + $elem.outerHeight(),
+                             'left': pos.left,
+                             'width': $elem.outerWidth()}).
+                        appendTo(document.body).
+                        hide().
+                        slideDown('fast');
+                    modal.activateModal($filterUI, closeUI);
 
-                        var $sortUI = $('<div>', {'class': 'filter-sort-ui'}).
-                            appendTo($filterUI).
-                            append('<h4>Sort by</h4>');
+                    var $sortUI = $('<div>', {'class': 'filter-sort-ui'}).
+                        appendTo($filterUI).
+                        append('<h4>Sort by</h4>');
 
-                        var $sortUL = $('<ul>').appendTo($sortUI);
-
-                        var sortLinks = {};
-                        $.each(sortCriteria, function(key) {
-                            sortLinks[key] = makeLink('sort', key, this).
-                                appendTo($sortUL).
-                                click(function() {
-                                    closeUI();
-                                });
-                        });
-
-                        var hp = hashparamutils.getHashParams();
-                        if (hp.sort === undefined)
-                            hp.sort = 'name';
+                    var $sortUL = $('<ul>').appendTo($sortUI);
+                    var sortLinks = {};
+                    $.each(sortCriteria, function(key) {
+                        sortLinks[key] = makeLink('sort', key, this).
+                            appendTo($sortUL).
+                            click(function() {
+                                closeUI();
+                            });
+                    });
 
-                        if (sortLinks.hasOwnProperty(hp.sort))
-                            sortLinks[hp.sort].addClass('selected');
+                    var hp = hashparamutils.getHashParams();
+                    if (hp.sort === undefined)
+                        hp.sort = 'name';
 
-                        return false;
-                    }
-                }).appendTo($elem);
+                    if (sortLinks.hasOwnProperty(hp.sort))
+                        sortLinks[hp.sort].addClass('selected');
 
-            $(document.body).click(function() {
-                if (closeUI())
                     return false;
-            });
+                }).appendTo($elem);
         });
     };
 });
diff --git a/sweettooth/static/js/main.js b/sweettooth/static/js/main.js
index c1a3589..b95eaed 100644
--- a/sweettooth/static/js/main.js
+++ b/sweettooth/static/js/main.js
@@ -1,8 +1,9 @@
 "use strict";
 
-require(['jquery', 'messages', 'extensions', 'uploader', 'filter',
+require(['jquery', 'messages', 'modal',
+         'extensions', 'uploader', 'filter',
          'jquery.cookie', 'jquery.jeditable',
-         'jquery.timeago', 'jquery.rating'], function($, messages) {
+         'jquery.timeago', 'jquery.rating'], function($, messages, modal) {
     if (!$.ajaxSettings.headers)
         $.ajaxSettings.headers = {};
 
@@ -42,38 +43,25 @@ require(['jquery', 'messages', 'extensions', 'uploader', 'filter',
 
         $("abbr.timestamp").timeago();
 
+        var $userPopupLink = $('#global_domain_bar .user');
+        var $userPopup = $('#global_domain_bar .user_popup');
         function closeUserSettings() {
-            var needsClose = $('#global_domain_bar .user').hasClass('active');
-            if (!needsClose)
-                return false;
-
-            $('#global_domain_bar .user').removeClass('active');
-            $('#global_domain_bar .user_settings, #global_domain_bar .login_popup_form').animate({ top: '10px', opacity: 0 }, 200, function() {
-                $(this).hide();
-            });
-            return true;
-        }
-
-        function openUserSettings() {
-            $('#global_domain_bar .user').addClass('active');
-            $('#global_domain_bar .user_settings, #global_domain_bar .login_popup_form').show().css({ top: '-10px', opacity: 0 }).animate({ top: '0', opacity: 1 }, 200);
+            if ($userPopupLink.hasClass('active')) {
+                $userPopupLink.removeClass('active');
+                $userPopup.animate({ top: '10px', opacity: 0 }, 200, function() {
+                    $(this).hide();
+                });
+                return true;
+            }
         }
 
-        $(document.body).click(function() {
-            if (closeUserSettings())
-                return false;
-        });
-
-        $('#global_domain_bar .user_settings, #global_domain_bar .login_popup_form').click(function(e) {
-            e.stopPropagation();
-        });
-
-        $('#global_domain_bar .user').click(function() {
-            if ($(this).hasClass('active')) {
-                closeUserSettings();
-            } else {
-                openUserSettings();
-            }
+        $userPopupLink.click(function() {
+            $userPopupLink.addClass('active');
+            $userPopup.
+                show().
+                css({ top: '-10px', opacity: 0 }).
+                animate({ top: '0', opacity: 1 }, 200);
+            modal.activateModal($userPopup, closeUserSettings);
             return false;
         });
 
diff --git a/sweettooth/static/js/modal.js b/sweettooth/static/js/modal.js
new file mode 100644
index 0000000..f52ca4f
--- /dev/null
+++ b/sweettooth/static/js/modal.js
@@ -0,0 +1,36 @@
+"use strict";
+
+define(['jquery'], function($) {
+
+    // jQuery doesn't support events in the capturing phase natively.
+    // This is a trick that fires jQuery's event handler during the
+    // capturing phase.
+    function captureHandler() {
+        $.event.handle.apply(document.body, arguments);
+    }
+
+    function activateModal(elem, closeFunction) {
+        $(document.body).click(function(e) {
+            // If the user clicked inside the modal popup, don't
+            // close it.
+            if ($(elem).has(e.target).length) {
+                return true;
+            }
+
+            if (closeFunction()) {
+                $(document.body).unbind(e);
+                document.body.removeEventListener('click', captureHandler, true);
+                return false;
+            }
+
+            return true;
+        });
+
+        document.body.addEventListener('click', captureHandler, true);
+    }
+
+    return {
+        activateModal: activateModal
+    };
+
+});
diff --git a/sweettooth/templates/base.html b/sweettooth/templates/base.html
index d0e5454..d057f60 100644
--- a/sweettooth/templates/base.html
+++ b/sweettooth/templates/base.html
@@ -30,7 +30,7 @@
           {% endspaceless %}
         </div>
         {% if request.user.is_authenticated %}
-        <div class="user_settings">
+        <div class="user_settings user_popup">
           <ul>
             <li><a href="{% url auth-profile user=request.user.username %}">Your profile</a></li>
             <li><a href="{% url auth-settings user=request.user.username %}">Settings</a></li>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]