]> dev.renevier.net Git - syj.git/blobdiff - public/js/utils.js
fixes: message did not appear when showing it too quickly after hiding it
[syj.git] / public / js / utils.js
index 376fbe85c358a72283e7e1b80e69d1265284fd1e..a81262fac5a89db5ae9151831225f078209c66fa 100644 (file)
@@ -1,6 +1,8 @@
-/*  This file is part of Syj, Copyright (c) 2010 Arnaud Renevier,
+/*  This file is part of Syj, Copyright (c) 2010-2011 Arnaud Renevier,
     and is published under the AGPL license. */
 
+"use strict";
+
 var CloseBtn = Class.create({
     initialize: function(elt, options) {
         var btn, imgsrc, style;
@@ -26,10 +28,17 @@ var CloseBtn = Class.create({
         elt.insert({top: btn});
         btn.observe("click", function(evt) {
             evt.stop();
+            if (evt.detail === 0) { // it's not a real click, possibly a submit event
+                return;
+            }
             if (typeof options.callback === "function") {
                 options.callback.call(elt);
             }
-            elt.hide();
+            if (typeof elt.clearMessages === "function") {
+                elt.clearMessages();
+            } else {
+                elt.hide();
+            }
         });
     }
 });
@@ -209,7 +218,8 @@ Ajax.Responders.register({
 
 // wrapper around Form.request that sets up the submit listener, stops the
 // submit event, calls presubmit function, calls Form.request and calls a
-// postsubmit function
+// postsubmit function. If form has some visible and activated file inputs,
+// execute presubmit, but do not send the file with ajax.
 Element.addMethods('form', {
     ajaxize : function(form, options) {
         var reqoptions;
@@ -217,7 +227,6 @@ Element.addMethods('form', {
         options = Object.clone(options || {});
 
         $(form).observe('submit', function(evt) {
-            evt.stop(); // cancel form submission
 
             reqoptions = Object.clone(options);
             delete(reqoptions.presubmit);
@@ -226,10 +235,30 @@ Element.addMethods('form', {
 
             if (Object.isFunction(options.presubmit)) {
                 if (options.presubmit(this) === false) {
+                    evt.stop(); // cancel form submission
                     return;
                 }
             }
 
+            // get list of input file not disabled, and not hidden
+            if (this.getInputs('file').find(function(elt) {
+                if (elt.disabled) {
+                    return false;
+                }
+                while (elt && $(elt).identify() !== this.identify()) {
+                    if (!elt.visible()) {
+                        return false;
+                    }
+                    elt = elt.parentNode;
+                }
+                return true;
+             }.bind(this))) {
+                // form has some file inputs. Do not manage on our own.
+                return;
+            }
+
+            evt.stop(); // cancel form submission
+
             var params = reqoptions.parameters, action = this.readAttribute('action') || '';
 
             if (action.blank()) {
@@ -336,7 +365,7 @@ Element.addMethods(['input', 'textarea'], {
                 }
                 handler.apply(null, arguments);
             });
-            proceed(element, 'paste', handler);
+            proceed(element, 'paste', handler.defer.bind(handler));
             return proceed(element, 'change', handler);
         }
         return proceed(element, eventName, handler);
@@ -375,50 +404,146 @@ Element.addMethods(['input', 'textarea'], {
     }
 });
 
-Element.addMethods('div', {
-    setMessage: function(div, message, status) {
-        div.clearMessages();
-        if (status) {
-            div.setMessageStatus(status);
+Element.addMethods('div', (function() {
+    var supportsTransition = false, endTransitionEventName = null;
+
+    if (window.addEventListener) { // fails badly in ie: prevents page from loading
+        var div = $(document.createElement('div'));
+        var timeout = null;
+
+        var cleanup = function() {
+            if (timeout) {
+                window.clearTimeout(timeout);
+                timeout = null;
+                div.stopObserving('webkitTransitionEnd');
+                div.stopObserving('transitionend');
+                div.stopObserving('oTransitionend');
+                Element.remove.defer(div);
+            }
         }
-        if (message) {
-            div.addMessage(message);
+
+        var handler = function(e) {
+            supportsTransition = true;
+            endTransitionEventName = e.type;
+            cleanup();
         }
-        return div;
-    },
+        div.observe('webkitTransitionEnd', handler).observe('transitionend', handler) .observe('oTransitionend', handler);
+        div.setStyle({'transitionProperty': 'opacity',
+                      'MozTransitionProperty': 'opacity',
+                      'WebkitTransitionProperty': 'opacity',
+                      'OTransitionProperty': 'opacity',
+                      'transitionDuration': '1ms',
+                      'MozTransitionDuration': '1ms',
+                      'WebkitTransitionDuration': '1ms',
+                      'OTransitionDuration': '1ms'});
+        $(document.documentElement).insert(div);
+        Element.setOpacity.defer(div, 0);
+        window.setTimeout(cleanup, 100);
+    }
 
-    clearMessages: function(div) {
+    function removeMessages(div) {
         var node = div.firstChild, nextNode;
 
         while (node) {
             nextNode = node.nextSibling;
-            if (node.nodeType === 3 || node.tagName.toLowerCase() === 'br') {
+            if (node.nodeType === 3 || node.tagName.toLowerCase() === 'br' || node.textContent || node.innerText) {
                 div.removeChild(node);
             }
                 node = nextNode;
         }
+        return div;
+    };
+
+    function hasOpacityTransition(div) {
+        return ([div.getStyle('transition-property'),
+                 div.getStyle('-moz-transition-property'),
+                 div.getStyle('-webkit-transition-property'),
+                 div.getStyle('-o-transition-property')
+                 ].join(' ').split(' ').indexOf('opacity') !== -1);
+    }
+
+    function hide(div) {
+        div = $(div);
+        if (supportsTransition && hasOpacityTransition(div)) {
+            div.observe(endTransitionEventName, function() {
+                div.stopObserving(endTransitionEventName);
+                if (!div.getOpacity()) { // in case show has been called in-between
+                  div.hide();
+                }
+            });
+            div.setOpacity(0);
+        } else {
+            div.hide();
+        }
+    }
+
+    function show(div) {
+        div = $(div);
+        div.show();
+        // we need to set opacity to 0 before calling hasOpacityTransition
+        // otherwise we trigger mozilla #601190
+        div.setOpacity(0);
+        if (supportsTransition && hasOpacityTransition(div)) {
+            // display = '' then opacity = 1;
+            Element.setOpacity.defer(div, 1);
+        } else {
+            div.setOpacity(1);
+        }
+    }
 
+    function clearMessages(div) {
+        if (div.getOpacity()) {
+            hide(div);
+        }
         return div;
-    },
+    }
 
-    addMessage: function(div, message) {
+    function setMessage(div, message, status) {
+        removeMessages(div);
+        if (status) {
+            div.setMessageStatus(status);
+        }
+        if (message) {
+            div.addMessage(message);
+        }
+        return div;
+    }
+
+    function addMessage(div, message) {
         var node = (div.ownerDocument || document).createTextNode(message);
 
         if ($A(div.childNodes).filter(function(node) {
-                return (node.nodeType === 3 || node.tagName.toLowerCase() === 'br');
+                return (node.nodeType === 3 || node.tagName.toLowerCase() === 'br' || node.textContent || node.innerText);
              }).length) {
             div.insert(new Element('br'));
         }
 
         div.appendChild(node);
-        return div.show();
-    },
+        if (!div.getOpacity()) {
+            show(div);
+        }
+        return div;
+    }
 
-    setMessageStatus: function(div, status) {
-        return div.removeClassName('error').
-                removeClassName('warn').
-                removeClassName('info').
-                removeClassName('success').
-                addClassName(status);
+    function setMessageStatus(div, status) {
+        $A(["error", "warn", "info", "success", "optional"]).each(function(clname) {
+            div.removeClassName(clname);
+        });
+        if (typeof status === "string") {
+            div.addClassName(status);
+        } else {
+            $A(status).each(function(clname) {
+                div.addClassName(clname);
+            });
+        }
+        return div;
     }
-});
+
+    return {
+        setMessage: setMessage,
+        clearMessages: clearMessages,
+        addMessage: addMessage,
+        setMessageStatus: setMessageStatus
+    };
+
+})());