<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/lib/wf_multipart.erl</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -2,8 +2,6 @@
 &lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
 &lt;plist version=&quot;1.0&quot;&gt;
 &lt;dict&gt;
-	&lt;key&gt;currentDocument&lt;/key&gt;
-	&lt;string&gt;src/lib/wf_handle_postback_multipart.erl&lt;/string&gt;
 	&lt;key&gt;documents&lt;/key&gt;
 	&lt;array&gt;
 		&lt;dict&gt;
@@ -643,7 +641,7 @@
 							&lt;key&gt;filename&lt;/key&gt;
 							&lt;string&gt;src/lib/wf_handle.erl&lt;/string&gt;
 							&lt;key&gt;lastUsed&lt;/key&gt;
-							&lt;date&gt;2009-03-24T03:17:40Z&lt;/date&gt;
+							&lt;date&gt;2009-03-25T23:04:21Z&lt;/date&gt;
 						&lt;/dict&gt;
 						&lt;dict&gt;
 							&lt;key&gt;filename&lt;/key&gt;
@@ -661,7 +659,7 @@
 							&lt;key&gt;filename&lt;/key&gt;
 							&lt;string&gt;src/lib/wf_handle_postback_multipart.erl&lt;/string&gt;
 							&lt;key&gt;lastUsed&lt;/key&gt;
-							&lt;date&gt;2009-03-24T03:26:30Z&lt;/date&gt;
+							&lt;date&gt;2009-03-25T23:04:20Z&lt;/date&gt;
 						&lt;/dict&gt;
 						&lt;dict&gt;
 							&lt;key&gt;filename&lt;/key&gt;
@@ -1188,34 +1186,6 @@
 			&lt;key&gt;firstVisibleLine&lt;/key&gt;
 			&lt;integer&gt;0&lt;/integer&gt;
 		&lt;/dict&gt;
-		&lt;key&gt;src/lib/wf_handle.erl&lt;/key&gt;
-		&lt;dict&gt;
-			&lt;key&gt;caret&lt;/key&gt;
-			&lt;dict&gt;
-				&lt;key&gt;column&lt;/key&gt;
-				&lt;integer&gt;28&lt;/integer&gt;
-				&lt;key&gt;line&lt;/key&gt;
-				&lt;integer&gt;24&lt;/integer&gt;
-			&lt;/dict&gt;
-			&lt;key&gt;firstVisibleColumn&lt;/key&gt;
-			&lt;integer&gt;0&lt;/integer&gt;
-			&lt;key&gt;firstVisibleLine&lt;/key&gt;
-			&lt;integer&gt;10&lt;/integer&gt;
-		&lt;/dict&gt;
-		&lt;key&gt;src/lib/wf_handle_postback_multipart.erl&lt;/key&gt;
-		&lt;dict&gt;
-			&lt;key&gt;caret&lt;/key&gt;
-			&lt;dict&gt;
-				&lt;key&gt;column&lt;/key&gt;
-				&lt;integer&gt;0&lt;/integer&gt;
-				&lt;key&gt;line&lt;/key&gt;
-				&lt;integer&gt;3&lt;/integer&gt;
-			&lt;/dict&gt;
-			&lt;key&gt;firstVisibleColumn&lt;/key&gt;
-			&lt;integer&gt;0&lt;/integer&gt;
-			&lt;key&gt;firstVisibleLine&lt;/key&gt;
-			&lt;integer&gt;1&lt;/integer&gt;
-		&lt;/dict&gt;
 		&lt;key&gt;src/lib/wf_redirect.erl&lt;/key&gt;
 		&lt;dict&gt;
 			&lt;key&gt;caret&lt;/key&gt;
@@ -1391,11 +1361,6 @@
 			&lt;integer&gt;0&lt;/integer&gt;
 		&lt;/dict&gt;
 	&lt;/dict&gt;
