Bug 400026 - Add a parser util to support detecting a valid and safe URL from a given string.
diff --git a/bundles/org.eclipse.orion.client.ui/web/js-tests/globalSearch/testcase.js b/bundles/org.eclipse.orion.client.ui/web/js-tests/globalSearch/testcase.js
index 2a82804..8b8ed15 100644
--- a/bundles/org.eclipse.orion.client.ui/web/js-tests/globalSearch/testcase.js
+++ b/bundles/org.eclipse.orion.client.ui/web/js-tests/globalSearch/testcase.js
@@ -41,7 +41,7 @@
 	 */
 	function replaceFile(fileContentText, fileModel, inFileQuery, replaceString) {
 		var newContents = {contents: null};
-		mSearchUtils.generateNewContents(true, fileModel.contents, newContents, fileModel, replaceString, inFileQuery.searchStrLength); 
+		mSearchUtils.generateNewContents(false, fileModel.contents, newContents, fileModel, replaceString, inFileQuery.searchStrLength); 
 		return newContents.contents.join("\n");
 	}
 	
diff --git a/bundles/org.eclipse.orion.client.ui/web/js-tests/jsTestSuite.js b/bundles/org.eclipse.orion.client.ui/web/js-tests/jsTestSuite.js
index 03f8fa3..167543c 100644
--- a/bundles/org.eclipse.orion.client.ui/web/js-tests/jsTestSuite.js
+++ b/bundles/org.eclipse.orion.client.ui/web/js-tests/jsTestSuite.js
@@ -83,7 +83,10 @@
 
 // list your test cases here....
 OrionTestCase("commonjs-unittesting", "/js-tests/commonjs-unittesting/test.html");
+OrionTestCase("charDiff", "/js-tests/charDiff/test.html");
 OrionTestCase("compare", "/js-tests/compare/test.html");
+OrionTestCase("globalSearch", "/js-tests/globalSearch/test.html");
+OrionTestCase("urlUtils", "/js-tests/urlUtils/test.html");
 OrionTestCase("serviceRegistry", "/js-tests/serviceRegistry/test.html");
 OrionTestCase("preferences", "/js-tests/preferences/test.html");
 OrionTestCase("pluginRegistry", "/js-tests/pluginRegistry/test.html");
