Commits

liefeld committed 8305b19

Fix for bugs 233,234 adding help text to add provate tool dialog. Also draft of upload url data source spec prototype

Comments (0)

Files changed (11)

jsui/src/main/java/org/genomespace/gsui/servlet/ExternalUploadServlet.java

+package org.genomespace.gsui.servlet;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpUtils;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.genomespace.client.GsSession;
+
+/**
+ * used to take external uplaods and save them to the designated directory for the user
+ */
+public class ExternalUploadServlet extends HttpServlet {
+	private static final long serialVersionUID = 1L;
+    JSUIConfig uiConfig = new JSUIConfig();
+	
+	private String dmUrl = null;
+	
+    /**
+     * @see HttpServlet#HttpServlet()
+     */
+    public ExternalUploadServlet() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+    
+    public void init(ServletConfig config) throws ServletException {
+  		super.init(config);
+  		uiConfig.init(config);
+  		dmUrl = uiConfig.getDmServerUrl()+ "/file/users/";
+      }
+	/**
+	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		String destinationPath = (String)request.getParameter("uploadTo");
+		String sourceUrl = (String)request.getParameter("sourceUrl");
+		String fileName = (String)request.getParameter("fileName");
+		String userName =  (String) request.getSession().getAttribute("gs-username");
+		
+		System.out.println("upload " + sourceUrl + " to " + destinationPath + "/" + fileName);
+		File tmpFile = new File(fileName);
+		tmpFile.deleteOnExit();
+		
+		try {
+			URL u;
+			InputStream is = null;
+			DataInputStream dis;
+			u = new URL(sourceUrl);
+			is = u.openStream(); 
+			BufferedInputStream bis = new BufferedInputStream(is);
+			FileOutputStream fos = new FileOutputStream(tmpFile);
+			int i;
+			// read byte by byte until end of stream
+			while ((i = bis.read()) > 0) {
+				fos.write(i);
+			}
+			fos.close();
+			GsSession gssession = new GsSession((String)request.getSession().getAttribute("gs-token"));
+			gssession.getDataManagerClient().uploadFile(tmpFile, destinationPath, fileName);
+			
+			response.getOutputStream().write("<html><head>done</head></html>".getBytes());
+			
+		} catch (Exception e){
+			throw new ServletException("Could not upload the requested URL to GenomeSpace\n"+e.getMessage());
+		}
+		
+		
+	}
+
+	/**
+	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
+	 */
+	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+		boolean isMultipart = ServletFileUpload.isMultipartContent(request);
+		// Create a factory for disk-based file items
+		FileItemFactory factory = new DiskFileItemFactory();
+
+		// Create a new file upload handler
+		ServletFileUpload upload = new ServletFileUpload(factory);
+		HashMap<String,Object> params = new HashMap<String,Object>();
+		File uploadedFile = null; 
+		// Parse the request
+		try {
+			List /* FileItem */ items = upload.parseRequest(request);
+			Iterator iter = items.iterator();
+			while (iter.hasNext()) {
+			    FileItem item = (FileItem) iter.next();
+
+			    if (item.isFormField()) {
+			    	String name = item.getFieldName();
+			        String value = item.getString();
+			        params.put(name, value);
+			    } else {
+			    	String fileName = item.getName();			    	   
+			    	uploadedFile = new File(fileName);
+			        item.write(uploadedFile);
+			    }
+			}
+			
+			GsSession session = new GsSession((String)request.getSession().getAttribute("gs-token"));
+			
+			Map<String, String> headers = new HashMap<String, String>();
+		    headers.put("Content-Length", "" + uploadedFile.length());
+		    headers.put("Content-Type", "application/octet-stream");
+		   
+		 	
+		    uploadGenomeSpaceFile((String)params.get("uploadTo"), uploadedFile, headers);
+			response.getOutputStream().write("<html><head>done</head></html>".getBytes());
+		
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+			response.getOutputStream().write("<html><head>error</head></html>".getBytes());
+			uploadedFile.delete();
+		}
+		
+		
+	}
+	
+	  public void uploadGenomeSpaceFile(String uri, File file, Map<String, String> headers) throws IOException {
+
+		  	System.out.println("PUT to " + uri);
+		  	System.out.println("Headers " + headers);
+		  	System.out.println("File " + file.getName() + "  " + file.length());
+			  
+		    HttpURLConnection urlconnection = null;
+	        OutputStream bos = null;
+
+	        URL url = new URL(uri);
+	        urlconnection = (HttpURLConnection) url.openConnection();
+	        urlconnection.setRequestMethod("PUT");
+	       
+	        for (Map.Entry<String, String> prop : headers.entrySet()) {
+	        	urlconnection.setRequestProperty(prop.getKey(), prop.getValue());
+            }
+	        
+	        urlconnection.setDoOutput(true);
+	        urlconnection.setDoInput(true);
+
+	        bos = new BufferedOutputStream(urlconnection.getOutputStream());
+	        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
+	        try {
+		        int i;
+		        // read byte by byte until end of stream
+		        while ((i = bis.read()) > 0) {
+		            bos.write(i);
+		        }
+		        bos.close();
+		        int responseCode = urlconnection.getResponseCode();
+	
+		        // Error messages below.
+		        if (responseCode >= 400) {
+		       //     String message = readErrorStream(urlconnection);
+		        	String message = " " + responseCode;
+		            throw new IOException("Error uploading " + file.getName() + " : " + message);
+		        } 
+	        }finally {
+	        	bis.close();
+	        }
+	    }
+	
+	  
+
+}

