punbb/include/js/common.js
changeset 6 5e1f1e916419
equal deleted inserted replaced
5:e3d7322305bf 6:5e1f1e916419
       
     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 */