~ better web app
authorAlexandre Bertails <bertails@w3.org>
Tue, 03 May 2011 10:23:36 -0400
changeset 369 b06800284060
parent 368 fff24385e340
child 370 3a9aa3b600f8
~ better web app
directmapping-webapp/src/main/resources/toserve/jquery.watermark.js
directmapping-webapp/src/main/scala/Servlet.scala
directmapping-webapp/src/main/scala/bootstrap/liftweb/Boot.scala
directmapping-webapp/src/main/webapp/index.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/directmapping-webapp/src/main/resources/toserve/jquery.watermark.js	Tue May 03 10:23:36 2011 -0400
@@ -0,0 +1,563 @@
+/*	
+	Watermark plugin for jQuery
+	Version: 3.1.3
+	http://jquery-watermark.googlecode.com/
+
+	Copyright (c) 2009-2011 Todd Northrop
+	http://www.speednet.biz/
+	
+	March 22, 2011
+
+	Requires:  jQuery 1.2.3+
+	
+	Dual licensed under the MIT or GPL Version 2 licenses.
+	See mit-license.txt and gpl2-license.txt in the project root for details.
+------------------------------------------------------*/
+
+(function ($, window, undefined) {
+
+var
+	// String constants for data names
+	dataFlag = "watermark",
+	dataClass = "watermarkClass",
+	dataFocus = "watermarkFocus",
+	dataFormSubmit = "watermarkSubmit",
+	dataMaxLen = "watermarkMaxLength",
+	dataPassword = "watermarkPassword",
+	dataText = "watermarkText",
+	
+	// Copy of native jQuery regex use to strip return characters from element value
+	rreturn = /\r/g,
+
+	// Includes only elements with watermark defined
+	selWatermarkDefined = "input:data(" + dataFlag + "),textarea:data(" + dataFlag + ")",
+
+	// Includes only elements capable of having watermark
+	selWatermarkAble = "input:text,input:password,input[type=search],input:not([type]),textarea",
+	
+	// triggerFns:
+	// Array of function names to look for in the global namespace.
+	// Any such functions found will be hijacked to trigger a call to
+	// hideAll() any time they are called.  The default value is the
+	// ASP.NET function that validates the controls on the page
+	// prior to a postback.
+	// 
+	// Am I missing other important trigger function(s) to look for?
+	// Please leave me feedback:
+	// http://code.google.com/p/jquery-watermark/issues/list
+	triggerFns = [
+		"Page_ClientValidate"
+	],
+	
+	// Holds a value of true if a watermark was displayed since the last
+	// hideAll() was executed. Avoids repeatedly calling hideAll().
+	pageDirty = false,
+	
+	// Detects if the browser can handle native placeholders
+	hasNativePlaceholder = ("placeholder" in document.createElement("input"));
+
+// Best practice: this plugin adds only one method to the jQuery object.
+// Also ensures that the watermark code is only added once.
+$.watermark = $.watermark || {
+
+	// Current version number of the plugin
+	version: "3.1.3",
+		
+	runOnce: true,
+	
+	// Default options used when watermarks are instantiated.
+	// Can be changed to affect the default behavior for all
+	// new or updated watermarks.
+	options: {
+		
+		// Default class name for all watermarks
+		className: "watermark",
+		
+		// If true, plugin will detect and use native browser support for
+		// watermarks, if available. (e.g., WebKit's placeholder attribute.)
+		useNative: true,
+		
+		// If true, all watermarks will be hidden during the window's
+		// beforeunload event. This is done mainly because WebKit
+		// browsers remember the watermark text during navigation
+		// and try to restore the watermark text after the user clicks
+		// the Back button. We can avoid this by hiding the text before
+		// the browser has a chance to save it. The regular unload event
+		// was tried, but it seems the browser saves the text before
+		// that event kicks off, because it didn't work.
+		hideBeforeUnload: true
+	},
+	
+	// Hide one or more watermarks by specifying any selector type
+	// i.e., DOM element, string selector, jQuery matched set, etc.
+	hide: function (selector) {
+		$(selector).filter(selWatermarkDefined).each(
+			function () {
+				$.watermark._hide($(this));
+			}
+		);
+	},
+	
+	// Internal use only.
+	_hide: function ($input, focus) {
+		var elem = $input[0],
+			inputVal = (elem.value || "").replace(rreturn, ""),
+			inputWm = $input.data(dataText) || "",
+			maxLen = $input.data(dataMaxLen) || 0,
+			className = $input.data(dataClass);
+	
+		if ((inputWm.length) && (inputVal == inputWm)) {
+			elem.value = "";
+			
+			// Password type?
+			if ($input.data(dataPassword)) {
+				
+				if (($input.attr("type") || "") === "text") {
+					var $pwd = $input.data(dataPassword) || [], 
+						$wrap = $input.parent() || [];
+						
+					if (($pwd.length) && ($wrap.length)) {
+						$wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
+						$wrap[0].appendChild($pwd[0]);
+						$input = $pwd;
+					}
+				}
+			}
+			
+			if (maxLen) {
+				$input.attr("maxLength", maxLen);
+				$input.removeData(dataMaxLen);
+			}
+		
+			if (focus) {
+				$input.attr("autocomplete", "off");  // Avoid NS_ERROR_XPC_JS_THREW_STRING error in Firefox
+				
+				window.setTimeout(
+					function () {
+						$input.select();  // Fix missing cursor in IE
+					}
+				, 1);
+			}
+		}
+		
+		className && $input.removeClass(className);
+	},
+	
+	// Display one or more watermarks by specifying any selector type
+	// i.e., DOM element, string selector, jQuery matched set, etc.
+	// If conditions are not right for displaying a watermark, ensures that watermark is not shown.
+	show: function (selector) {
+		$(selector).filter(selWatermarkDefined).each(
+			function () {
+				$.watermark._show($(this));
+			}
+		);
+	},
+	
+	// Internal use only.
+	_show: function ($input) {
+		var elem = $input[0],
+			val = (elem.value || "").replace(rreturn, ""),
+			text = $input.data(dataText) || "",
+			type = $input.attr("type") || "",
+			className = $input.data(dataClass);
+
+		if (((val.length == 0) || (val == text)) && (!$input.data(dataFocus))) {
+			pageDirty = true;
+		
+			// Password type?
+			if ($input.data(dataPassword)) {
+				
+				if (type === "password") {
+					var $pwd = $input.data(dataPassword) || [],
+						$wrap = $input.parent() || [];
+						
+					if (($pwd.length) && ($wrap.length)) {
+						$wrap[0].removeChild($input[0]); // Can't use jQuery methods, because they destroy data
+						$wrap[0].appendChild($pwd[0]);
+						$input = $pwd;
+						$input.attr("maxLength", text.length);
+						elem = $input[0];
+					}
+				}
+			}
+		
+			// Ensure maxLength big enough to hold watermark (input of type="text" or type="search" only)
+			if ((type === "text") || (type === "search")) {
+				var maxLen = $input.attr("maxLength") || 0;
+				
+				if ((maxLen > 0) && (text.length > maxLen)) {
+					$input.data(dataMaxLen, maxLen);
+					$input.attr("maxLength", text.length);
+				}
+			}
+            
+			className && $input.addClass(className);
+			elem.value = text;
+		}
+		else {
+			$.watermark._hide($input);
+		}
+	},
+	
+	// Hides all watermarks on the current page.
+	hideAll: function () {
+		if (pageDirty) {
+			$.watermark.hide(selWatermarkAble);
+			pageDirty = false;
+		}
+	},
+	
+	// Displays all watermarks on the current page.
+	showAll: function () {
+		$.watermark.show(selWatermarkAble);
+	}
+};
+
+$.fn.watermark = $.fn.watermark || function (text, options) {
+	///	<summary>
+	///		Set watermark text and class name on all input elements of type="text/password/search" and
+	/// 	textareas within the matched set. If className is not specified in options, the default is
+	/// 	"watermark". Within the matched set, only input elements with type="text/password/search"
+	/// 	and textareas are affected; all other elements are ignored.
+	///	</summary>
+	///	<returns type="jQuery">
+	///		Returns the original jQuery matched set (not just the input and texarea elements).
+	/// </returns>
+	///	<param name="text" type="String">
+	///		Text to display as a watermark when the input or textarea element has an empty value and does not
+	/// 	have focus. The first time watermark() is called on an element, if this argument is empty (or not
+	/// 	a String type), then the watermark will have the net effect of only changing the class name when
+	/// 	the input or textarea element's value is empty and it does not have focus.
+	///	</param>
+	///	<param name="options" type="Object" optional="true">
+	///		Provides the ability to override the default watermark options ($.watermark.options). For backward
+	/// 	compatibility, if a string value is supplied, it is used as the class name that overrides the class
+	/// 	name in $.watermark.options.className. Properties include:
+	/// 		className: When the watermark is visible, the element will be styled using this class name.
+	/// 		useNative (Boolean or Function): Specifies if native browser support for watermarks will supersede
+	/// 			plugin functionality. If useNative is a function, the return value from the function will
+	/// 			determine if native support is used. The function is passed one argument -- a jQuery object
+	/// 			containing the element being tested as the only element in its matched set -- and the DOM
+	/// 			element being tested is the object on which the function is invoked (the value of "this").
+	///	</param>
+	/// <remarks>
+	///		The effect of changing the text and class name on an input element is called a watermark because
+	///		typically light gray text is used to provide a hint as to what type of input is required. However,
+	///		the appearance of the watermark can be something completely different: simply change the CSS style
+	///		pertaining to the supplied class name.
+	///		
+	///		The first time watermark() is called on an element, the watermark text and class name are initialized,
+	///		and the focus and blur events are hooked in order to control the display of the watermark.  Also, as
+	/// 	of version 3.0, drag and drop events are hooked to guard against dropped text being appended to the
+	/// 	watermark.  If native watermark support is provided by the browser, it is detected and used, unless
+	/// 	the useNative option is set to false.
+	///		
+	///		Subsequently, watermark() can be called again on an element in order to change the watermark text
+	///		and/or class name, and it can also be called without any arguments in order to refresh the display.
+	///		
+	///		For example, after changing the value of the input or textarea element programmatically, watermark()
+	/// 	should be called without any arguments to refresh the display, because the change event is only
+	/// 	triggered by user actions, not by programmatic changes to an input or textarea element's value.
+	/// 	
+	/// 	The one exception to programmatic updates is for password input elements:  you are strongly cautioned
+	/// 	against changing the value of a password input element programmatically (after the page loads).
+	/// 	The reason is that some fairly hairy code is required behind the scenes to make the watermarks bypass
+	/// 	IE security and switch back and forth between clear text (for watermarks) and obscured text (for
+	/// 	passwords).  It is *possible* to make programmatic changes, but it must be done in a certain way, and
+	/// 	overall it is not recommended.
+	/// </remarks>
+	
+	if (!this.length) {
+		return this;
+	}
+	
+	var hasClass = false,
+		hasText = (typeof(text) === "string");
+	
+	if (hasText) {
+		text = text.replace(rreturn, "");
+	}
+	
+	if (typeof(options) === "object") {
+		hasClass = (typeof(options.className) === "string");
+		options = $.extend({}, $.watermark.options, options);
+	}
+	else if (typeof(options) === "string") {
+		hasClass = true;
+		options = $.extend({}, $.watermark.options, {className: options});
+	}
+	else {
+		options = $.watermark.options;
+	}
+	
+	if (typeof(options.useNative) !== "function") {
+		options.useNative = options.useNative? function () { return true; } : function () { return false; };
+	}
+	
+	return this.each(
+		function () {
+			var $input = $(this);
+			
+			if (!$input.is(selWatermarkAble)) {
+				return;
+			}
+			
+			// Watermark already initialized?
+			if ($input.data(dataFlag)) {
+			
+				// If re-defining text or class, first remove existing watermark, then make changes
+				if (hasText || hasClass) {
+					$.watermark._hide($input);
+			
+					if (hasText) {
+						$input.data(dataText, text);
+					}
+					
+					if (hasClass) {
+						$input.data(dataClass, options.className);
+					}
+				}
+			}
+			else {
+			
+				// Detect and use native browser support, if enabled in options
+				if (
+					(hasNativePlaceholder)
+					&& (options.useNative.call(this, $input))
+					&& (($input.attr("tagName") || "") !== "TEXTAREA")
+				) {
+					// className is not set because current placeholder standard doesn't
+					// have a separate class name property for placeholders (watermarks).
+					if (hasText) {
+						$input.attr("placeholder", text);
+					}
+					
+					// Only set data flag for non-native watermarks
+					// [purposely commented-out] -> $input.data(dataFlag, 1);
+					return;
+				}
+				
+				$input.data(dataText, hasText? text : "");
+				$input.data(dataClass, options.className);
+				$input.data(dataFlag, 1); // Flag indicates watermark was initialized
+				
+				// Special processing for password type
+				if (($input.attr("type") || "") === "password") {
+					var $wrap = $input.wrap("<span>").parent(),
+						$wm = $($wrap.html().replace(/type=["']?password["']?/i, 'type="text"'));
+					
+					$wm.data(dataText, $input.data(dataText));
+					$wm.data(dataClass, $input.data(dataClass));
+					$wm.data(dataFlag, 1);
+					$wm.attr("maxLength", text.length);
+					
+					$wm.focus(
+						function () {
+							$.watermark._hide($wm, true);
+						}
+					).bind("dragenter",
+						function () {
+							$.watermark._hide($wm);
+						}
+					).bind("dragend",
+						function () {
+							window.setTimeout(function () { $wm.blur(); }, 1);
+						}
+					);
+					$input.blur(
+						function () {
+							$.watermark._show($input);
+						}
+					).bind("dragleave",
+						function () {
+							$.watermark._show($input);
+						}
+					);
+					
+					$wm.data(dataPassword, $input);
+					$input.data(dataPassword, $wm);
+				}
+				else {
+					
+					$input.focus(
+						function () {
+							$input.data(dataFocus, 1);
+							$.watermark._hide($input, true);
+						}
+					).blur(
+						function () {
+							$input.data(dataFocus, 0);
+							$.watermark._show($input);
+						}
+					).bind("dragenter",
+						function () {
+							$.watermark._hide($input);
+						}
+					).bind("dragleave",
+						function () {
+							$.watermark._show($input);
+						}
+					).bind("dragend",
+						function () {
+							window.setTimeout(function () { $.watermark._show($input); }, 1);
+						}
+					).bind("drop",
+						// Firefox makes this lovely function necessary because the dropped text
+						// is merged with the watermark before the drop event is called.
+						function (evt) {
+							var elem = $input[0],
+								dropText = evt.originalEvent.dataTransfer.getData("Text");
+							
+							if ((elem.value || "").replace(rreturn, "").replace(dropText, "") === $input.data(dataText)) {
+								elem.value = dropText;
+							}
+							
+							$input.focus();
+						}
+					);
+				}
+				
+				// In order to reliably clear all watermarks before form submission,
+				// we need to replace the form's submit function with our own
+				// function.  Otherwise watermarks won't be cleared when the form
+				// is submitted programmatically.
+				if (this.form) {
+					var form = this.form,
+						$form = $(form);
+					
+					if (!$form.data(dataFormSubmit)) {
+						$form.submit($.watermark.hideAll);
+						
+						// form.submit exists for all browsers except Google Chrome
+						// (see "else" below for explanation)
+						if (form.submit) {
+							$form.data(dataFormSubmit, form.submit);
+							
+							form.submit = (function (f, $f) {
+								return function () {
+									var nativeSubmit = $f.data(dataFormSubmit);
+									
+									$.watermark.hideAll();
+									
+									if (nativeSubmit.apply) {
+										nativeSubmit.apply(f, Array.prototype.slice.call(arguments));
+									}
+									else {
+										nativeSubmit();
+									}
+								};
+							})(form, $form);
+						}
+						else {
+							$form.data(dataFormSubmit, 1);
+							
+							// This strangeness is due to the fact that Google Chrome's
+							// form.submit function is not visible to JavaScript (identifies
+							// as "undefined").  I had to invent a solution here because hours
+							// of Googling (ironically) for an answer did not turn up anything
+							// useful.  Within my own form.submit function I delete the form's
+							// submit function, and then call the non-existent function --
+							// which, in the world of Google Chrome, still exists.
+							form.submit = (function (f) {
+								return function () {
+									$.watermark.hideAll();
+									delete f.submit;
+									f.submit();
+								};
+							})(form);
+						}
+					}
+				}
+			}
+			
+			$.watermark._show($input);
+		}
+	);
+};
+
+// The code included within the following if structure is guaranteed to only run once,
+// even if the watermark script file is included multiple times in the page.
+if ($.watermark.runOnce) {
+	$.watermark.runOnce = false;
+
+	$.extend($.expr[":"], {
+
+		// Extends jQuery with a custom selector - ":data(...)"
+		// :data(<name>)  Includes elements that have a specific name defined in the jQuery data
+		// collection. (Only the existence of the name is checked; the value is ignored.)
+		// A more sophisticated version of the :data() custom selector originally part of this plugin
+		// was removed for compatibility with jQuery UI. The original code can be found in the SVN
+		// source listing in the file, "jquery.data.js".
+		data: function( elem, i, match ) {
+			return !!$.data( elem, match[ 3 ] );
+		}
+	});
+
+	// Overloads the jQuery .val() function to return the underlying input value on
+	// watermarked input elements.  When .val() is being used to set values, this
+	// function ensures watermarks are properly set/removed after the values are set.
+	// Uses self-executing function to override the default jQuery function.
+	(function (valOld) {
+
+		$.fn.val = function () {
+			
+			// Best practice: return immediately if empty matched set
+			if ( !this.length ) {
+				return arguments.length? this : undefined;
+			}
+
+			// If no args, then we're getting the value of the first element;
+			// otherwise we're setting values for all elements in matched set
+			if ( !arguments.length ) {
+
+				// If element is watermarked, get the underlying value;
+				// otherwise use native jQuery .val()
+				if ( this.data(dataFlag) ) {
+					var v = (this[0].value || "").replace(rreturn, "");
+					return (v === (this.data(dataText) || ""))? "" : v;
+				}
+				else {
+					return valOld.apply( this, arguments );
+				}
+			}
+			else {
+				valOld.apply( this, arguments );
+				$.watermark.show(this);
+				return this;
+			}
+		};
+
+	})($.fn.val);
+	
+	// Hijack any functions found in the triggerFns list
+	if (triggerFns.length) {
+
+		// Wait until DOM is ready before searching
+		$(function () {
+			var i, name, fn;
+		
+			for (i=triggerFns.length-1; i>=0; i--) {
+				name = triggerFns[i];
+				fn = window[name];
+				
+				if (typeof(fn) === "function") {
+					window[name] = (function (origFn) {
+						return function () {
+							$.watermark.hideAll();
+							return origFn.apply(null, Array.prototype.slice.call(arguments));
+						};
+					})(fn);
+				}
+			}
+		});
+	}
+
+	$(window).bind("beforeunload", function () {
+		if ($.watermark.options.hideBeforeUnload) {
+			$.watermark.hideAll();
+		}
+	});
+}
+
+})(jQuery, window);
--- a/directmapping-webapp/src/main/scala/Servlet.scala	Sun May 01 19:37:10 2011 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,212 +0,0 @@
-package org.w3.directmapping.servlet
-
-import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} 
-import scala.xml.XML
-import scala.xml.dtd.{DocType, PublicID}
-
-import org.w3.rdf._
-import org.w3.rdb.RDB._
-import org.w3.sql
-import org.w3.rdf.turtle.TurtleModule
-import org.w3.directmapping.DirectMappingModule
-import java.io.File
-
-import org.w3.rdf.jena._
-
-import java.util.regex._ 
-
-object DirectMappingWebapp {
-
-  val defaultSQL = QueryManager.getQueries("defaultSQL")
-
-  val encoding = "utf-8"
-
-  val Style = """
-    #sql { background-color: #e7e7ff; float:left; border: thin solid #888888; padding: 1em; }
-    #result { background-color: #eee; float:left; border: thin solid #888888; padding: 1em; }
-    .clear { clear:both; }
-    input { margin-bottom: -1em; }
-"""
-
-  def format(varr:String, sql:String):String = {
-    val formattedSQL = sql.replaceAll("\n+$", "").replaceAll("\n", "\\\\n\\\\\n")
-    "var " + varr + " = '" + formattedSQL + "';"
-  }
-
-  def validJSvar(varr:String) = {
-    if ("^[0-9]".r.findFirstIn(varr).isDefined)
-      "_" + varr
-    else
-      varr
-  }
-
-  val Script:String = QueryManager.getQueries map { case (varr, sql) => format(validJSvar(varr), sql) } mkString "\n\n"
-
-  def renderVar(varr:String) = 
-    <p><input value={ varr } type="button" onclick={ "document.getElementById('sql').value = " + validJSvar(varr) + ";" } /></p>
-
-}
-
-import DirectMappingWebapp._
-
-class DirectMappingWebapp extends HttpServlet with JenaModel with DirectMappingModule with TurtleModule {
-
-  import DirectMapping._
-
-  val SQLParser = sql.SqlParser()
-
-  val turtleParser = new TurtleParser { }
-
-  def jenaSerializer(g:Graph):String = {
-    val m = com.hp.hpl.jena.rdf.model.ModelFactory.createModelForGraph(g.jenaGraph)
-    val s = new java.io.StringWriter
-    m.write(s, "TURTLE")
-    s.toString
-//     m.write(s, "N-TRIPLE")
-//     val r = s.toString
-// println("r: " + r)
-// val p = Pattern.compile("\\\\u([0-9A-F]{4})").matcher(r)
-// val sb = new StringBuffer(r.size) ; val rsb = new StringBuffer(4)
-
-// while (p.find) { rsb.replace(0, rsb.length, p.group(1)) ; p.appendReplacement(sb, Character(rsb)) }
-// p.appendTail(sb)
-//     sb.toString
-  }
-
-  def minEncodeElement (minEncode:Boolean):scala.xml.Elem =
-    if (minEncode) <input name="minEncode" checked="on" type="checkbox" />
-    else <input name="minEncode" type="checkbox" />
-
-  override def doPost(request:HttpServletRequest, response:HttpServletResponse) = {
-    val minEncode = request.getParameter("minEncode") == "on"
-    request.getParameter("sql") match {
-      case null | "" => processIndex(request, response, minEncode)
-      case sql       => processSQL(request, response, sql, minEncode)
-    }
-  }
-
-  override def doGet(request:HttpServletRequest, response:HttpServletResponse) = doPost(request, response)
-
-  val xhtmlDoctype = DocType("html",
-                             PublicID("-//W3C//DTD XHTML 1.0 Strict//EN",
-                                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"),
-                             Nil)
-
-  def render(sql:String, minEncode:Boolean, result:Option[String]) =
-    <html xmlns="http://www.w3.org/1999/xhtml">
-      <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-        <title>Direct Mapping Demo</title>
-      <style type="text/css" media="print, screen and (min-width: 481px)">{ Style }
-      </style>
-      <script type="text/javascript">{ Script }
-      </script>
-      </head>
-      <body>
-        <h1>Direct Mapping Demo</h1>
-	<p>Input some DDL/SQL and see the resulting <a href="http://www.w3.org/2001/sw/rdb2rdf/directMapping/">Direct Graph</a>. This interface uses GET (vs. POST) so the length of the input SQL will be limited on servers which impose a limit on the URL length.</p>
-	<p>Please send bug reports to <a href="mailto:public-rdb2rdf-comments@w3.org">public-rdb2rdf-comments@w3.org</a>.</p>
-        <form method="get" action="/">
-          <p><textarea rows="15" cols="80" name="sql" id="sql">{ sql }</textarea></p>
-	  <div style="float:right;">
-	  <div style="float:left;">
-            { List("emp_addr", "hier_tabl_proto", "hier_table", "multi_key", "ref_no_pk") map renderVar }
-	  </div>
-	  <div style="float:left;">
-            { List("1table0rows", "1table1row", "1table2columns1row", "1table3columns1row", "2duplicates0nulls", "varchar_varchar_1row", "1table1compositeprimarykey3columns1row", "1table1primarykey1column1row", "2tables1primarykey1foreingkey") map renderVar }
-	  </div>
-	  </div>
-	  <p>{ minEncodeElement(minEncode) }Minimally encode IRI components (just encode [%&lt;+ /=#&gt;])</p>
-	  <p><input value="clear" type="button" onclick="document.getElementById('sql').value = '';" /></p>
-	  <p><input id="submit" value="submit SQL" type="submit" /></p>
-        </form>
-	<div class="clear"/>
-        { if (result isDefined) <pre name="result" id="result">{ result.get }</pre> }
-        <hr class="clear" />
-        <address>
-          <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Feb 2011
-        </address>
-      </body>
-    </html>
-
-  def processSQL(request:HttpServletRequest, response:HttpServletResponse, sql:String, minEncode:Boolean) {
-
-    val result:String =
-      try {
-        val db = SQLParser.toDB(sql)
-        DirectMapping.MinEncode = minEncode
-        val computedGraph:Graph = databaseSemantics(db)
-        jenaSerializer(computedGraph)
-      } catch {
-        case e => e.getMessage
-      }
-
-    val html = render(sql, minEncode, Some(result))
-
-    response.setContentType("application/xml; charset='" + encoding + "'")
-
-    XML.write(response.getWriter, html, encoding, false, xhtmlDoctype) 
-
-  }
-
-  def processIndex(request:HttpServletRequest, response:HttpServletResponse, minEncode:Boolean) {
-
-    val index = render(defaultSQL, minEncode, None)
-
-    response.setContentType("application/xml; charset='" + encoding + "'")
-
-    XML.write(response.getWriter, index, encoding, false, xhtmlDoctype)
-
-  }
-
-}
-
-object QueryManager {
-
-  import java.net._
-  import java.io._
-  import java.util.jar._
-  import scala.collection.JavaConversions._
-  import scala.io.Source
-
-  /** http://www.uofr.net/~greg/java/get-resource-listing.html */
-  def getResourceListing(path:String):List[String] = {
-    val clazz:Class[_] = this.getClass
-    var dirURL:URL = clazz.getClassLoader().getResource(path)
-    if (dirURL != null && dirURL.getProtocol == "file") {
-      /* A file path: easy enough */
-      new File(dirURL.toURI).list.toList
-    } else {
-      if (dirURL == null) {
-        val me = clazz.getName().replace(".", "/")+".class"
-        dirURL = clazz.getClassLoader().getResource(me)
-      }
-      if (dirURL.getProtocol == "jar") {
-        val jarPath = dirURL.getPath.substring(5, dirURL.getPath().indexOf("!"))
-        val jar:JarFile = new JarFile(URLDecoder.decode(jarPath, "UTF-8"))
-        val entries = jar.entries filter { _.getName startsWith path } map { e => {
-          var entry = e.getName substring path.length
-          val checkSubdir = entry indexOf "/"
-          if (checkSubdir >= 0) entry = entry.substring(0, checkSubdir)
-          entry
-        } }
-        
-        entries
-      }    
-      error("Cannot list files for URL "+dirURL);
-    }
-  }
-
-  lazy val getQueries:Map[String, String] = {
-    val classloader = this.getClass.getClassLoader
-    val entries = getResourceListing("queries/")
-    val queries = entries map { entry => {
-      val url = classloader.getResource("queries/" + entry)
-      val query = Source.fromURL(url, "UTF-8").getLines.mkString("\n")
-      (entry, query)
-    } } toMap
-
-    queries
-  }
-
-}
--- a/directmapping-webapp/src/main/scala/bootstrap/liftweb/Boot.scala	Sun May 01 19:37:10 2011 -0400
+++ b/directmapping-webapp/src/main/scala/bootstrap/liftweb/Boot.scala	Tue May 03 10:23:36 2011 -0400
@@ -53,6 +53,8 @@
     import net.liftweb.http.ResourceServer
     ResourceServer.allow {
       case "typewatch.js" :: Nil => true
+      case "jquery.watermark.js" :: Nil => true
+      case "autocomplete" :: _ => true
     }
 
 
--- a/directmapping-webapp/src/main/webapp/index.html	Sun May 01 19:37:10 2011 -0400
+++ b/directmapping-webapp/src/main/webapp/index.html	Tue May 03 10:23:36 2011 -0400
@@ -4,7 +4,10 @@
     <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
     <title>Direct Mapping Demo</title>
     <script type="text/javascript" src="/classpath/jquery.js"></script>
+    <script type="text/javascript" src="/classpath/autocomplete/jquery.autocomplete.js"></script>
+    <link rel="stylesheet" href="/classpath/autocomplete/jquery.autocomplete.css" type="text/css" />
     <script type="text/javascript" src="/classpath/typewatch.js"></script>
+    <script type="text/javascript" src="/classpath/jquery.watermark.js"></script>
     <style type="text/css" media="print, screen and (min-width: 481px)">
     div.area {position:relative; min-width:600px; zoom:0}
     textarea.query {display:block; width:60%; height:150px; min-height:150px; resize:vertical}
@@ -18,6 +21,8 @@
 // <![CDATA[
 jQuery(document).ready(function() {
 
+  jQuery("#ddl").watermark(jQuery("#ddl").val());
+
   jQuery("#ddl-name").autocomplete("/ddls", {minChars:0,matchContains:true}).result(function(event, dt, ddlname) {
     jQuery("#ddl-name").val(ddlname);
     jQuery.ajax({url: '/ddl/'+ddlname,
@@ -59,10 +64,10 @@
       <div class="interaction-area">
         <div class="query-management">
           <div class="query-box" >
-            <input type="text" value="" id="ddl-name" autocomplete="off" class="ac_input"/>
+            <input type="text" value="" id="ddl-name" class="ac_input"/>
           </div>
           <div class="message">
-            <textarea id="ddl-message" rows="5" cols="40" disabled="disabled">Nothing here</textarea>
+            <textarea id="ddl-message" rows="5" cols="40" disabled="disabled"></textarea>
           </div>
         </div>
       </div>
@@ -70,17 +75,21 @@
 
     <h2>SPARQL</h2>
 
-    If empty, this will be ignored.
+    If empty or non-valid SPARQL CONSTRUCT, this will be ignored.
 
-    <div id="sparql-area" class="lift:DirectMapping.queryArea area">
-      <textarea rows="15" cols="80" id="sparql-query" class="query">Here goes the SPARQL query</textarea>
+    <div class="area">
+      <textarea rows="15" cols="80" id="sparql" class="query">CONSTRUCT {
+  ?s ?p ?o .
+} WHERE {
+  ?s ?p ?o .
+}</textarea>
       <div class="interaction-area">
         <div class="query-management">
           <div class="query-box" >
-            <textarea rows="1" cols="16" class="area"></textarea>
+            <input type="text" value="" id="sparql-name" class="ac_input"/>
           </div>
           <div id="sparql-message" class="message">
-            <textarea rows="5" cols="40" disabled="disabled">Nothing here</textarea>
+            <textarea id="sparql-message" rows="5" cols="40" disabled="disabled"></textarea>
           </div>
         </div>
       </div>
@@ -88,6 +97,10 @@
     
     <h2>Direct Mapping + SPARQL</h2>
 
+    <div class="area">
+      <textarea id="result" rows="15" cols="80" class="result"></textarea>
+    </div>
+
     <hr ></hr>
     <address>
       <a href="http://www.w3.org/People/Eric/">Eric Prud'hommeaux</a>, <a href="http://www.w3.org/People/Bertails/">Alexandre Bertails</a>, Apr 2011<br />