jsui/src/main/webapp/WEB-INF/web.xml

     <servlet-name>FileUploadServlet</servlet-name>
     <url-pattern>/FileUploadServlet</url-pattern>
   </servlet-mapping>
+   <servlet>
+    <description></description>
+    <display-name>ExternalUploadServlet</display-name>
+    <servlet-name>ExternalUploadServlet</servlet-name>
+    <servlet-class>org.genomespace.gsui.servlet.ExternalUploadServlet</servlet-class>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>ExternalUploadServlet</servlet-name>
+    <url-pattern>/ExternalUpload</url-pattern>
+  </servlet-mapping>
+  
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>Protected Context</web-resource-name>

jsui/src/main/webapp/css/TedsStyles.css

 #aboutFormatConvertersTable tr:nth-child(2n), #mptOrderToolTablebody tr:nth-child(2n+1) {
   background-color: #e8f2fe;
 }
+
+#aptUrlExample {
+	max-width: 320px !important;
+	width: 320px;
+}
+.aptHelpIcnButton {
+	display: block;
+	margin-left: auto;
+	margin-right: 0;
+	margin-top: 0 !important;
+	margin-bottom: auto;
+	float: right;
+	vertical-align:text-top;
+}
+
+.aptHelp {
+	margin-right: auto;
+	margin-left: 10;
+	margin-top: 0;
+	margin-bottom: auto;
+	border: 1px solid lightgrey;
+	width: 300px !important;
+	max-width: 300px !important;
+	scroll: auto;
+	padding: 3px;
+	background-color: #e8f2fe;
+	-moz-border-radius: 5px;
+	border-radius: 5px 5px 5px 5px;
+}
+.aptHelp td{
+	
+	align: left;
+}
+
+
+
+

jsui/src/main/webapp/gsui.html

 </div>
 
 <div id="addPrivateToolsDialog" style="display:none">
+   
     <table border="0px">