-	&lt;key&gt;openDocuments&lt;/key&gt;
-	&lt;array&gt;
-		&lt;string&gt;src/lib/wf_handle_postback_multipart.erl&lt;/string&gt;
-		&lt;string&gt;src/lib/wf_handle.erl&lt;/string&gt;
-	&lt;/array&gt;
 	&lt;key&gt;showFileHierarchyDrawer&lt;/key&gt;
 	&lt;true/&gt;
 	&lt;key&gt;treeState&lt;/key&gt;</diff>
      <filename>Nitrogen.tmproj</filename>
    </modified>
    <modified>
      <diff>@@ -12,7 +12,30 @@ headline() -&gt; &quot;Upload Example&quot;.
 right() -&gt; linecount:render().
 
 body() -&gt; [
-	#upload { id=myUpload }
+	
+	#h3 { text=&quot;Upload Example #1&quot; },
+	#p{},
+	&quot;Upload example with modified button text. The default text is 'Upload'.&quot;,
+	#p{},
+	#upload { tag=myUpload1, button_text=&quot;Upload File&quot; },
+	
+	#hr{},
+	
+	#h3 { text=&quot;Upload Example #2&quot; },
+	#p{},
+	&quot;This example hides he upload button. When the user selects a file it will automatically start uploading.&quot;,
+	#p{},
+	#upload { tag=myUpload1, show_button=false }
+	
 ].
 	
-event(_) -&gt; ok.
\ No newline at end of file
+event(_) -&gt; ok.
+
+upload_event(_Tag, undefined, _) -&gt;
+	wf:flash(&quot;Please select a file.&quot;),
+	ok;
+
+upload_event(_Tag, FileName, LocalFileData) -&gt;
+	FileSize = filelib:file_size(LocalFileData),
+	wf:flash(wf:f(&quot;Uploaded file: ~s (~p bytes)&quot;, [FileName, FileSize])),
+	ok.
\ No newline at end of file</diff>
      <filename>Quickstart/src/samples/web_samples_upload.erl</filename>
    </modified>
    <modified>
      <diff>@@ -73,7 +73,7 @@
 -define(CONTROL_BASE(Module), ?ELEMENT_BASE(Module), tag).
 -record(inplace_textbox, {?CONTROL_BASE(element_inplace_textbox), text=&quot;&quot;, html_encode=true, start_mode=view, validators=[]}).
 -record(wizard, {?CONTROL_BASE(element_wizard), titles, steps }).
--record(upload, {?CONTROL_BASE(element_upload)}).
+-record(upload, {?CONTROL_BASE(element_upload), show_button=true, button_text=&quot;Upload&quot; }).
 
 %%% Actions %%%
 -define(ACTION_BASE(Module), module=Module, trigger, target, actions, show_if=true).</diff>
      <filename>include/wf.inc</filename>
    </modified>
    <modified>
      <diff>@@ -15,13 +15,17 @@ reflect() -&gt; record_info(fields, upload).
 % - Does document.parentNode always work in an iframe?
 
 render(ControlID, Record) -&gt;
+	ShowButton = Record#upload.show_button,
+	ButtonText = Record#upload.button_text,
 	FormID = wf:temp_id(),
 	IFrameID = wf:temp_id(),
 	SubmitJS = wf:f(&quot;Nitrogen.$upload(obj('~s'));&quot;, [FormID]),
