|
1 var Punbb = { |
|
2 /* attach FN to WINDOW.ONLOAD handler */ |
|
3 addLoadEvent: function(fn) |
|
4 { |
|
5 var x = window.onload; |
|
6 window.onload = (x && typeof x=='function') ? function(){x();fn()} : fn; |
|
7 }, |
|
8 /* return TRUE if node N has class X, else FALSE */ |
|
9 hasClass: function(n, x) |
|
10 { |
|
11 return (new RegExp('\\b' + x + '\\b')).test(n.className) |
|
12 }, |
|
13 /* add X class to N node, return TRUE if added, FALSE if already exists */ |
|
14 addClass: function(n, x) |
|
15 { |
|
16 if (Punbb.hasClass(n, x)) return false; |
|
17 else n.className += ' ' + x; |
|
18 return true; |
|
19 }, |
|
20 /* remove X class from N node, return TRUE if removed, FALSE if not present */ |
|
21 removeClass: function(n, x) |
|
22 { |
|
23 if (!Punbb.hasClass(n, x)) return false; |
|
24 x = new RegExp('\\s*\\b' + x + '\\b', 'g'); |
|
25 n.className = n.className.replace(x, ''); |
|
26 return true; |
|
27 }, |
|
28 /* blink node N twice */ |
|
29 blink: function(n, i) |
|
30 { |
|
31 if (typeof i == 'undefined') i = 2; |
|
32 var x = n.style.visibility; |
|
33 if (i && x!='hidden') |
|
34 { |
|
35 n.style.visibility = 'hidden'; |
|
36 setTimeout(function(){n.style.visibility=x}, 200); |
|
37 setTimeout(function(){Punbb.blink(n,i-1)}, 400); |
|
38 } |
|
39 }, |
|
40 /* return true if node N scrolled into view, else false (y axis only) */ |
|
41 onScreen: function(n) |
|
42 { |
|
43 function pageYOffset() // return number of pixels page has scrolled |
|
44 { |
|
45 var y = -1; |
|
46 if (self.pageYOffset) y = self.pageYOffset; // all except IE |
|
47 else if (document.documentElement && document.documentElement.scrollTop) |
|
48 y = document.documentElement.scrollTop; // IE 6 Strict |
|
49 else if (document.body) y = document.body.scrollTop; // all other IE ver |
|
50 return y; |
|
51 } |
|
52 function innerHeight() // return inner height of browser window |
|
53 { |
|
54 var y = -1; |
|
55 if (self.innerHeight) y = self.innerHeight; // all except IE |
|
56 else if (document.documentElement && document.documentElement.clientHeight) |
|
57 y = document.documentElement.clientHeight; // IE 6 Strict Mode |
|
58 else if (document.body) y = document.body.clientHeight; // all other IE ver |
|
59 return y; |
|
60 } |
|
61 function nodeYOffset(n) // return y coordinate of node N |
|
62 { |
|
63 var y = n.offsetTop; |
|
64 n = n.offsetParent; |
|
65 return n ? y += nodeYOffset(n) : y; |
|
66 } |
|
67 var screenTop = pageYOffset(); |
|
68 var screenBottom = screenTop + innerHeight(); |
|
69 var nodeTop = nodeYOffset(n); |
|
70 var nodeBottom = nodeTop + n.clientHeight; |
|
71 return nodeTop >= screenTop && nodeBottom < screenBottom; |
|
72 }, |
|
73 /* apply FN to every ARR item, return array of results */ |
|
74 map: function(fn, arr) |
|
75 { |
|
76 for (var i=0,len=arr.length; i<len; i++) |
|
77 { |
|
78 arr[i] = fn(arr[i]) |
|
79 } |
|
80 return arr; |
|
81 }, |
|
82 /* return first index where FN(ARR[i]) is true or -1 if none */ |
|
83 find: function(fn, arr) |
|
84 { |
|
85 for (var i=0,len=arr.length; i<len; i++) |
|
86 { |
|
87 if (fn(arr[i])) return i; |
|
88 } |
|
89 return -1; |
|
90 }, |
|
91 /* return array of elements for which FN(ARR[i]) is true */ |
|
92 arrayOfMatched: function(fn, arr) |
|
93 { |
|
94 matched = []; |
|
95 for (var i=0,len=arr.length; i<len; i++) |
|
96 { |
|
97 if (fn(arr[i])) matched.push(arr[i]) |
|
98 } |
|
99 return matched; |
|
100 }, |
|
101 /* flattens multi-dimentional arrays into simple arrays */ |
|
102 flatten: function(arr) |
|
103 { |
|
104 flt = []; |
|
105 for (var i=0,len=arr.length; i<len; i++) |
|
106 { |
|
107 if (typeof arr[i] == 'object' && arr.length) { |
|
108 flt.concat(Punbb.flatten(arr[i])) |
|
109 alert('length1!!'+ arr.length); |
|
110 //x.hasChildNodes() |
|
111 } |
|
112 else flt.push(arr[i]) |
|
113 } |
|
114 return flt |
|
115 }, |
|
116 /* check FORM's required (REQ_) fields */ |
|
117 validateForm: function(form) |
|
118 { |
|
119 var elements = form.elements; |
|
120 var fn = function(x) { return x.name && x.name.indexOf('req_')==0 }; |
|
121 var nodes = Punbb.arrayOfMatched(fn, elements); |
|
122 fn = function(x) { return /^\s*$/.test(x.value) }; |
|
123 var empty = Punbb.find(fn, nodes); |
|
124 if (empty > -1) |
|
125 //if (Punbb.find(fn, nodes) > -1) |
|
126 { |
|
127 var n = document.getElementById('req-msg'); |
|
128 Punbb.removeClass(n, 'frm-warn'); |
|
129 var newlyAdded = Punbb.addClass(n, 'frm-error'); |
|
130 if (!Punbb.onScreen(n)) |
|
131 { |
|
132 n.scrollIntoView(); // method not in W3C DOM, but fully cross-browser? |
|
133 setTimeout(function(){Punbb.blink(n)}, 500); |
|
134 } |
|
135 else if (!newlyAdded) Punbb.blink(n); |
|
136 if (Punbb.onScreen(nodes[empty])) nodes[empty].focus(); |
|
137 return false; |
|
138 } |
|
139 return true; |
|
140 }, |
|
141 /* attach form validation function to submit-type inputs */ |
|
142 attachValidateForm: function() |
|
143 { |
|
144 var forms = document.forms; |
|
145 for (var i=0,len=forms.length; i<len; i++) |
|
146 { |
|
147 var elements = forms[i].elements; |
|
148 var fn = function(x) { return x.name && x.name.indexOf('req_')==0 }; |
|
149 if (Punbb.find(fn, elements) > -1) |
|
150 { |
|
151 fn = function(x) { return x.type && (x.type=='submit' && x.name!='cancel') }; |
|
152 var nodes = Punbb.arrayOfMatched(fn, elements) |
|
153 var formRef = forms[i]; |
|
154 fn = function() { return Punbb.validateForm(formRef) }; |
|
155 //TODO: look at passing array of node refs instead of forum ref |
|
156 //fn = function() { return Punbb.checkReq(required.slice(0)) }; |
|
157 nodes = Punbb.map(function(x){x.onclick=fn}, nodes); |
|
158 } |
|
159 } |
|
160 }, |
|
161 attachWindowOpen: function() |
|
162 { |
|
163 if (!document.getElementsByTagName) return; |
|
164 var nodes = document.getElementsByTagName('a'); |
|
165 for (var i=0; i<nodes.length; i++) |
|
166 { |
|
167 if (Punbb.hasClass(nodes[i], 'exthelp')) // || nodes[i].getAttribute('rel') == 'external') |
|
168 nodes[i].onclick = function() { window.open(this.href); return false; }; |
|
169 } |
|
170 }, |
|
171 autoFocus: function() |
|
172 { |
|
173 var nodes = document.getElementById('afocus'); |
|
174 if (!nodes || window.location.hash.replace(/#/g,'')) return; |
|
175 nodes = nodes.all ? nodes.all : nodes.getElementsByTagName('*'); |
|
176 // TODO: make sure line above gets nodes in display-order across browsers |
|
177 var fn = function(x) { return x.tagName.toUpperCase()=='TEXTAREA' || (x.tagName.toUpperCase()=='INPUT' && (x.type=='text') || (x.type=='password')) }; |
|
178 var n = Punbb.find(fn, nodes); |
|
179 if (n > -1) nodes[n].focus(); |
|
180 } |
|
181 } |
|
182 Punbb.addLoadEvent(Punbb.attachValidateForm); |
|
183 Punbb.addLoadEvent(Punbb.attachWindowOpen); |
|
184 Punbb.addLoadEvent(Punbb.autoFocus); |
|
185 |
|
186 /* A handful of functions in this script have been released into the Public |
|
187 Domain by Shawn Brown or other authors. Although I, Shawn Brown, do not |
|
188 believe that it is legally necessary to note which parts of a Copyrighted |
|
189 work are based on Public Domain content, a list of the Public Domain |
|
190 code (functions and methods) contained in this file is included below: |
|
191 |
|
192 * addLoadEvent: Released into the Public Domain by Shawn Brown and |
|
193 based on Simon Willison's Public Domain function of the same name. |
|
194 * hasClass, addClass & removeClass: Released into the Public Domain |
|
195 by Shawn Brown. |
|
196 * onScreen: Released into the Public Domain by Shawn Brown and based, |
|
197 in-part, on Peter Paul-Koch's Public Domain node-position functions. |
|
198 * map, find, arrayOfMatched & flatten: These basic functional methods |
|
199 have been released into the Public Domain by Shawn Brown. |
|
200 |
|
201 It is entirely possible that, in the future, someone may contribute code |
|
202 that is in the Public Domain but not note it as such. This should not be |
|
203 a problem, but one should keep in mind that the list provided here is known |
|
204 to be complete and accurate only up until 24-JUNE-2007. |
|
205 */ |