-    <tr><td>Name:</td><td><input type="text" name="aptName" id="aptName" size="35"></input><td><input type="hidden" name="aptInternalId" id="aptInternalId"/></td></tr>
+    <tr><td>Name:</td><td><input type="text" name="aptName" id="aptName" size="35"></input><input type="hidden" name="aptInternalId" id="aptInternalId"/><img  class="aptHelpIcnButton" src="images/Help.gif"/></td>
+    
+    <td rowspan="5" class="aptHelpTd"  valign="top" align="left"> <div style="display:none" class="aptHelp">
+	Enter the name, a brief description and the provider (typically an organization name such as 'Broad Institute'). 
+	The <B>Base URL</B> should be the page in the app you wish to have launched or the URL of a jnlp launch file for desktop applications.
+	The <b>Help URL</b> is optional but reccomended if you wil be sharing this app with others.
+	</div></td></tr>
+    
     <tr><td>Description:</td><td><input type="text" name="aptDescription" id="aptDescription" size="55"></input></td></tr>
     <tr><td>Tool Provider:</td><td><input type="text" name="aptAuthor" id="aptAuthor" size="35"></input></td></tr>
     <tr><td>Base URL:</td><td><input type="text" name="aptBaseUrl" id="aptBaseUrl" size="55"></input></td></tr>
     <tr><td>Help URL:</td><td><input type="text" name="aptHelpUrl" id="aptHelpUrl" size="55"></input></td></tr>
    
-    	<tr><td valign="top"><br/>File Parameter:</td><td>
+    	<tr><td valign="top"><br/>File Parameter:</td><td valign="top">
     	<table border="0" cellspacing="5">
     	<tr><td>Parameter name:<input type="text" name="aptFileParamName" id="aptFileParamName" size="4"></input></td><td>Required: <input type="checkbox" id="aptFileParamRequired"/></td></tr>
 	    
 	    <tr><td>Allow multiple files:<input type="checkbox" id="aptFileParamComposite"/></td><td>Multiple file Delimiter:<input type="text" name="aptFileParamDelimiter" id="aptFileParamDelimiter" size="4"></td>
 	    </tr>
-	     <tr><td colspan="2" style="color: grey;"><font size="0.75em">example call with dummy files</font><br/>&nbsp;<span id="aptUrlExample"></span></td></tr>
+	     <tr><td colspan="2" style="color: grey;"><font size="0.75em">example call with dummy files</font>
+	     <div  id="aptUrlExample" ></div></td></tr>
 	     <tr><td colspan="2"><div  id="aptFileFormatDiv">
 			<select multiple="multiple" id="aptFormats" name="aptFormats[]">
 			</select>
 			<a class="aptMailLink" href="mailto:gs-help@broadinstitute.org?subject=New%20file%20format%20request" >Request a new format be added to the available formats list.</a> 
 	    </div></td></tr>
 	     </table>
-	     </td></tr>
-	   <tr><td colspan="2" class="aptNote">&nbsp;&nbsp;If a file parameter is included this will show up as a tool, if not it will appear as a data source</td></tr>		
-    
-	
+	     <img  class="aptHelpIcnButton" src="images/Help.gif"/>
+	     </td>
+	     <td rowspan="1"  valign="top"><div style="display:none" class="aptHelp">
+	     <B>File parameters</B> (optional) are used to pass GenomeSpace file URLs to the tool when they are launched. 
+	     If a <B>File Parameter</B> is named, this tool will show up in the list of tools. If not it will show in the list of Data Sources.
+	     The parameter name will be added to the Base URL (as in the example call). If multiple files
+	     can be passed the the tool at once, the <b>Delimiter</b> will seperate the file URLs. 
+	     <b>File Formats</b> (optional) indicate what formats the tool accepts but will not prevent other files being sent to the tool.  
+	     Select as many as apply.
+	     </div></td></tr>
+	 
 	    <tr></tr>
     	
     <tr><td></td></tr>
         <input type="hidden" id="toolIconUrl" value="generic_tool.png"/>
      	<img height="30" width="30" id="toolIconPreview" src="images/tools/generic_tool.png"/><br/>
      	<form id="customIconUpload" action="toolicon"  enctype="multipart/form-data" method="post">
-     	<input type="file" name="icon" size="20"> </input>
-     	<input type="submit" value="Upload"></input>
+     	<input type="file" id="aptIconFileSelector" name="icon" size="20"> </input>
+     	<input type="submit" value="Upload" style="display:none;"></input>
      	</form>