-	% wf:wire(ControlID, #event { type=change, actions=SubmitJS }),
-
 	PostbackInfo = action_event:make_postback_info(Record#upload.tag, upload, ControlID, ControlID, ?MODULE),
-
+	
+	% If the button is invisible, then start uploading when the user selects a file.
+	wf:wire(ControlID, #event { show_if=(not ShowButton), type=change, actions=SubmitJS }),
+	
+	% Render the controls and hidden iframe...
 	FormContent = [
 		wf_tags:emit_tag(input, [
 			{id, ControlID},
@@ -41,7 +45,7 @@ render(ControlID, Record) -&gt;
 			{value, &quot;&quot;}
 		]),
 		
-		wf:render(#button { text=&quot;Upload&quot;, actions=#event { type=click, actions=SubmitJS } })
+		wf:render(#button { show_if=ShowButton, text=ButtonText, actions=#event { type=click, actions=SubmitJS } })
 	],
 	
 	[
@@ -56,10 +60,11 @@ render(ControlID, Record) -&gt;
 		wf_tags:emit_tag(iframe, [], [
 			{id, IFrameID},
 			{name, IFrameID},
-			{style, &quot;width: 300px; height: 100px;&quot;}
+			{style, &quot;display: none; width: 300px; height: 100px;&quot;}
 		])
 	].
 	
-event(Tag) -&gt; 
-	?PRINT(Tag),
+event({upload, Tag, Filename, LocalFileData}) -&gt; 
+	Delegate = wf_platform:get_page_module(),
+	Delegate:upload_event(Tag, Filename, LocalFileData),
 	ok.
\ No newline at end of file</diff>
      <filename>src/elements/forms/element_upload.erl</filename>
    </modified>
    <modified>
      <diff>@@ -30,7 +30,7 @@ check_multipart_postback(Module) -&gt;
 
 check_request_method(Module) -&gt;
 	% Get the query...
-	Query = case wf_platform:request_method() of
+	Query = case wf_platform:get_request_method() of
 		'GET' -&gt; wf_platform:parse_get_args();
 		'POST' -&gt; wf_platform:parse_post_args()
 	end,
@@ -38,7 +38,7 @@ check_request_method(Module) -&gt;
 	wf_query:prepare_request_query_paths(Query),
 
 	% Check if this is the first request or a postback...
-	IsFirstRequest = wf_platform:request_method() == 'GET' andalso wf:q(postbackInfo) == [],
+	IsFirstRequest = wf_platform:get_request_method() == 'GET' andalso wf:q(postbackInfo) == [],
 	case IsFirstRequest of 
 		true  -&gt; wf_handle_firstrequest:handle_request(Module);
 		false -&gt; wf_handle_postback:handle_request(Module) </diff>
      <filename>src/lib/wf_handle.erl</filename>
    </modified>
    <modified>
      <diff>@@ -7,41 +7,37 @@
 -export ([handle_request/1]).
 
 handle_request(Module) -&gt;
-	Request = wf_platform:get_request(),
-	?PRINT(mochiweb_multipart:parse_multipart_request(Request, fun callback/1)),
-	wf_platform:set_response_body(&quot;Done&quot;),
-	wf_platform:build_response().
+	% Parse the template...
+ 	{ok, Query, FileName, LocalFileData} = wf_multipart:parse_upload(),
+	put(request_query, Query),
+	wf_query:prepare_request_query_paths(Query),
+	
 
-callback(X) -&gt; 
-	?PRINT(X), 
-	F = fun(Y) -&gt; callback(Y) end,
-	F.
+	% Get the event that triggered the postback...
+	[PostbackInfo] = wf:q(postbackInfo),
+	{ObjectID, Tag, _EventType, TriggerID, TargetID, Delegate} = wf:depickle(PostbackInfo),
+	
+	% Find the delegate...
+	Module1 = case Delegate of 
+		undefined -&gt; Module;
+		_ -&gt; Delegate
+	end,	
+	
+	% Setup the response...
+	put(current_id, ObjectID),
+	put(current_path, wf_path:to_path(TargetID)),
 
-	% % Get the event that triggered the postback...
-	% [PostbackInfo] = wf:q(postbackInfo),
-	% {ObjectID, Tag, _EventType, TriggerID, TargetID, Delegate} = wf:depickle(PostbackInfo),
-	% 
-	% % Find the delegate...
-	% Module1 = case Delegate of 
-	% 	undefined -&gt; Module;
-	% 	_ -&gt; Delegate
-	% end,	
-	% 
-	% % Get the filename...
-	% File = case wf:q(TriggerID) of
-	% 	[X] -&gt; X;
-	% 	_   -&gt; undefined
-	% end,
-	% 
-	% % Create the postback...
-	% NewTag = {upload, Tag, File},
-	% Postback = action_event:make_postback(NewTag, upload_finished, TriggerID, TargetID, Module1),
-	% 
-	% % Send the response...
-	% wf_platform:set_content_type(&quot;text/html&quot;),
-	% wf_platform:set_response_body([
-	% 	&quot;&lt;html&gt;&lt;body&gt;&lt;script&gt;&quot;,
-	% 	wf:f(&quot;window.parent.~s.&quot;, [ObjectID]), Postback,
-	% 	&quot;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;&quot;
-	% ]),
-	% wf_platform:build_response().
\ No newline at end of file
+	% Create the postback...
+	NewTag = {upload, Tag, FileName, LocalFileData},
+	Postback = action_event:make_postback(NewTag, upload_finished, TriggerID, TargetID, Module1),
+	
+	% Send the response...
+	wf_platform:set_content_type(&quot;text/html&quot;),
+	wf_platform:set_response_body([
+		&quot;&lt;html&gt;&lt;body&gt;&lt;script&gt;&quot;,
+		&quot;var Nitrogen = window.parent.Nitrogen;&quot;,
+		wf:me_var(),
+		Postback,
+		&quot;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;&quot;
+	]),
+	wf_platform:build_response().
\ No newline at end of file</diff>
      <filename>src/lib/wf_handle_postback_multipart.erl</filename>
    </modified>
    <modified>
      <diff>@@ -12,7 +12,8 @@
 
 	get_raw_path/0,
 	get_querystring/0,
-	request_method/0,
+	get_request_method/0,
+	get_request_body/0,
 	parse_get_args/0,
 	parse_post_args/0,
 
@@ -24,6 +25,8 @@
 	set_redirect/1,
 	set_header/2,
 	get_peername/0,
+	get_socket/0,
+	recv_from_socket/2,
 	route/1, request/1,
 	set_response_code/1,
 	set_content_type/1,
@@ -49,6 +52,7 @@ do(Method, Args) -&gt;
 
 get_platform() -&gt; do(get_platform).
 get_request() -&gt; get(wf_request).
+get_request_body() -&gt; do(get_request_body).
 get_page_module() -&gt; get(wf_page_module).
 set_page_module(Module) -&gt; put(wf_page_module, Module).
 get_path_info() -&gt; get(wf_path_info).
@@ -60,7 +64,7 @@ get_querystring() -&gt; do(get_querystring).
 
 %%% METHOD AND ARGS %%%
 
-request_method() -&gt; do(request_method).
+get_request_method() -&gt; do(get_request_method).
 parse_get_args() -&gt; do(parse_get_args).
 parse_post_args() -&gt; do(parse_post_args).
 
@@ -104,8 +108,10 @@ set_header(Key, Value) -&gt;
 	
 
 %%% SOCKETS %%%
+get_socket() -&gt; do(get_socket).
+get_peername() -&gt; inet:peername(get_socket).
+recv_from_socket(Length, Timeout) -&gt; do(recv_from_socket, [Length, Timeout]).
 
-get_peername() -&gt; do(get_peername).
 
 %%% ROUTE AND REQUEST %%%
 
@@ -158,7 +164,7 @@ handle_redirects() -&gt;
 
 build_redirect(Url) -&gt;
 	Url1 = wf:to_list(Url),
-	case request_method() of
+	case get_request_method() of
 		'GET' -&gt; build_get_redirect(Url1);
 		'POST' -&gt; build_post_redirect(Url1)
 	end.</diff>
      <filename>src/lib/wf_platform.erl</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,8 @@
 
 	get_raw_path/0,
 	get_querystring/0,
-	request_method/0,
+	get_request_method/0,
+	get_request_body/0,
 
 	get_headers/0,
 	get_header/1,
@@ -24,7 +25,8 @@
 	
 	build_response/0,
 
-	get_peername/0
+	get_socket/0,
+	recv_from_socket/2
 ]).
 
 get_platform() -&gt; inets.
@@ -43,9 +45,13 @@ get_querystring() -&gt;
 		_ -&gt; tl(QueryString) 
 	end.
 
-request_method() -&gt;
+get_request_method() -&gt;
 	Info = wf_platform:get_request(),
 	wf:to_atom(Info#mod.method).
+	
+get_request_body() -&gt;
+	Req = wf_platform:get_request(),
+	Req#mod.entity_body.
 
 parse_get_args() -&gt;
 	QueryString = get_querystring(),
@@ -153,6 +159,13 @@ build_response() -&gt;
 
 %%% SOCKETS %%%
 
-get_peername() -&gt;
+get_socket() -&gt;
 	Info = wf_platform:get_request(),
-	inet:peername(Info#mod.socket).
+	Info#mod.socket.
+
+recv_from_socket(Length, Timeout) -&gt; 
+	Socket = get_socket(),
+	case gen_tcp:recv(Socket, Length, Timeout) of
+		{ok, Data} -&gt; Data;
+		_ -&gt; exit(normal)
+	end.</diff>
      <filename>src/lib/wf_platform_inets.erl</filename>
    </modified>
    <modified>
      <diff>@@ -3,12 +3,14 @@
 % See MIT-LICENSE for licensing information.
 
 -module (wf_platform_mochiweb).
+-include (&quot;wf.inc&quot;).
 -export ([
 	get_platform/0,
 	
 	get_raw_path/0,
 	get_querystring/0,
-	request_method/0,
+	get_request_method/0,
+	get_request_body/0,
 	
 	parse_get_args/0,
 	parse_post_args/0,
@@ -23,7 +25,8 @@
 	
 	build_response/0,
 
-	get_peername/0
+	get_socket/0,
+	recv_from_socket/2
 ]).
 
 get_platform() -&gt; mochiweb.
@@ -40,9 +43,12 @@ get_querystring() -&gt;
 	{_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath),
 	QueryString.
 	
-request_method() -&gt;
+get_request_method() -&gt;
 	Req = wf_platform:get_request(),
 	Req:get(method).
+	
+get_request_body() -&gt;
+	undefined.
 
 parse_get_args() -&gt;
 	Req = wf_platform:get_request(),
@@ -117,6 +123,16 @@ build_response() -&gt;
 
 %%% SOCKETS %%%
 
-get_peername() -&gt;
+get_socket() -&gt;
 	Req = wf_platform:get_request(),
-	inet:peername(Req:get(socket)).
+	Req:get(socket).
+
+recv_from_socket(Length, Timeout) -&gt; 
+	Socket = get_socket(),
+	case gen_tcp:recv(Socket, Length, Timeout) of
+		{ok, Data} -&gt; 
+			put(mochiweb_request_recv, true),
+			Data;
+		_Other -&gt; 
+			exit(normal)
+	end.</diff>
      <filename>src/lib/wf_platform_mochiweb.erl</filename>
    </modified>
    <modified>
      <diff>@@ -9,7 +9,8 @@
 	
 	get_raw_path/0,
 	get_querystring/0,
-	request_method/0,
+	get_request_method/0,
+	get_request_body/0,
 	
 	parse_get_args/0,
 	parse_post_args/0,
@@ -23,7 +24,8 @@
 	
 	build_response/0,
 
-	get_peername/0
+	get_socket/0,
+	recv_from_socket/2
 ]).
 
 get_platform() -&gt; yaws.
@@ -38,10 +40,17 @@ get_querystring() -&gt;
 	Arg = wf_platform:get_request(),
 	Arg#arg.querydata.
 
-request_method() -&gt;
+get_request_method() -&gt;
 	Arg = wf_platform:get_request(),
 	(Arg#arg.req)#http_request.method.
 	
+get_request_body() -&gt;
+	Arg = wf_platform:get_request(),
+	case Arg#arg.clidata of
+		{partial, Data} -&gt; Data;
+		Data -&gt; Data
+	end.
+	
 parse_get_args() -&gt;
 	Arg = wf_platform:get_request(),
 	yaws_api:parse_query(Arg).
@@ -123,6 +132,13 @@ build_response() -&gt;
 
 %%% SOCKETS %%%
 
-get_peername() -&gt;
+get_socket() -&gt;
 	Arg = wf_platform:get_request(),
-	inet:peername(Arg#arg.clisock).
+	Arg#arg.clisock.
+
+recv_from_socket(Length, Timeout) -&gt; 
+	Socket = get_socket(),
+	case gen_tcp:recv(Socket, Length, Timeout) of
+		{ok, Data} -&gt; Data;
+		_ -&gt; exit(normal)
+	end.</diff>
      <filename>src/lib/wf_platform_yaws.erl</filename>
    </modified>
    <modified>
      <diff>@@ -20,14 +20,6 @@ restore_state() -&gt;
 			put(wf_state, wf:depickle(DomState))
 	end.
 
-% restore_state_from_post(Query) -&gt;
-% 	{value, {_, DomState}} = lists:keysearch(&quot;domState&quot;, 1, Query),
-% 	case DomState of 
-% 		undefined -&gt; ignore;
-% 		_ -&gt;
-% 			put(wf_state, wf:depickle(DomState))
-% 	end.
-	
 %%% STATE %%%
 
 %state/1 - Get the value for Key.</diff>
      <filename>src/lib/wf_state.erl</filename>
    </modified>
    <modified>
      <diff>@@ -19,7 +19,8 @@
 	get_session_timeout/0,
 	get_sign_key/0,
 	get_wwwroot/0,
-	get_hooks_module/0
+	get_hooks_module/0,
+	get_scratch_directory/0
 ]).
 
 start() -&gt; start(undefined).
@@ -133,6 +134,12 @@ get_hooks_module() -&gt;
 			{ok, {Module, _}} = application:get_key(mod),
 			Module
 	end.
+	
+get_scratch_directory() -&gt;
+	case get_env(serving_app(), scratch_directory) of
+		{ok, Val} -&gt; Val;
+		_ -&gt; &quot;./scratch&quot;
+	end.
 
 serving_app() -&gt; 
 	case get_env(nitrogen, serving_app) of </diff>
      <filename>src/nitrogen.erl</filename>
    </modified>
    <modified>
      <diff>@@ -253,7 +253,8 @@ N.prototype.$do_windex_comet = function(postbackInfo) {
 N.$upload = function(form) {
 	var n = Nitrogen.$lookup(Nitrogen.$current_id);
 	form.domState.value = n.$dom_state;
-	form.submit();	
+	form.submit();
+	form.reset();
 }
 
 /*** SERIALIZATION ***/
@@ -264,7 +265,10 @@ N.prototype.$get_elements_to_serialize = function() {
 	for (var i=0; i&lt;tagnames.length; i++) {
 		var l = this.$div.getElementsByTagName(tagnames[i]);
 		for (var j=0; j&lt;l.length; j++) {
-			a = a.concat(l[j]);
+			var elementName = l[j].name;
+			if (elementName != &quot;domState&quot; &amp;&amp; elementName != &quot;postbackInfo&quot;) {
+				a = a.concat(l[j]);
+			}
 		}
 	}
 	</diff>
      <filename>www/nitrogen.js</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>38ed68c5b6b78866c4b0c07be9ec4adf52904c59</id>
    </parent>
  </parents>
  <author>
    <name>Rusty Klophaus</name>
    <email>rklophaus@gmail.com</email>
  </author>
  <url>http://github.com/rklophaus/nitrogen/commit/fbc2a7536bc268b58f285a78aca3ca2e1a9d94ce</url>
  <id>fbc2a7536bc268b58f285a78aca3ca2e1a9d94ce</id>
  <committed-date>2009-03-28T17:23:37-07:00</committed-date>
  <authored-date>2009-03-28T17:23:37-07:00</authored-date>
  <message>Finish file upload support.</message>
  <tree>42a4708d8eec866f8e90afdb41dd85b408c81401</tree>
  <committer>
    <name>Rusty Klophaus</name>
    <email>rklophaus@gmail.com</email>
  </committer>
</commit>