diff --git a/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/test.html b/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/test.html
new file mode 100644
index 0000000..f7da669
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/test.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- standard scripts -->
+	<script src="../../requirejs/require.js"></script>
+	<script type="text/javascript">
+	/*global require window*/
+	require({
+		  baseUrl: '../..',
+		  paths: {
+			  text: 'requirejs/text',
+			  i18n: 'requirejs/i18n',
+			  domReady: 'requirejs/domReady'	    
+		  },
+		  isTest: true
+		});
+	
+	window.onload = function() {
+		require(["orion/test","testcase.js"], function(test, testcase) {
+			test.run(testcase);			
+		});
+	};
+	</script>
+</head>
+<body>
+</body>
+</html>
\ No newline at end of file
diff --git a/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/testcase.js b/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/testcase.js
new file mode 100644
index 0000000..3e849ca
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.ui/web/js-tests/urlUtils/testcase.js
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2011, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made 
+ * available under the terms of the Eclipse Public License v1.0 
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+ * 
+ * Contributors: IBM Corporation - initial API and implementation
+ ******************************************************************************/
+/*global define orion */
+
+define(["orion/assert", "orion/urlUtils"], function(assert, mUrlUtils) {
+      
+	//The test cases are for testing the urlUtils function to detect if a given text has any URL encloded by "[" and "]". 
+	//Currently this detecting function is used as a parser for rendering a string in the shell page, by different segment. The segment is mixed by plain text and url link.
+	// Each segment has the following 2 properties:
+	//      segmentStr: String. The string in the segment.
+	//      isValidURL: Boolean. The flag indicating if the segment is a valid URL.
+	// 
+	var tests = {};
+	
+	/**
+	 * Test an empty string.
+	 */
+	tests.testEmpty = function() {
+		var result = mUrlUtils.detectValidURL("");
+		assert.equal(result, null);
+	};
+
+	/**
+	 * Test a string with no URL and no [] pair.
+	 */
+	tests.testNoURLNoPair = function() {
+		var result = mUrlUtils.detectValidURL("There is no URL");
+		assert.equal(result, null);
+	};
+
+	/**
+	 * Test a string with URL but no [] pair.
+	 */
+	tests.testWithURLNoPair = function() {
+		var result = mUrlUtils.detectValidURL("There is URL  http://abc.com:8081/param=foo");
+		assert.equal(result, null);
+	};
+
+	/**
+	 * Test a string with good URL enclosed by [] pair.
+	 */
+	tests.testWithURLAndPair = function() {
+		var result = mUrlUtils.detectValidURL("There is URL  [http://abc.com:8081/param=foo]  and it is valid");
+		var expectedResult = [{segmentStr: "There is URL  ", isValidURL: false},
+							  {segmentStr: "http://abc.com:8081/param=foo", isValidURL: true},
+							  {segmentStr: "  and it is valid", isValidURL: false}];
+		assert.deepEqual(result, expectedResult);
+	};
+
+	/**
+	 * Test a string with good URL enclosed by [] pair.
+	 */
+	tests.testWithTwoGoodURLAndPair = function() {
+		var result = mUrlUtils.detectValidURL("There is URL  [http://abc.com:8081/param=foo]   [http://abc.com:8082/param=foo] and they are valid");
+		var expectedResult = [{segmentStr: "There is URL  ", isValidURL: false},
+							  {segmentStr: "http://abc.com:8081/param=foo", isValidURL: true},
+							  {segmentStr: "   ", isValidURL: false},
+							  {segmentStr: "http://abc.com:8082/param=foo", isValidURL: true},
+							  {segmentStr: " and they are valid", isValidURL: false}];
+		assert.deepEqual(result, expectedResult);
+	};
+
+	/*
+	 // Test a string with bad URL enclosed by [] pair.
+	 
+	tests.testWithBadURLAndPair = function() {
+		var result = mUrlUtils.detectValidURL("There is URL  [//attacker.com:8081/param=foo]  and it is valid");
+		assert.deepEqual(result, null);
+	};
+
+	
+	// Test a string with bad URL and a good one enclosed by [] pair.
+	
+	tests.testWithGoodAndBadURLAndPair = function() {
+		var result = mUrlUtils.detectValidURL("There is bad URL  [//attacker.com:8081/param=foo]  and a good URL [https://abc.com:8081/param=foo] that is valid");
+		var expectedResult = [{segmentStr: "There is bad URL  [//attacker.com:8081/param=foo]  and a good URL ", isValidURL: false},
+							  {segmentStr: "http://abc.com:8081/param=foo", isValidURL: true},
+							  {segmentStr: " that is valid", isValidURL: false}];
+		assert.deepEqual(result, expectedResult);
+	};
+*/
+
+	return tests;
+});
diff --git a/bundles/org.eclipse.orion.client.ui/web/orion/urlUtils.js b/bundles/org.eclipse.orion.client.ui/web/orion/urlUtils.js
new file mode 100644
index 0000000..b584f48
--- /dev/null
+++ b/bundles/org.eclipse.orion.client.ui/web/orion/urlUtils.js
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * @license
+ * Copyright (c) 2009, 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials are made 
+ * available under the terms of the Eclipse Public License v1.0 
+ * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution 
+ * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html). 
+ *
+ * Contributors: IBM Corporation - initial API and implementation
+ *******************************************************************************/
+/*global define window document*/
+
+define(['orion/PageUtil'], function(PageUtil) {
+                
+    /**
+     * Detect if the given text has any URL encloded by "[" and "]". Multiple occurences of the pattern "[url string]" and the non matched part are returned as an array of segments.
+     * @param {String} text The given string to detect.
+	 * @returns {Array} An array containing all the segments of the given string. Each segment has the following 2 properties:
+	 *     segmentStr: String. The string in the segment.
+	 *     isValidURL: Boolean. The flag indicating if the segment is a valid URL.
+	 */
+	function detectValidURL(text) {
+		var regex = /\[([^\]]+)\]/g;
+		var match = regex.exec(text), matches=[], lastNonMatchIndex=0;
+		while (match) {
+			//match[0]: the string enclosed by "[" and "]"
+			//match[1]: the string inside the pair of "[" and "]"
+			if(match.length === 2 && match[1].length >= 0){
+				if(PageUtil.validateURLScheme(match[1])) { //Check if it is a valid URL
+					if(match.index > lastNonMatchIndex) { //We have to push a plain text segment first
+						matches.push({segmentStr: text.substring(lastNonMatchIndex, match.index), isValidURL: false});
+					}
+					matches.push({segmentStr: match[1], isValidURL: true});
+					lastNonMatchIndex = match.index + match[0].length;
+				}
+			}
+			match = regex.exec(text);
+		}
+		if(lastNonMatchIndex === 0) {
+			return null;
+		} else if( lastNonMatchIndex < (text.length - 1) ) {
+			matches.push({segmentStr: text.substring(lastNonMatchIndex), isValidURL: false});
+		}
+		return matches;
+	}
+	
+    /**
+     * Render an array of string segments.
+     * @param {dom node} parentNode The given parent dom node where the segements will be rendered.
+     * @param {Array} segements The given array containing all the segments. Each segment has the following 2 properties:
+	 *     segmentStr: String. The string in the segment.
+	 *     isValidURL: Boolean. The flag indicating if the segment is a valid URL.
+	 */
+	function rendeStrSegments(parentNode, segments) {
+		segments.forEach(function(segment) {
+			if(segment.isValidURL){
+				var link = document.createElement('a');
+		        link.href = segment.segmentStr;
+		        link.appendChild(document.createTextNode(segment.segmentStr));
+				parentNode.appendChild(link);
+			} else {
+				var plainText = document.createElement("span");
+				plainText.textContent = segment.segmentStr;
+				parentNode.appendChild(plainText);
+			}
+		});
+	}
+	
+	//return module exports
+	return {
+		detectValidURL: detectValidURL,
+		rendeStrSegments: rendeStrSegments
+	};
+});
diff --git a/bundles/org.eclipse.orion.client.ui/web/search/search.js b/bundles/org.eclipse.orion.client.ui/web/search/search.js
index 6a268e3..dec1030 100644
--- a/bundles/org.eclipse.orion.client.ui/web/search/search.js
+++ b/bundles/org.eclipse.orion.client.ui/web/search/search.js
@@ -9,7 +9,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *******************************************************************************/
-/*global window define */
+/*global window define document*/
 /*browser:true*/
 
 define(['i18n!orion/search/nls/messages', 'require', 'orion/bootstrap', 'orion/status', 'orion/progress','orion/dialogs',