-     
-     </td></tr>
+        <img class="aptHelpIcnButton" src="images/Help.gif"/>
+     </td>     <td rowspan="1"  valign="top"><div style="display:none" class="aptHelp">
+		Provide a custom <b>Icon</b> for your tool to use in the tool bar. You can use <b>gif</b>, <b>jpg</b>, and <b>png</b> files.
+		The icon will be scaled to 44x44 pixels on the toolbar and smaller in a few other dialogs.
+	
+	</div></td></tr>
     
     
      
-    <tr><td>Share with group:</td><td><select  id="editAPTGroup"> </select> <img id="aptOpenGroupsDialog" src="images/edit16.png" title="Manage Groups"/></td></tr>
-    <tr><td colspan="2" class="aptNote">&nbsp;&nbsp;You may only share this tool with members of a group you are a member of</td></tr>		
+    <tr><td>Share with group:</td>
+    <td><select  id="editAPTGroup"> </select> <img id="aptOpenGroupsDialog" src="images/edit16.png" title="Manage Groups"/></td>
+     <td rowspan="1"  valign="top"><div style="display:none" class="aptHelp">
+     You may only share private tools with groups you are a member of. 
+     Click on the <img src="images/edit16.png"/> icon to create or edit user groups</div></td></tr>
+    	
   </table>
-    
+   
     <br/>
    	    	
 </div>

jsui/src/main/webapp/js/manageTools.js

 				autoOpen: false,
 				modal: true, 
 				title: 'Add a Tool or Data Source',
-				width: '525px',
+				width: 'auto',
 				buttons: [
 					    	{
 					    		id: 'aptSavePrivateToolButton',
 			    } ]
 
 			});
-		   
+		   $('.aptHelpIcnButton').click(toggleAddToolHelp);
+		   $('.aptHelp').click(toggleAddToolHelp);
 		$('#aptFileParamName').change(setExampleUrl);
 		$('#aptFileParamDelimiter').change(setExampleUrl);
 		$('#aptFileParamComposite').change(setExampleUrl);
 			 beforeSubmit:  setIconPath,
 		     success:       iconSubmittedSuccess 
 		 }); 
+		 $('#aptIconFileSelector').change(function(e){
+			 $('#customIconUpload').submit();
+
+		 });
+		 
+		 
+		 
 }
 
 
 	  return retval;
 }
 
+function toggleAddToolHelp(){
+	$('.aptHelp').toggle();
+	$('.aptHelpIcnButton').toggle();
+}
 
 
-

jsui/src/main/webapp/openidLoginExample.html

