Fix for IE in element_pos()
[fa-stable.git] / js / utils.js
1 /**********************************************************************
2     Copyright (C) FrontAccounting, LLC.
3         Released under the terms of the GNU General Public License, GPL, 
4         as published by the Free Software Foundation, either version 3 
5         of the License, or (at your option) any later version.
6     This program is distributed in the hope that it will be useful,
7     but WITHOUT ANY WARRANTY; without even the implied warranty of
8     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
9     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ***********************************************************************/
11 //
12 //      JsHttpRequest class extensions.
13 //
14 // Main functions for asynchronus form submitions
15 //      Trigger is the source of request and can have following forms:
16 //      - input object - all form values are also submited
17 //  - arbitrary string - POST var trigger with value 1 is added to request;
18 //              if form parameter exists also form values are submited, otherwise
19 //              request is directed to current location 
20 // 
21     JsHttpRequest.request= function(trigger, form) {
22                 var mark = document.getElementById('ajaxmark');
23                 if(mark) mark.style.visibility = 'visible';
24                 if (trigger.tagName=='A') {
25                         var content = {};
26                         var upload = 0;
27                         var url = trigger.href;
28                         if (trigger.id) content[trigger.id] = 1;
29                 } else {
30                 var submitObj = typeof(trigger) == "string" ? 
31                         document.getElementsByName(trigger)[0] : trigger;
32                 
33                 form = form || (submitObj && submitObj.form);
34
35                 var upload = form && form.enctype=='multipart/form-data';
36                 
37                 var url = form ? form.action : 
38                   window.location.toString();
39
40                 var content = this.formInputs(trigger, form, upload);
41
42                 if (!form) url = url.substring(0, url.indexOf('?'));
43                 
44                 if (!submitObj) 
45                         content[trigger] = 1;
46                         
47                 }
48                         // this is to avoid caching problems
49                 content['_random'] = Math.random()*1234567;
50
51         JsHttpRequest.query(
52             (upload ? "form." : "")+"POST "+url, // force form loader
53                 content,
54             // Function is called when an answer arrives. 
55             function(result, errors) {
56                 // Write the answer.
57                         var newwin = 0;
58                 if (result) {
59                           for(var i in result ) { 
60                           atom = result[i];
61                           cmd = atom['n'];
62                           property = atom['p'];
63                           type = atom['c'];
64                           id = atom['t'];
65                           data = atom['data'];
66 //                              debug(cmd+':'+property+':'+type+':'+id);
67                         // seek element by id if there is no elemnt with given name
68                           objElement = document.getElementsByName(id)[0] || document.getElementById(id);
69                   if(cmd=='as') {
70                                   eval("objElement.setAttribute('"+property+"',"+data+");");
71                           } else if(cmd=='up') {
72 //                              if(!objElement) alert('No element "'+id+'"');
73                                 if(objElement) {
74                             if (objElement.tagName == 'INPUT' || objElement.tagName == 'TEXTAREA')
75                                   objElement.value = data;
76                             else
77                                   objElement.innerHTML = data; // selector, div, span etc
78                                 }
79                           } else if(cmd=='di') { // disable/enable element
80                                   objElement.disabled = data;
81                           } else if(cmd=='fc') { // set focus
82                                   _focus = data;
83                           } else if(cmd=='js') {        // evaluate js code
84                                   eval(data);
85                           } else if(cmd=='rd') {        // client-side redirection
86                                   window.location = data;
87                           } else if(cmd=='pu') {        // pop-up
88                                   newwin = 1;
89                                   window.open(data,'REP_WINDOW','toolbar=no,scrollbar=no,resizable=yes,menubar=no');
90                           } else {
91                                   errors = errors+'<br>Unknown ajax function: '+cmd;
92                         }
93                   }
94
95         // Write errors to the debug div.
96                   document.getElementById('msgbox').innerHTML = errors;
97                   var mark = document.getElementById('ajaxmark');
98                   if(mark) mark.style.visibility = 'hidden';
99
100                   Behaviour.apply();
101
102                   if (errors.length>0)
103                         window.scrollTo(0,0);
104                         //document.getElementById('msgbox').scrollIntoView(true);
105           // Restore focus if we've just lost focus because of DOM element refresh
106                         if(!newwin) { 
107                                 setFocus();
108                         }
109                 }
110             },
111             false  // do not disable caching
112         );
113     }
114         // collect all form input values plus inp trigger value
115         JsHttpRequest.formInputs = function(inp, objForm, upload)
116         {
117                 var submitObj = inp;
118                 var q = {};
119
120                 if (typeof(inp) == "string")
121                         submitObj = document.getElementsByName(inp)[0];
122                 else
123                         submitObj = inp;
124                 
125                 objForm = objForm || (submitObj && submitObj.form);
126
127                 if (objForm)
128                 {
129                         var formElements = objForm.elements;
130                         for( var i=0; i < formElements.length; i++)
131                         {
132                           var el = formElements[i];
133                           var name = el.name;
134                                 if (!el.name) continue;
135                                 if(upload) { // for form containing file inputs collect all 
136                                         // form elements and add value of trigger submit button
137                                         // (internally form is submitted via form.submit() not button click())
138                                         q[name] = submitObj.type=='submit' && el==submitObj ? el.value : el;
139                                         continue;
140                                 }
141                                 if (el.type )
142                                   if( 
143                                   ((el.type == 'radio' || el.type == 'checkbox') && el.checked == false)
144                                   || (el.type == 'submit' && (!submitObj || el.name!=submitObj.name)))
145                                         continue;
146                                 if (el.disabled && el.disabled == true)
147                                         continue;
148                                 if (name)
149                                 {
150                                         if(el.type=='select-multiple')
151                                         {
152                                                 for (var j = 0; j < el.length; j++)
153                                                 {
154                                                         if (el.options[j].selected == true)
155                                                                 q[name] = el.options[j].value;
156                                                 }
157                                         }
158                                         else
159                                         {
160                                                 q[name] = el.value;
161                                         }
162                                 } 
163                         }
164                 }
165                 return q;
166         }
167 //
168 //      User price formatting
169 //
170 function price_format(post, num, dec, label, color) {
171         var el = label ? document.getElementById(post) : document.getElementsByName(post)[0];
172         //num = num.toString().replace(/\$|\,/g,'');
173         if(isNaN(num))
174                 num = "0";
175         sign = (num == (num = Math.abs(num)));
176         if(dec<0) dec = 2;
177         decsize = Math.pow(10, dec);
178         num = Math.floor(num*decsize+0.50000000001);
179         cents = num%decsize;
180         num = Math.floor(num/decsize).toString();
181         for( i=cents.toString().length; i<dec; i++){
182                 cents = "0" + cents;
183         }
184         for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
185                 num = num.substring(0,num.length-(4*i+3))+user.ts+
186                         num.substring(num.length-(4*i+3));
187          num = ((sign)?'':'-') + num;
188          if(dec!=0) num = num + user.ds + cents;
189         if(label)
190             el.innerHTML = num;
191         else
192             el.value = num;
193         if(color) {
194                         el.style.color = (sign) ? '' : '#FF0000';
195         }
196 }
197
198 function get_amount(doc, label) {
199             if(label)
200                 var val = document.getElementById(doc).innerHTML;
201             else
202                 var val = document.getElementsByName(doc)[0].value;
203                 val = val.replace(new RegExp('\\'+user.ts, 'g'),'');
204                 val = +val.replace(new RegExp('\\'+user.ds, 'g'),'.');
205                 return isNaN(val) ? 0 : val;
206 }
207
208 function goBack() {
209         if (window.history.length <= 1)
210          window.close();
211         else
212          window.history.go(-1);
213 }
214
215 function setFocus(name, byId) {
216
217  if(typeof(name)=='object')
218         el = name;
219  else {
220         if(!name) { // page load/ajax update
221                 if (_focus)     
222                         name = _focus;  // last focus set in onfocus handlers
223                 else 
224                         if (document.forms.length) {    // no current focus (first page display) -  set it from from last form
225                           var cur = document.getElementsByName('_focus')[document.forms.length-1];
226                           if(cur) name = cur.value;
227                         }
228           }
229           if(byId || !(el = document.getElementsByName(name)[0]))
230                 el = document.getElementById(name);
231   }
232   if(el && el.focus) {
233     // The timeout is needed to prevent unpredictable behaviour on IE & Gecko.
234     // Using tmp var prevents crash on IE5
235         
236     var tmp = function() {el.focus(); if (el.select) el.select();};
237         setTimeout(tmp, 0);
238   }
239 }
240 /*
241         Find closest element in neighbourhood and set focus.
242         dir is arrow keycode.
243 */
244 function move_focus(dir, e0, neighbours)
245 {
246         var p0 = element_pos(e0);
247         var t;
248         var l=0;
249         for(var i=0; i<neighbours.length; i++) {
250                 var e = neighbours[i];
251                 var p = element_pos(e);
252                 if (p!=null && (e.className=='menu_option' || e.className=='printlink')) {
253                         if (((dir==40) && (p.y>p0.y)) || (dir==38 && (p.y<p0.y)) 
254                                 || ((dir==37) && (p.x<p0.x)) || ((dir==39 && (p.x>p0.x)))) {
255                                         var l1 = (p.y-p0.y)*(p.y-p0.y)+(p.x-p0.x)*(p.x-p0.x);
256                                         if ((l1<l) || (l==0)) {
257                                                 l = l1; t = e;
258                                         }
259                         }
260                 }
261         }
262         if (t)
263                 setFocus(t);
264         return t;
265 }
266
267 var __isFireFox = navigator.userAgent.match(/gecko/i);
268 //returns the absolute position of some element within document
269 function element_pos(e) {
270         var res = new Object();
271                 res.x = 0; res.y = 0;
272         if (e !== null) {
273                 res.x = e.offsetLeft;
274                 res.y = e.offsetTop;
275                 var offsetParent = e.offsetParent;
276                 var parentNode = e.parentNode;
277
278                 while (offsetParent !== null && offsetParent.style.display != 'none') {
279                         res.x += offsetParent.offsetLeft;
280                         res.y += offsetParent.offsetTop;
281                         // the second case is for IE6/7 in some doctypes
282                         if (offsetParent != document.body && offsetParent != document.documentElement) {
283                                 res.x -= offsetParent.scrollLeft;
284                                 res.y -= offsetParent.scrollTop;
285                         }
286                               //next lines are necessary to support FireFox problem with offsetParent
287                         if (__isFireFox) {
288                                 while (offsetParent != parentNode && parentNode !== null) {
289                                         res.x -= parentNode.scrollLeft;
290                                         res.y -= parentNode.scrollTop;
291
292                                         parentNode = parentNode.parentNode;
293                                 }
294                         }
295                         parentNode = offsetParent.parentNode;
296                         offsetParent = offsetParent.offsetParent;
297                 }
298         }
299         // parentNode has style.display set to none
300         if (parentNode != document.documentElement) return null;
301         return res;
302 }