bugfix.
[Plinn.git] / skins / ajax_scripts / ajax_form_manager.js
index 9caf6e4..6f6748e 100644 (file)
@@ -1,20 +1,23 @@
-// (c) Benoît PIN 2006-2007
+// (c) Benoît PIN 2006-2014
 // http://plinn.org
 // Licence GPL
-// $Id: ajax_form_manager.js 1470 2009-02-18 16:42:02Z pin $
-// $URL: http://svn.cri.ensmp.fr/svn/Plinn/branches/CMF-2.1/skins/ajax_scripts/ajax_form_manager.js $
+// 
+// 
 
+var FormManager;
 
-function FormManager(form, responseTextDest, lazy) {
-       if (form.elements.namedItem("noAjax")) return;
+(function(){
+       
+FormManager = function(form, responseTextDest, lazy, noHistory) {
+       if (form.elements.namedItem("noAjax")) {return;}
        
        this.form = form;
        this.responseTextDest = responseTextDest;
        this.lazy = lazy;
+       this.noHistory = noHistory;
        var thisManager = this;
        this.form.onsubmit = function(evt) { thisManager.submit(evt); };
        this.form.onclick = function(evt) { thisManager.click(evt); };
-       this.submitButton = null;
        
        /* raised on form submit */
        this.onBeforeSubmit = null;
@@ -26,21 +29,20 @@ function FormManager(form, responseTextDest, lazy) {
        this.submitButton = null;
        
        if (this.lazy) {
-               this.fieldTagName;
-               this.liveFormField;
-               this.pendingEvent;
                this.form.onclick = function(evt){
                        thisManager.replaceElementByField(evt);
                        thisManager.click(evt);
                };
-               if (browser.isDOM2Event)
+               if (browser.isDOM2Event) {
                        this.form.onfocus = this.form.onclick;
-               else if (browser.isIE6up)
+               }
+               else if (browser.isIE6up) {
                        this.form.onfocusin = this.form.onclick;
+               }
                this.onResponseLoad = function(req){ thisManager.restoreField(req); };
-               this.lazyListeners = new Array();
+               this.lazyListeners = [];
        }
-}
+};
        
 FormManager.prototype.submit = function(evt) {
        var form = this.form;
@@ -50,16 +52,19 @@ FormManager.prototype.submit = function(evt) {
        if (!this.onBeforeSubmit) {
                var onBeforeSubmit = form.elements.namedItem("onBeforeSubmit");
                if (onBeforeSubmit) {
-                       if (onBeforeSubmit.length)
+                       if (onBeforeSubmit.length) {
                                onBeforeSubmit = onBeforeSubmit[0];
+                       }
+                       /*jslint evil: true */
                        this.onBeforeSubmit = eval(onBeforeSubmit.value);
                        bsMessage = this.onBeforeSubmit(thisManager, evt);
                }
        }
-       else
+       else {
                bsMessage = this.onBeforeSubmit(thisManager, evt);
+       }
        
-       if (bsMessage == 'cancelSubmit') {
+       if (bsMessage === 'cancelSubmit') {
                try {disableDefault(evt);}
                catch (e){}
                return;
@@ -67,41 +72,43 @@ FormManager.prototype.submit = function(evt) {
 
        if (!this.onResponseLoad) {
                var onResponseLoad = form.elements.namedItem("onResponseLoad");
-               if (onResponseLoad)
+               if (onResponseLoad) {
                        this.onResponseLoad = eval(onResponseLoad.value);
-               else
+               }
+               else {
                        this.onResponseLoad = this.loadResponse;
+               }
        }
 
        var submitButton = this.submitButton;
        var queryInfo = this.formData2QueryString();
-       var query = queryInfo['query'];
-       this.hasFile = queryInfo['hasFile'];
+       var query = queryInfo.query;
+       this.hasFile = queryInfo.hasFile;
        
        
        if (!this.onAfterPopulate) {
                var onAfterPopulate = form.elements.namedItem("onAfterPopulate");
-               if (onAfterPopulate)
+               if (onAfterPopulate) {
                        this.onAfterPopulate = onAfterPopulate.value;
-               else
+               }
+               else {
                        this.onAfterPopulate = function() {};
+               }
        }
        
        if (submitButton) {
                query += submitButton.name + '=' + submitButton.value + '&';
        }
        
-       if (window.AJAX_CONFIG && (AJAX_CONFIG & 1 == 1)) {
-               if (form.method.toLowerCase() == 'post')
-                       this._post(query);
-               else
-                       this._get(query)
-       }
-       else
+       if (form.method.toLowerCase() === 'post') {
                this._post(query);
+       }
+       else {
+               this._get(query);
+       }
        
        try {disableDefault(evt);}
-       catch (e){}
+       catch (e2){}
 };
 
 FormManager.prototype._post = function(query) {
@@ -117,11 +124,14 @@ FormManager.prototype._post = function(query) {
                                break;
                        case 4 :
                                hideProgressImage();
-                               if (req.status == 200 || req.status == 204)
+                               if (req.status === 200 || req.status === 204) {
                                        thisManager.onResponseLoad(req);
-                               else
+                               }
+                               else {
                                        alert('Error: ' + req.status);
-               };
+                               }
+                               break;
+               }
        };
        var url = this.form.action;
        req.open("POST", url, true);
@@ -130,16 +140,15 @@ FormManager.prototype._post = function(query) {
 };
 
 FormManager.prototype._get = function(query) {
-       // send form by browser location
        var url = this.form.action;
-       url += '?' + query
-       linkHandler.loadUrl(url);
+       url += '?' + query;
+       AjaxLinkHandler.prototype.loadUrl(url);
 };
 
 
 FormManager.prototype.click = function(evt) {
        var target = getTargetedObject(evt);
-       if(target.type == "submit" || target.type == "image") {
+       if(target.type === "submit" || target.type === "image") {
                this.submitButton = target;
                disablePropagation(evt);
        }
@@ -149,9 +158,10 @@ FormManager.prototype.replaceElementByField = function(evt) {
        evt = getEventObject(evt);
        var ob = getTargetedObject(evt);
        var eventType = evt.type;
-       if (eventType == 'focus' || eventType == 'focusin') {
-               if (this.liveFormField && ob.tagName != 'INPUT')
+       if (eventType === 'focus' || eventType === 'focusin') {
+               if (this.liveFormField && ob.tagName !== 'INPUT') {
                        this.pendingEvent = [ob, 'click'];
+               }
                return;
        }
        var fieldName = ob.getAttribute('id');
@@ -159,11 +169,15 @@ FormManager.prototype.replaceElementByField = function(evt) {
                this.fieldTagName = ob.tagName;
                var tabIndex = ob.tabIndex;
                var text;
-               if (ob.firstChild && ob.firstChild.className == 'hidden_value')
-                   text = ob.firstChild.innerHTML;
-               else
-                   text = ob.innerHTML;
+               if (ob.firstChild && ob.firstChild.className === 'hidden_value') {
+                       text = ob.firstChild.innerHTML;
+               }
+               else {
+                       text = ob.innerHTML;
+               }
                disablePropagation(evt);
+               var parent;
+               thisManager = this;
                switch (ob.tagName) {
                        case 'SPAN' :
                                // create input element
@@ -180,7 +194,7 @@ FormManager.prototype.replaceElementByField = function(evt) {
                                //inputText.setAttribute("size", text.length);
 
                                // replacement
-                               var parent = ob.parentNode;
+                               parent = ob.parentNode;
                                parent.replaceChild(inputText, ob);
 
                                inputText.focus();
@@ -189,7 +203,6 @@ FormManager.prototype.replaceElementByField = function(evt) {
                                inputText.tabIndex = tabIndex;
                                inputText.className = 'live_field';
                                this.liveFormField = inputText;
-                               var thisManager = this;
                                this.lazyListeners.push({'element': inputText, 'eventName' : 'blur', 'handler': function(){ thisManager.submit();}});
                                this.lazyListeners.push({'element': inputText, 'eventName' : 'keypress', 'handler': function(evt){ thisManager._fitField(evt);}});
                                this._addLazyListeners();
@@ -206,7 +219,7 @@ FormManager.prototype.replaceElementByField = function(evt) {
                                ta.value = text;
 
                                // replacement
-                               var parent = ob.parentNode;
+                               parent = ob.parentNode;
                                parent.replaceChild(ta, ob);
 
                                ta.focus();
@@ -214,27 +227,26 @@ FormManager.prototype.replaceElementByField = function(evt) {
                                ta.setAttribute('name', fieldName);
                                ta.tabIndex = tabIndex;
                                this.liveFormField = ta;
-                               var thisManager = this;
                                this.lazyListeners.push({'element': ta, 'eventName' : 'blur', 'handler': function(){ thisManager.submit();}});
                                this._addLazyListeners();
                                break;
-                               
-                               
-               };
+               }
        }
 };
 
 FormManager.prototype._addLazyListeners = function() {
-       for (var i=0 ; i<this.lazyListeners.length ; i++) {
-               var handlerInfo = this.lazyListeners[i];
-               addListener(handlerInfo['element'], handlerInfo['eventName'], handlerInfo['handler']);
+       var i, handlerInfo;
+       for (i=0 ; i<this.lazyListeners.length ; i++) {
+               handlerInfo = this.lazyListeners[i];
+               addListener(handlerInfo.element, handlerInfo.eventName, handlerInfo.handler);
        }
 };
 
 FormManager.prototype._removeLazyListeners = function() {
-       for (var i=0 ; i<this.lazyListeners.length ; i++) {
-               var handlerInfo = this.lazyListeners[i];
-               removeListener(handlerInfo['element'], handlerInfo['eventName'], handlerInfo['handler']);
+       var i, handlerInfo;
+       for (i=0 ; i<this.lazyListeners.length ; i++) {
+               handlerInfo = this.lazyListeners[i];
+               removeListener(handlerInfo.element, handlerInfo.eventName, handlerInfo.handler);
        }
 };
 
@@ -242,11 +254,12 @@ FormManager.prototype._removeLazyListeners = function() {
 FormManager.prototype.restoreField = function(req) {
        var text;
        var input = this.liveFormField;
-       if (req.status == 200) {
-               if (req.getResponseHeader('Content-Type').indexOf('text/xml') != -1) {
+       if (req.status === 200) {
+               if (req.getResponseHeader('Content-Type').indexOf('text/xml') !== -1) {
                        var out = '..........';
-                       if (req.responseXML.documentElement.firstChild)
+                       if (req.responseXML.documentElement.firstChild) {
                                out = req.responseXML.documentElement.firstChild.nodeValue;
+                       }
                        
                        switch (req.responseXML.documentElement.nodeName) {
                                case 'computedField':
@@ -259,18 +272,19 @@ FormManager.prototype.restoreField = function(req) {
                                        input.focus();
                                        this._addLazyListeners();
                                        return false;
-                                       break;
                        }
                }
                else {
                        text = req.responseText;
                }
        }
-       else
+       else {
                text = '';
+       }
        
-       if (!text.match(/\w/))
+       if (!text.match(/\w/)) {
                text = '..........';
+       }
        
        var field = document.createElement(this.fieldTagName);
        field.innerHTML = text;
@@ -282,8 +296,9 @@ FormManager.prototype.restoreField = function(req) {
        parent.replaceChild(field, input);
        this.liveFormField = null;
        
-       if (this.pendingEvent)
+       if (this.pendingEvent) {
                raiseMouseEvent(this.pendingEvent[0], this.pendingEvent[1]);
+       }
        return true;
 };
 
@@ -293,26 +308,29 @@ FormManager.prototype.formData2QueryString = function() {
        var form = this.form;
        var strSubmit = '', formElem, elements;
        var hasFile = false;
+       var i;
 
-       if (!this.lazy)
+       if (!this.lazy) {
                elements = form.elements;
+       }
        else {
-               elements = new Array();
+               elements = [];
                var formElements = form.elements;
-               for (var i = 0; i < formElements.length; i++) {
+               for (i = 0; i < formElements.length; i++) {
                        formElem = formElements[i];
                        switch (formElem.type) {
                                case 'hidden':
                                        elements.push(formElem);
                                        break;
                                default :
-                                       if (formElem == this.liveFormField)
+                                       if (formElem === this.liveFormField) {
                                                elements.push(formElem);
-                       };
+                                       }
+                       }
                }
        }
-       
-       for (var i = 0; i < elements.length; i++) {
+
+       for (i = 0; i < elements.length; i++) {
                formElem = elements[i];
                switch (formElem.type) {
                        // text, select, hidden, password, textarea elements
@@ -325,28 +343,33 @@ FormManager.prototype.formData2QueryString = function() {
                                break;
                        case 'radio':
                        case 'checkbox':
-                               if (formElem.checked)
+                               if (formElem.checked) {
                                        strSubmit += formElem.name + '=' + encodeURIComponent(formElem.value) + '&';
+                               }
                                break;
                        case 'select-multiple':
                                var options = formElem.getElementsByTagName("OPTION"), option;
-                               for (var j = 0 ; j < options.length ; j++) {
+                               var j;
+                               for (j = 0 ; j < options.length ; j++) {
                                        option = options[j];
-                                       if (option.selected)
+                                       if (option.selected) {
                                                strSubmit += formElem.name + '=' + encodeURIComponent(option.value) + '&';
+                                       }
                                }
                                break;
                        case 'file':
-                               if (formElem.value)
+                               if (formElem.value) {
                                        hasFile = true;
+                               }
                                break;
-               };
+               }
        }
        return {'query' : strSubmit, 'hasFile' : hasFile};
 };
 
 FormManager.prototype.loadResponse = function(req) {
-       if (req.getResponseHeader('Content-Type').indexOf('text/xml') != -1) {
+       var scripts;
+       if (req.getResponseHeader('Content-Type').indexOf('text/xml') !== -1) {
                switch(req.responseXML.documentElement.nodeName) {
                        case 'fragments' :
                                if (this.hasFile) {
@@ -363,16 +386,30 @@ FormManager.prototype.loadResponse = function(req) {
                                        return;
                                }
                                var fragments = req.responseXML.documentElement.childNodes;
-                               var fragment, dest, scripts;
-                               for (var i=0 ; i<fragments.length ; i++) {
-                                       fragment = fragments[i];
-                                       if (fragment.nodeName == 'fragment') {
-                                               dest = document.getElementById(fragment.getAttribute('id'));
-                                               dest.innerHTML = fragment.firstChild.nodeValue;
-                       
-                                               scripts = dest.getElementsByTagName('script');
-                                               for (var j=0 ; j < scripts.length ; j++)
-                                                       globalScriptRegistry.loadScript(scripts[j]);
+                               var element, dest, i, j;
+                               for (i=0 ; i < fragments.length ; i++) {
+                                       element = fragments[i];
+                                       switch (element.nodeName) {
+                                               case 'fragment' :
+                                                       dest = document.getElementById(element.getAttribute('id'));
+                                                       if(dest) {
+                                                               dest.innerHTML = element.firstChild.nodeValue;
+                                                               scripts = dest.getElementsByTagName('script');
+                                                               for (j=0 ; j < scripts.length ; j++) {
+                                                                       globalScriptRegistry.loadScript(scripts[j]); }
+                                                       }
+                                                       break;
+                                               case 'base' :
+                                                       var headBase = document.getElementsByTagName('base');
+                                                       if (headBase.length > 0) {
+                                                               headBase[0].setAttribute('href', element.getAttribute('href'));
+                                                       }
+                                                       else {
+                                                               headBase = document.createElement('base');
+                                                               headBase.setAttribute('href', element.getAttribute('href'));
+                                                               document.head.appendChild(headBase);
+                                                       }
+                                                       break;
                                        }
                                }
                                break;
@@ -383,18 +420,27 @@ FormManager.prototype.loadResponse = function(req) {
        }
        else {
                this.responseTextDest.innerHTML = req.responseText;
-               var scripts = this.responseTextDest.getElementsByTagName('script');
-               for (var j=0 ; j < scripts.length ; j++)
-                       globalScriptRegistry.loadScript(scripts[j]);
+               scripts = this.responseTextDest.getElementsByTagName('script');
+               var k;
+               for (k=0 ; k < scripts.length ; k++) {
+                       globalScriptRegistry.loadScript(scripts[k]);
+               }
        }
        
        var onAfterPopulate = this.onAfterPopulate;
-       if (typeof(onAfterPopulate) == "string") {
-               if (window.console)
-                       console.warn('Deprecation WARNING onAfterPopulate: ' + onAfterPopulate);
-               onAfterPopulate = eval(onAfterPopulate);
-       }
        onAfterPopulate();
+       this.scrollToPortalMessage();
+       var url = this.form.action;
+       if (!this.noHistory){ history.pushState(url, document.title, url); }
+};
+
+FormManager.prototype.scrollToPortalMessage = function() {
+       var psm = document.getElementById('DesktopStatusBar');
+       if (psm) {
+               var msgOffset = psm.offsetTop;
+               smoothScroll(window.scrollY, msgOffset);
+               shake(psm, 10, 1000);
+       }
 };
 
 FormManager.prototype._fitField = function(evt) {
@@ -405,14 +451,80 @@ FormManager.prototype._fitField = function(evt) {
 };
 
 function initForms(baseElement, lazy) {
-       if (!baseElement)
+       if (!baseElement) {
                baseElement = document;
+       }
        var dest = document.getElementById("mainCell");
        var forms = baseElement.getElementsByTagName("form");
-       var f;
-       for (var i = 0 ; i < forms.length ; i++ )
+       var f, i;
+       for (i = 0 ; i < forms.length ; i++ ) {
                f = new FormManager(forms[i], dest, lazy);
+       }
 }
 
+function smoothScroll(from, to) {
+       var intervalId;
+       var step = 25;
+       var pos = from;
+       var dir;
+       if (to > from) {
+               dir = 1;
+       }
+       else {
+               dir = -1;
+       }
+
+       var jump = function() {
+               window.scroll(0, pos);
+               pos = pos + step * dir;
+               if ((dir === 1 && pos >= to) ||
+                       (dir === -1 && pos <= to)) {
+                       window.clearInterval(intervalId);
+                       window.scroll(0, to);
+               }
+       };
+       intervalId = window.setInterval(jump, 10);
+}
+
+/* adapted from http://xahlee.info/js/js_shake_box.html */
+function shake(e, distance, time) {
+       // Handle arguments
+       if (!time) { time = 500; }
+       if (!distance) { distance = 5; }
+
+       // Save the original style of e, Make e relatively positioned, Note the animation start time, Start the animation
+       var originalStyle = e.style.cssText;
+       e.style.position = "relative";
+       var start = (new Date()).getTime();
+
+       // This function checks the elapsed time and updates the position of e.
+       // If the animation is complete, it restores e to its original state.
+       // Otherwise, it updates e's position and schedules itself to run again.
+       function animate() {
+               var now = (new Date()).getTime();
+               // Get current time
+               var elapsed = now-start;
+               // How long since we started
+               var fraction = elapsed/time;
+               // What fraction of total time?
+               if (fraction < 1) {
+                       // If the animation is not yet complete
+                       // Compute the x position of e as a function of animation
+                       // completion fraction. We use a sinusoidal function, and multiply
+                       // the completion fraction by 4pi, so that it shakes back and
+                       // forth twice.
+                       var x = distance * Math.sin(fraction*8*Math.PI);
+                       e.style.left = x + "px";
+                       // Try to run again in 25ms or at the end of the total time.
+                       // We're aiming for a smooth 40 frames/second animation.
+                       setTimeout(animate, Math.min(25, time-elapsed));
+               }
+               else {
+                       // Otherwise, the animation is complete
+                       e.style.cssText = originalStyle; // Restore the original style
+               }
+       }
+       animate();
+}
 
-//registerStartupFunction(initForms);
\ No newline at end of file
+}());