+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon" >
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+	<META HTTP-EQUIV="Expires" CONTENT="-1">
+	<link href="css/jquery-ui-1.8.20.custom.css" rel="stylesheet"  type="text/css"/>
+	<link href="css/base.css" rel="stylesheet" type="text/css" />
+	<link href="css/TedsStyles.css" rel="stylesheet" type="text/css" />
+	<link href="css/multi-select.css" rel="stylesheet" type="text/css" />
+
+	  
+	<title>minimal login example</title>
+<div style="display: none">
+<!--  a hidden login form to force a login when there is no token found -->
+
+
+
+<form id="hiddenLoginForm" name="hiddenLoginForm" method="get" action="openIdClient">
+		<p />
+		<input type="submit" name="login" value="Login">
+		<input type="text" id="thisPageUrl" name="url" value=" <%=window.location%>"/>
+	</form>
+</div>
+  <script src="js/jquery-1.7.2.min.js" type="text/javascript"></script>
+  <script src="js/jquery-ui-1.8.20.custom.min.js" type="text/javascript"></script>
+  <script src="js/identity.js" type="text/javascript"></script> 
+  <script src="js/utilities.js" type="text/javascript"></script> 
+   
+  	
+   <script type="text/javascript">
+    var username;
+	var token;
+   
+   if (navigator.appName == 'Microsoft Internet Explorer') {
+	alert("Sorry, the GSUI does not yet work on InternetExplorer.  Please use Firefox or Chrome instead.");
+   }
+   
+    // set the callback url in case we need to login
+	$('#thisPageUrl').text(window.location);
+	$('#thisPageUrl').val(window.location);
+	
+	// synchronous call to get the token and username first
+	// should redirect to login if there are any problems
+	jQuery.ajax({
+        url:    'gslogin',
+        datatype: 'json',
+        cache: false, 
+        success: function(result){
+        	
+        	token = result.gstoken;
+    		username = result.gsusername;
+    		if (username == "null") {
+    			document.forms["hiddenLoginForm"].submit();
+    			$('#hiddenLoginForm').submit();
+    		} else {
+    			// logLogin();
+    		}
+    	 },
+        error: function(f ){
+     	 	$('#hiddenLoginForm').submit();
+        },
+        async:   false
+  });      
+
+	$(document).ready(function(){
+		
+		
+			
+			    $('#username').html(username);
+	});
+	 </script>
+ 
+</head>
+<body>
+
+
+ <div id="contentArea">
+
+
+<div class="genomespace">
+<div class="gs-web-header">
+		
+		<img class="small-logo" src="images/gssmalllogo2.png"  height="38" alt="GenomeSpace" />
+		
+		<div class="user">
+		   <a id="systemMessage" href="http://www.genomespace.org/system-status/">System Status</a>
+		   
+		   <span id="profileBtn"><span id="username"></span><img src="images/user.png" /></span>
+		 </div>
+		
+</div>
+
+<br/><br/><br/><br/>
+	
+We are here
+   		 
+
+</div>
+
+<div class="footer">
+<span class="footer_left">&copy;2012 <a href="http://www.broadinstitute.org">The Broad Institute of MIT and Harvard</a></span>
+<span class="footer_right">
+this is the footer</span>
+</div>
+</div>
+
+</body>
+</html>

jsui/src/main/webapp/upload/images/closedfolder.png

Added
New image

jsui/src/main/webapp/upload/images/openedfolder.png

Added
New image

jsui/src/main/webapp/upload/loadUrlToGenomespace.html

