org.symbian.tools.wrttools.doc.WebDeveloper/html/js/utils.js
changeset 229 716254ccbcc0
equal deleted inserted replaced
228:913c9751c067 229:716254ccbcc0
       
     1 // ARRAY FUNTIONS
       
     2 
       
     3 /**
       
     4  * Test is some array member is equal (===) to tested value.
       
     5  *
       
     6  * @param arr array to test
       
     7  * @param value value to test
       
     8  * @type Boolean
       
     9  */
       
    10 function inArray(arr, value) {
       
    11 	for (var i = 0; i < arr.length; i++) {
       
    12 		if (arr[i] === value) {
       
    13 			return true;
       
    14 		}
       
    15 	}
       
    16 	return false;
       
    17 }
       
    18 
       
    19 // STRING FUNCTIONS
       
    20 
       
    21 
       
    22 /**
       
    23  * Get relative URL.
       
    24  *
       
    25  * @param url URL string
       
    26  * @return relative part of the URL
       
    27  * @type String
       
    28  */ 
       
    29 function getRelativeUrl(url, baseUrl) {
       
    30     if (baseUrl === undefined) {
       
    31         var i = url.lastIndexOf("/");
       
    32         if (i != -1) {
       
    33             return url.substring(i + 1);
       
    34         } else {
       
    35             return url;
       
    36         }
       
    37     } else {
       
    38         if (url.substring(0, baseUrl.length) === baseUrl) {
       
    39             return url.substring(baseUrl.length);
       
    40         } else {
       
    41             return undefined;
       
    42         }
       
    43     }
       
    44 }
       
    45 
       
    46 /**
       
    47  * Fix file scheme URLs generated by IE.
       
    48  *
       
    49  * @param url file scheme URL to fix
       
    50  */
       
    51 /* 
       
    52 function fixUrl(url) {
       
    53   var _url;
       
    54   if (pathFileUrl.test(url)) {
       
    55     _url = url.replace(pathFileUrl, "file:///$1/$2");
       
    56   } else {
       
    57     _url = url;
       
    58   }
       
    59   return _url.replace("\\", "/");
       
    60 
       
    61 }
       
    62 var pathFileUrl = new RegExp("^file://([a-zA-Z]:)[\\\\/](.+)$");
       
    63 */
       
    64 
       
    65 /**
       
    66  * Get string value for array where list is in prose.
       
    67  *
       
    68  * @param array array to get the string value for
       
    69  * @type String
       
    70  * @return array string value in prose
       
    71  */
       
    72 function toProseString(array) {
       
    73 	switch (array.length) {
       
    74 	case 0:
       
    75 		return "";
       
    76 	case 1:
       
    77 		return array[0];
       
    78 	case 2:
       
    79 		return array[0] + " and " + array[1];
       
    80 	default:
       
    81 		var t = "";
       
    82 		for (var i = 0; i < array.length - 1; i++) {
       
    83 			t += array[i] + ", ";
       
    84 		}
       
    85 		return t + "and " + array[array.length - 1];
       
    86 	}
       
    87 }
       
    88 
       
    89 
       
    90 // EVENT FUNCTIONS
       
    91 
       
    92 /**
       
    93  * Stop event.
       
    94  *
       
    95  * @param event event to stop
       
    96  */
       
    97 function stopEvent(event) {
       
    98     if (event.stopPropagation) {
       
    99         event.stopPropagation();
       
   100     } else {
       
   101         event.cancelBubble = true;
       
   102     }
       
   103     if (event.preventDefault) {
       
   104         event.preventDefault();
       
   105     } else {
       
   106         event.returnValue = false;
       
   107     }
       
   108 }
       
   109 
       
   110 /**
       
   111  * Return target node of an event.
       
   112  *
       
   113  * @return target node of the event
       
   114  * @type Node
       
   115  */
       
   116 function getTargetNode(event) {
       
   117 	if (event.target) {
       
   118 		return event.target;
       
   119 	} else if (event.srcElement) {
       
   120 		return event.srcElement;	
       
   121 	} else {
       
   122 		return null;	
       
   123 	}
       
   124 }
       
   125 
       
   126 /**
       
   127  * Attach event listener to a DOM node.
       
   128  *
       
   129  * @param node DOM node to attach lister to
       
   130  * @param type Type of event to catch
       
   131  * @param func Function to act as the handler 
       
   132  */
       
   133 function attachEventListener(node, type, func) {
       
   134     if (node.addEventListener) {
       
   135         node.addEventListener(type, func, false);
       
   136     } else if (node.attachEvent) {
       
   137         node.attachEvent("on" + type, function() { func.call(this, event); } );
       
   138     }
       
   139 }
       
   140 
       
   141 
       
   142 // CSS CLASS FUNCTIONS
       
   143 
       
   144 
       
   145 /**
       
   146  * Switch class of an element.
       
   147  *
       
   148  * @param n Element node to change the class of
       
   149  * @param f Class to change from
       
   150  * @param t Class to change to
       
   151  * @param arr Class array (optional)
       
   152  */
       
   153 function switchClass(n, f, t, arr) {
       
   154     if (arr === undefined) {
       
   155         arr = getClassArray(n.className);
       
   156     }
       
   157     for (var i = 0; i < arr.length; i++) {
       
   158         if (arr[i] == f) {
       
   159             arr[i] = t;
       
   160         } else if (arr[i] == t) {
       
   161             arr[i] = f;
       
   162         }
       
   163     }
       
   164     n.className = arr.join(" "); 
       
   165 }
       
   166 
       
   167 /**
       
   168  * Test if element is of class.
       
   169  *
       
   170  * @param n Element node to test
       
   171  * @param c Class to test for
       
   172  * @param arr Class array (optional)
       
   173  * @return boolean value if element is of the tested class
       
   174  */
       
   175 function isClass(n, c, arr) {
       
   176     if (arr === undefined) {
       
   177         arr = getClassArray(n.className);
       
   178     }
       
   179     for (var i = 0; i < arr.length; i++) {
       
   180         if (arr[i] == c) {
       
   181             return true;
       
   182         }
       
   183     }
       
   184     return false;
       
   185 }
       
   186 
       
   187 /**
       
   188  * Add class to an element.
       
   189  *
       
   190  * @param n Element node to add the class to
       
   191  * @param c Class to add
       
   192  * @param arr Class array (optional)
       
   193  */
       
   194 function addClass(n, c, arr) {
       
   195     if (arr === undefined) {
       
   196         arr = getClassArray(n.className);
       
   197     }
       
   198     if (!isClass(n, c, arr)) {
       
   199         n.className = n.className + " " + c;
       
   200     }
       
   201 }
       
   202 
       
   203 /**
       
   204  * Remove class
       
   205  *
       
   206  * @param n Element node to remove the class from
       
   207  * @param c Class to remove
       
   208  * @param arr Class array (optional)
       
   209  */
       
   210 function removeClass(n, c, arr) {
       
   211     if (arr === undefined) {
       
   212         arr = getClassArray(n.className);
       
   213     }
       
   214     if (isClass(n, c, arr)) {
       
   215         var ret = [];
       
   216         for (var i = 0; i < arr.length; i++) {
       
   217             if (arr[i] != c) {
       
   218                 ret.push(arr[i]);
       
   219             }
       
   220         }
       
   221         n.className = ret.join(" ");
       
   222     }
       
   223 }
       
   224 
       
   225 /**
       
   226  * Get class names as an array
       
   227  *
       
   228  * @param c class name
       
   229  * @return array of class members
       
   230  * @type Array
       
   231  */
       
   232 function getClassArray(c) {
       
   233     return String(c).split(" ");
       
   234 }
       
   235 
       
   236 
       
   237 // COLLECTION CLASSES
       
   238 
       
   239 
       
   240 /**
       
   241  * Multi value Map.
       
   242  *
       
   243  * Usage:
       
   244  *
       
   245  * >> var m = new Map();
       
   246  * >> m.put("a", "first");
       
   247  * >> m.put("a", "second");
       
   248  * >> m.size();
       
   249  * 1
       
   250  * >> m.get("a");
       
   251  * ["first", "second"]
       
   252  *
       
   253  * @constructor
       
   254  * @param {Boolean} multi Boolean to define whether map will store dublicate values into an array
       
   255  */
       
   256 function Map(multi) {
       
   257     this.keys = [];
       
   258     this.values = [];
       
   259     this.multi = (multi === undefined ? false : multi); 
       
   260 }
       
   261 Map.prototype.toString = function() {
       
   262     var val = "[Object Map";
       
   263     if (this.keys.length !== 0) {
       
   264         val += ": {";
       
   265         for (var i = 0; i < this.keys.length; i++) {
       
   266         	if (i !== 0) {
       
   267         		val += "; ";
       
   268         	}
       
   269         	val += this.keys[i] + ":";
       
   270 	        for (var j = 0; j < this.values[i].length; j++) {
       
   271 	        	if (j !== 0) {
       
   272 	        		val += ",";
       
   273 	        	}
       
   274 	        	val += " " + this.values[i][j].toString();
       
   275 	        }
       
   276 	       
       
   277         }
       
   278         val += "}";
       
   279     }
       
   280     val += "]";
       
   281     return val;
       
   282 };
       
   283 /**
       
   284  * @param {String} key
       
   285  * @param {Object} value
       
   286  */
       
   287 Map.prototype.put = function(key, value) {
       
   288     var index = this._find(key);
       
   289     var a;
       
   290     if (index != -1 ) {
       
   291         a = this.values[index];   
       
   292     } else {
       
   293         index = this.keys.length;
       
   294         this.keys[index] = key;
       
   295         a = [];
       
   296     }
       
   297     if (this.multi) {
       
   298         a[a.length] = value;
       
   299     } else {
       
   300         a[0] = value;
       
   301     }
       
   302     this.values[index] = a;
       
   303 };
       
   304 /**
       
   305  * @param {String} key
       
   306  * @type Object
       
   307  */
       
   308 Map.prototype.get = function(key) {
       
   309     var index = this._find(key);
       
   310     if (index != -1) {
       
   311         if (this.multi) {
       
   312             return this.values[index];
       
   313         } else {
       
   314             return this.values[index][0];
       
   315         }   
       
   316     } else {
       
   317         return null;
       
   318     }
       
   319 };
       
   320 /**
       
   321  * Iterator for the value set.
       
   322  *
       
   323  * @return Iterator for the values
       
   324  * @type ArrayIterator
       
   325  */
       
   326 Map.prototype.iterator = function(key) {
       
   327     var index = this._find(key);
       
   328     var val;
       
   329     if (index != -1) {
       
   330         val = this.values[index];
       
   331     } else {
       
   332         val = [];
       
   333     }
       
   334     return new ArrayIterator(val);
       
   335 };
       
   336 /**
       
   337  * @type Number
       
   338  */
       
   339 Map.prototype.size = function() {
       
   340 	return this.keys.length;
       
   341 };
       
   342 /**
       
   343  * @param {String} key
       
   344  * @type Number
       
   345  */
       
   346 Map.prototype._find = function(key) {
       
   347     var index = -1;
       
   348     for (var i = 0; i < this.keys.length; i++) {
       
   349         if (this.keys[i] == key) {
       
   350             index = i;
       
   351             break;
       
   352         }
       
   353     }
       
   354     return index;
       
   355 };
       
   356 
       
   357 /**
       
   358  * Map.
       
   359  *
       
   360  * Usage:
       
   361  *
       
   362  * >> var m = new SingleValueMap();
       
   363  * >> m.put("a", "first");
       
   364  * >> m.put("a", "second");
       
   365  * >> m.size();
       
   366  * 1
       
   367  * >> m.get("a");
       
   368  * "second"
       
   369  *
       
   370  * @constructor
       
   371  */
       
   372 function SingleValueMap() {
       
   373     this.keys = [];
       
   374     this.values = [];
       
   375     this.multi = false; 
       
   376 }
       
   377 SingleValueMap.prototype = new Map(false);
       
   378 SingleValueMap.prototype.toString = function() {
       
   379     return "[Object SingleValueMap]";
       
   380 };
       
   381 
       
   382 /**
       
   383  * Set.
       
   384  *
       
   385  * @constructor
       
   386  */
       
   387 function Set() {
       
   388 	this.keys = [];
       
   389 }
       
   390 Set.prototype.toString = function() {
       
   391 	var val = "[object Set";
       
   392 	if (this.keys.length > 0) {
       
   393 		val += ":";
       
   394 		for (var i = 0; i < this.keys.length; i++) {
       
   395 			if (i !== 0) {
       
   396 				val += ",";
       
   397 			}
       
   398 			val += " " + this.keys[i];
       
   399 		}
       
   400 	}
       
   401 	val += "]";
       
   402 	return val;
       
   403 };
       
   404 Set.prototype.add = function(value) {
       
   405 	var i = this.m_find(value);
       
   406 	if (i == -1) {
       
   407 		this.keys[this.keys.length] = value;
       
   408 	}
       
   409 };
       
   410 Set.prototype.iterator = function() {
       
   411 	return new ArrayIterator(this.keys);
       
   412 };
       
   413 Set.prototype.size = Map.prototype.size;
       
   414 Set.prototype.m_find = Map.prototype._find;
       
   415 
       
   416 /**
       
   417  * Array Iterator
       
   418  *
       
   419  * Usage:
       
   420  *
       
   421  * >> var arr = new Array("a", "b", "c");
       
   422  * >> for (var itr = new ArrayIterator(arr); itr.hasNext();) {
       
   423  * >>    alert(itr.next());
       
   424  * >> }
       
   425  * "a"
       
   426  * "b"
       
   427  * "c"
       
   428  *
       
   429  * @constructor
       
   430  * @param {Array} arrayLike array to iterate through
       
   431  */
       
   432 function ArrayIterator(arrayLike) {
       
   433     this.arrayLike = arrayLike;
       
   434     this.i = 0;
       
   435     NoSuchElementException = function() {};
       
   436     NoSuchElementException.prototype = new Error();
       
   437     NoSuchElementException.prototype.name = 'NoSuchElementException';
       
   438     NoSuchElementException.prototype.message = 'Iteration has no more elements';
       
   439 }
       
   440 /**
       
   441  * String value of the object.
       
   442  *
       
   443  * @type String
       
   444  */
       
   445 ArrayIterator.prototype.toString = function() {
       
   446   return "[Object ArrayIterator]";
       
   447 };
       
   448 /**
       
   449  * @type Object
       
   450  */
       
   451 ArrayIterator.prototype.next = function() {
       
   452     if (!this.hasNext()) {
       
   453         throw new NoSuchElementException();
       
   454     }
       
   455     if (this.arrayLike.item) {
       
   456     	return this.arrayLike.item(this.i++);
       
   457     } else {
       
   458     	return this.arrayLike[this.i++];
       
   459     }
       
   460 };
       
   461 /*/
       
   462  * @type Boolean
       
   463  */
       
   464 ArrayIterator.prototype.hasNext = function() {
       
   465     return this.i < this.arrayLike.length;
       
   466 };
       
   467 
       
   468 
       
   469 // DOM FUNCTIONS
       
   470 
       
   471 
       
   472 /**
       
   473  * Get next sibling by element name
       
   474  *
       
   475  * @param n current element
       
   476  * @param t element name of the desired sibling
       
   477  * @return next sibling element with a given name or null if not found
       
   478  * @type Element
       
   479  */
       
   480 function getNextSiblingByTagName(n, t) {
       
   481     if (n != null) {
       
   482         var tag = t.toLowerCase();
       
   483     	var i = n;
       
   484     	while (true) {
       
   485     		if (i.nodeType == 1 && i.nodeName.toLowerCase() == tag) {
       
   486     		    return i;
       
   487     		}
       
   488     		if (i.nextSibling != null) {
       
   489     			i = i.nextSibling;
       
   490     		} else {
       
   491     			return null;
       
   492     		}
       
   493     	}
       
   494 	}
       
   495 	return null;
       
   496 }
       
   497 
       
   498 /**
       
   499  * Get child elements by element name.
       
   500  *
       
   501  * @param node parent element
       
   502  * @param name element name of the desired child elements
       
   503  * @return array of child elements
       
   504  * @type Array
       
   505  */
       
   506 function getChildElementsByTagName(node, name) {
       
   507 	var buf = [];
       
   508 	var tag = undefined;
       
   509     if (name !== undefined) {
       
   510         tag = name.toLowerCase();
       
   511     }
       
   512 	for (var n = node.firstChild; n != null; n = n.nextSibling) {
       
   513 		if (n.nodeType == 1 && (name === undefined || n.nodeName.toLowerCase() == tag)) {
       
   514 			buf[buf.length] = n;
       
   515 		}
       
   516 	}
       
   517 	return buf;
       
   518 }
       
   519 
       
   520 /**
       
   521  * Get first child element by element name.
       
   522  *
       
   523  * @param node parent element
       
   524  * @param name element name of the desired child elements
       
   525  * @return DOM Element, null if none found
       
   526  * @type Object
       
   527  */
       
   528 function getFirstChildElementByTagName(node, name) {
       
   529 	var tag = undefined;
       
   530     if (name !== undefined) {
       
   531         tag = name.toLowerCase();
       
   532     }
       
   533 	for (var n = node.firstChild; n != null; n = n.nextSibling) {
       
   534 		if (n.nodeType == 1 && (name === undefined || n.nodeName.toLowerCase() == tag)) {
       
   535 		  return n;
       
   536 		}
       
   537 	}
       
   538 	return null;
       
   539 }
       
   540 
       
   541 
       
   542 /**
       
   543  * Wrap child nodes of an element to wrapper element.
       
   544  *
       
   545  * @param parent element whose child nodes to wrapper
       
   546  * @param wrapper wrapper element 
       
   547  */
       
   548 function wrapChildElements(parent, wrapper) {
       
   549 	for (var c = parent.firstChild, n = null; c != null; c = parent.firstChild) {
       
   550 		n = parent.removeChild(c);
       
   551 		wrapper.appendChild(n);
       
   552 	}
       
   553 	parent.appendChild(wrapper);
       
   554 }
       
   555 
       
   556 /**
       
   557  * Get elements by class name.
       
   558  *
       
   559  * @param node DOM node whose descendants select
       
   560  * @param cls class name
       
   561  * @param elem element name (optional)
       
   562  * @return array of DOM nodes
       
   563  * @type Array
       
   564  */
       
   565 function getElementsByClassName(node, cls, elem) {
       
   566 	if (elem === undefined) {
       
   567 		elem = "*";
       
   568 	}
       
   569 	var res = [];
       
   570 	for (var el = document.getElementsByTagName(elem), i = 0; i < el.length; i++) {
       
   571 	  	if (isClass(el[i], cls)) {
       
   572 	    	res[res.length] = el[i];
       
   573 		}
       
   574 	}
       
   575 	return res;
       
   576 }
       
   577 
       
   578 /**
       
   579  * Get first element by class name.
       
   580  *
       
   581  * @param node DOM node whose descendants select
       
   582  * @param cls class name
       
   583  * @param elem element name (optional)
       
   584  * @return DOM Element, null if none found
       
   585  * @type Object
       
   586  */
       
   587 function getFirstElementByClassName(node, cls, elem) {
       
   588   	if (elem === undefined) {
       
   589   		elem = "*";
       
   590   	}
       
   591   	for (var el = document.getElementsByTagName(elem), i = 0; i < el.length; i++) {
       
   592   	  	if (isClass(el[i], cls)) {
       
   593   	  	    return el[i];
       
   594         }
       
   595   	}
       
   596   	return null;
       
   597 }
       
   598 
       
   599 // FORM FUNCTIONS
       
   600 
       
   601 function formSubmitHandler(event) {
       
   602     var f = getTargetNode(event);
       
   603     if (!validateForm(f)) {
       
   604         stopEvent(event);
       
   605     }
       
   606 }
       
   607 
       
   608 /**
       
   609  * Validate form
       
   610  *
       
   611  * @param form form to validate
       
   612  * @type Boolean
       
   613  * @return boolean value whether validation was successful
       
   614  */
       
   615 function validateForm(form) {
       
   616     var isValid = true;
       
   617     var labels;
       
   618     var r = [];
       
   619     var missing;
       
   620     var col = form.elements;
       
   621     elements: for (var i = 0; i < col.length; i++) {
       
   622         if (isClass(col[i], "required") && !col[i].disabled) {
       
   623             var f = col[col[i].name];
       
   624             var valid = false;
       
   625             if (col[i].type === "checkbox" || col[i].type === "radio") {            
       
   626                 if (col[i].value != f[0].value) { // test only the first
       
   627                     continue;
       
   628                 }
       
   629                 for (var j = 0; j < f.length; j++) {
       
   630                     if (f[j].checked && f[j].className.indexOf("nonrequired") == -1) {
       
   631                         continue elements;
       
   632                     }
       
   633                 }
       
   634             } else if (col[i].type === "select-one") {
       
   635                 if (!isClass(col[i][col[i].selectedIndex], "nonvalue")) {
       
   636                     continue;
       
   637                 }
       
   638             } else {
       
   639                 if (f.value !== "") {
       
   640                     continue;
       
   641                 }
       
   642             }
       
   643             
       
   644             if (labels === undefined) {
       
   645             	labels = form.getElementsByTagName("label");
       
   646             }
       
   647             var label;
       
   648             for (j = 0; j < labels.length; j++) {
       
   649                 if (labels[j].htmlFor == col[i].name) {
       
   650                 	label = labels[j];
       
   651                 }
       
   652             }
       
   653             if (!valid) {
       
   654             	isValid = false;
       
   655                 if (missing === undefined) {
       
   656                 	missing = [];
       
   657                 }
       
   658                 missing[missing.length] = label.firstChild.data;
       
   659                 addClass(label, "form_invalid");
       
   660             } else {
       
   661             	removeClass(label, "form_invalid");
       
   662             }
       
   663         }
       
   664     }
       
   665  	  if (!isValid) {
       
   666 	      window.alert("Required field" + (missing.length < 2 ? "" : "s")	+
       
   667 	            " " + toProseString(missing) +
       
   668 	            " " + (missing.length < 2 ? "has" : "have") + " no value");
       
   669     }
       
   670     return isValid;
       
   671 }