+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+   "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+	<link rel="shortcut icon" href="../images/favicon.ico" type="image/x-icon" >
+	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+	<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+	<META HTTP-EQUIV="Expires" CONTENT="-1">
+	<link href="../css/jquery-ui-1.8.20.custom.css" rel="stylesheet"  type="text/css"/>
+	<link href="../css/multi-select.css" rel="stylesheet" type="text/css" />
+	<link href="./upload.css" rel="stylesheet" type="text/css" />
+
+	  
+	<title>Upload URL to GenomeSpace</title>
+
+  <script src="../js/jquery-1.7.2.min.js" type="text/javascript"></script>
+  <script src="../js/jquery-ui-1.8.20.custom.min.js" type="text/javascript"></script>
+
+
+   <div style="display: none">
+<!--  a hidden login form to force a login when there is no token found -->
+ 	<form id="hiddenLoginForm" name="hiddenLoginForm" method="get" action="/jsui/openIdClient">
+		<p />
+		<input type="submit" name="login" value="Login">
+		<input type="text" id="thisPageUrl" name="url" value=" <%=window.location%>"/>
+	</form>
+	</div>
+   <script type="text/javascript">
+    var LoginUrl = "/openIdClient";
+    var username;
+	var token;
+	var dmUrlBase = null;
+	var dmUrlNoVersion = null;
+
+   if (navigator.appName == 'Microsoft Internet Explorer') {
+	alert("Sorry, the GSUI does not yet work on InternetExplorer.  Please use Firefox or Chrome instead.");
+   }
+   
+    // set the callback url in case we need to login
+	$('#thisPageUrl').text(window.location);
+	$('#thisPageUrl').val(window.location);
+	// synchronous call to get the token and username first
+	// should redirect to login if there are any problems
+	jQuery.ajax({
+        url:    '../gslogin',
+        datatype: 'json',
+        cache: false, 
+        success: function(result){
+        	
+        	token = result.gstoken;
+    		username = result.gsusername;
+    		dmUrlBase = result.dm+"/"+result.api;
+    		dmUrlNoVersion = result.dm;
+    		if (username == "null") {
+    			document.forms["hiddenLoginForm"].submit();
+    			$('#hiddenLoginForm').submit();
+    		} else {
+    			// logLogin();
+    		}
+    	 },
+        error: function(f ){
+     	 	$('#hiddenLoginForm').submit();
+        },
+        async:   false
+  });      
+
+	$(document).ready(function(){
+		// set some standard options for all ajax requests
+		// these are to allow CORS requests to go through
+		$.ajaxSetup({
+			xhrFields: {
+	            withCredentials: true
+	        },
+	        mozBackgroundRequest: true,
+	        crossDomain: true
+		});
+		// set the wait cursor for all ajax requests
+		$("html").bind("ajaxStart", function(){  
+			var x = $(this);
+			setTimeout(function(){	x.addClass('waiting');}, 1);});
+		$("html").bind("ajaxComplete", function(){
+			var x = $(this);
+			setTimeout(function(){x.removeClass('waiting');}, 1);});  
+		
+		
+	    $('#username').html(username);
+		var uploadUrl = getUrlParameter("uploadUrl");
+	
+		
+		var inputLink = $('<a href="'+decodeURIComponent(uploadUrl)+'" target="_blank">'+getUrlDisplayString()+'</a>');
+		$("#gsupUploadUrl").append(inputLink);
+
+		$('#submitUpload').click(submitUrlUpload);
+		$('#gsupSaveFileName').val(getDefaultFilename(uploadUrl));
+			
+		// get the root dir
+		dmGetDirectory('Home/'+username, rootDirectoryLoaded);
+	});
+	
+	function getUrlDisplayString(){
+		var providedFilename = getUrlParameter("fileName");
+		if (providedFilename != null) return providedFilename;
+		else return decodeURIComponent(getUrlParameter("uploadUrl"));
+	}
+	
+	// guess a file name for this file based on the url
+	function getDefaultFilename(anUrl){
+		var providedFilename = getUrlParameter("fileName");
+		if (providedFilename != null) return providedFilename;
+		
+		var decodedUrl = decodeURIComponent(anUrl);
+		var idxStart = decodedUrl.lastIndexOf('/') + 1;
+		var idxEnd = decodedUrl.lastIndexOf('?');
+		if (idxEnd == -1) {
+			idxEnd = decodedUrl.length;
+		}
+		var defaultName =  decodedUrl.substring(idxStart, idxEnd);
+		if (defaultName.length <= 0) defaultName="someFile.txt";
+		return defaultName;
+	}
+	
+	
+	
+	function rootDirectoryLoaded(data){
+		var parent = $('#gsupDirectoryUL');
+		$('#gsupDestinationPath').html(data.directory.path);
+		var dirName = $('<span>'+data.directory.path+'</span>');
+		var dir = $('<li id="'+data.directory.path+'"></li>');
+		dir.append(dirName)
+		$(dir).addClass("gsRootDir");
+		dirName.click(function(){
+			$('.selectedTreeNode').removeClass('selectedTreeNode');
+			$('#gsupDestinationPath').html(data.directory.path);
+			$(dir).addClass('selectedTreeNode');
+		});
+		parent.append(dir);
+		var subDirs = new Array();
+		$.each(data.contents, function(k, dirChild){
+			if (dirChild.isDirectory == true) subDirs.push(dirChild);
+		});
+		if (subDirs.length > 0){
+			var subList = $('<ul></ul>');
+			subList.addClass("tree");
+			subList.addClass("gsOpenedDir");
+			$(subList).attr("path", data.directory.path);
+			dir.append(subList);
+			$.each(subDirs, function(k, dirChild){
+				var subdir = $('<li id="'+dirChild.name+'">'+dirChild.name+'</li>');
+				$(subList).append(subdir);
+				$(subdir).attr("path", dirChild.path);
+				$(subdir).addClass("tree");
+				$(subdir).addClass("gsClosedDir");
+				$(subdir).click(function(e){
+					dmGetDirectory(dirChild.path, subDirectoryClicked);
+					});
+			});
+			
+		}		
+		$(dir).addClass('selectedTreeNode');
+	}
+		
+	
+	
+	function subDirectoryClicked(data){
+		var parent = $('li [path="'+data.directory.path+'"]');
+		var alreadyLoaded = $(parent).attr("gsDirLoaded");
+		$('#gsupDestinationPath').html(data.directory.path);
+		
+		$('.selectedTreeNode').removeClass('selectedTreeNode');
+		
+		if (alreadyLoaded != "true"){
+			$(parent).removeClass("gsClosedDir");
+			var subDirs = new Array();
+			$.each(data.contents, function(k, dirChild){
+				if (dirChild.isDirectory == true) subDirs.push(dirChild);
+			});
+			
+			if (subDirs.length > 0){
+				var subList = $('<ul></ul>');
+				subList.addClass("tree");
+				parent.append(subList);
+				$.each(subDirs, function(k, dirChild){
+					var subdir = $('<li id="'+dirChild.name+'">'+dirChild.name+'</li>');
+					subdir.addClass("gsClosedDir");
+					$(subList).append(subdir);
+					$(subdir).attr("path", dirChild.path);
+					$(subdir).addClass("tree");
+					$(subdir).click(function(e){
+						e.stopPropagation();
+						dmGetDirectory(dirChild.path, subDirectoryClicked);
+					});
+				});
+				
+			}		
+			$(parent).attr("gsDirLoaded", "true");
+			$(parent).attr("gsDirOpened", "true");
+			$(parent).addClass("gsOpenedDir");
+		} else {
+			// its loaded so hide it if open and show it if closed
+			var alreadyOpened = $(parent).attr("gsDirOpened");
+			if (alreadyOpened == "true") {
+				// its open so close (hide) the children
+				$(parent).attr("gsDirOpened", "false");
+				$(parent).find("> ul").hide();
+				
+				$(parent).removeClass("gsOpenedDir");
+				$(parent).addClass("gsClosedDir");
+			} else {
+				// its closed so open (show) the children
+				$(parent).attr("gsDirOpened", "true");
+				$(parent).find("> ul").show();
+				
+				$(parent).addClass("gsOpenedDir");
+				$(parent).removeClass("gsClosedDir");
+			}
+			
+			
+		}
+		
+		$(parent).addClass('selectedTreeNode');
+	
+		
+	}
+	
+	function submitUrlUpload(e){
+		e.preventDefault();
+		e.stopPropagation();
+		
+		var destinationPath = $('#gsupDestinationPath').html();
+		var fileName = $('#gsupSaveFileName').val();
+		var urlToSave = getUrlParameter("uploadUrl");
+		var submitUrl = '../ExternalUpload?fileName='+fileName+"&uploadTo="+destinationPath+"&sourceUrl="+urlToSave;
+		
+		jQuery.ajax({
+	        url:    submitUrl,
+	        datatype: 'json',
+	        cache: false, 
+	        success: function(result){
+	        	$('#gsUploadDiv').hide();
+	        	$('#gsMessageDiv').html(getUrlDisplayString() +" has been saved to GenomeSpace as " + destinationPath +"/" + fileName );
+	        	$('#gsMessageDiv').show();
+	    	 },
+	        error: function(f ){
+	        	alert('Failure saving ' + urlToSave);
+	        },
+	        async:   true
+	  });  
+		
+	}
+	
+	
+	
+	 </script>
+     <script src="../js/identity.js" type="text/javascript"></script> 
+     <script src="../js/utilities.js" type="text/javascript"></script> 
+     <script src="../js/dm.js" type="text/javascript"></script> 
+</head>
+<body>
+<div id="contentArea">
+<div id="gsUploadDiv">
+Saving file <span id="gsupUploadUrl"></span> to GenomeSpace<br/>
+<div id="gsupDirectoryTree">
+ <ul id="gsupDirectoryUL" class="tree"></ul>
+</div>
+<span id="gsupDestinationPath"></span>/&nbsp;<input id="gsupSaveFileName" size="40" ></input><br/>
+<a href="#" id="submitUpload">Submit</a>
+</div>
+<div id="gsMessageDiv" style="display:none">
+</div>
+</div>
+</body>
+</html>

jsui/src/main/webapp/upload/upload.css

+img { border: none; }
+ 
+.selectedTreeNode {
+	font-weight:bold;
+}
+.selectedTreeNode li  {
+	font-weight:normal !important;
+}
+
+
+ul.tree {
+	list-style: none;
+}
+
+
+li.tree,li.gsClosedDir, li.gsOpenedDir, li.gsRootDir {
+	margin-left: -15px;
+	padding-left: 17px;
+	list-style: none;
+	cursor: pointer;
+}
+
+li.gsRootDir {
+	background: url(images/openedfolder.png) no-repeat;
+}
+
+li.gsClosedDir {
+	background: url(images/closedfolder.png) no-repeat;
+
+}
+
+li.gsOpenedDir {
+	background: url(images/openedfolder.png) no-repeat !important;
+}
+
+
+/* CSS Tree menu styles */
+ul.tree
+{
+	padding: 0 0 0 20px;
+	width: 300px;
+}
+
+#gsupDirectoryTree {
+	border: 1px solid ;
+	border-color: #FCC !important;
+	max-height: 170px !important;
+	min-height: 170px !important;
+	width: 350px;
+	max-width: 350px !important;
+	overflow-y: auto  !important;
+	overflow-x: auto  !important;
+}
+
+#gsUploadDiv {
+	max-height: 300px !important;
+	width: 380px;
+	max-width: 370px !important;	
+}
+
+
+	
+	

jsui/src/main/webapp/uploaddialog.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Testing GS </title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+        <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
+        <META HTTP-EQUIV="Expires" CONTENT="-1">
+        <link href="http://www.broadinstitute.org/~liefeld/jquery-ui-1.8.20.custom.css" rel="stylesheet"  type="text/css"/>
+        <script src="http://www.broadinstitute.org/~liefeld/jquery-1.7.2.min.js" type="text/javascript"></script>
+    <script src="http://www.broadinstitute.org/~liefeld/jquery-ui-1.8.20.custom.min.js" type="text/javascript"></script>
+        <script type="text/javascript">
+                $(document).ready(function(){
+                        $('#uploadLink').click(function(e){
+                                e.preventDefault();
+                                var gsUploadUrl = "https://localhost:6443/jsui/upload/loadUrlToGenomespace.html?uploadUrl=";
+                                var dest = encodeURIComponent("http://www.broadinstitute.org/ccle/downloadFile/DefaultSystemRoot/exp_10/ds_23/CCLE_Oncomap3_2012-04-09.maf?downloadff=true&fileId=3000");
+
+                                $('#gsUploadFrame').attr('src', gsUploadUrl + dest + "&fileName=IsetThisName.txt");
+                                $('#uploadDialog').dialog('open');
+                        });
+                        $('#uploadDialog').dialog({
+                                modal: true,
+                                title: "Upload to GenomeSpace",
+                                autoOpen: false,
+                                width: 450,
+                                height: 470,
+                                buttons: [
+                                {
+                                text: 'Close',
+                                click: function(){ $(this).dialog("close");  }
+                            } ]
+                        });
+
+
+                });
+
+
+   </script>
+</head>
+<body>
+<div id="uploadLink">Click here to upload</div>
+<div id="uploadDialog" style="display:none">
+<iframe
+    id="gsUploadFrame"
+        height="380"
+        width="400"
+        frameborder="0">
+        </iframe>
+</div>
+
+</body>
+</html>