diff --git a/draft/library/wsf_js_widget/kernel/input/wsf_file_control.e b/draft/library/wsf_js_widget/kernel/input/wsf_file_control.e index c1bef063..8b2f57a5 100644 --- a/draft/library/wsf_js_widget/kernel/input/wsf_file_control.e +++ b/draft/library/wsf_js_widget/kernel/input/wsf_file_control.e @@ -32,6 +32,9 @@ feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- State management if attached {JSON_STRING} new_state.item ("file") as new_name and attached {JSON_STRING} new_state.item ("type") as new_type and attached {JSON_NUMBER} new_state.item ("size") as new_size then create file.make (new_name.unescaped_string_32, new_type.unescaped_string_32, new_size.item.to_integer_32); end + if attached {JSON_STRING} new_state.item ("upload_file") as f then + upload_file:=f.unescaped_string_32; + end end state: WSF_JSON_OBJECT @@ -41,7 +44,18 @@ feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- State management Result.put_boolean (attached change_event, "callback_change") end -feature --Event handling +feature -- Uploaded Files + + set_uploaded_file (p: detachable STRING) + -- Store link to uploaded file in control state. In order to make it availabe for future callbacks + do + if attached p as a_p then + upload_file := a_p + state_changes.put_string (a_p, "upload_file") + end + end + +feature -- Event handling set_change_event (e: attached like change_event) -- Set text change event handle @@ -49,11 +63,20 @@ feature --Event handling change_event := e end + set_upload_function (e: attached like upload_function) + -- Set button click event handle + do + upload_function := e + end + handle_callback (cname: LIST [STRING]; event: STRING; event_parameter: detachable ANY) do - if Current.control_name.same_string (cname [1]) and attached change_event as cevent then - if event.same_string ("change") then + if Current.control_name.same_string (cname [1]) then + if attached change_event as cevent and event.same_string ("change") then cevent.call (Void) + elseif attached upload_function as ufunction and event.same_string ("uploadfile") and attached {ITERABLE[WSF_UPLOADED_FILE]}event_parameter as files then + + set_uploaded_file(ufunction.item ([files])) end end end @@ -89,4 +112,10 @@ feature -- Properties change_event: detachable PROCEDURE [ANY, TUPLE] -- Procedure to be execued on change + upload_function: detachable FUNCTION [ANY, TUPLE[ITERABLE[WSF_UPLOADED_FILE]],detachable STRING] + -- Procedure to be execued on change + + upload_file: detachable STRING + -- Link to uploaded file + end diff --git a/draft/library/wsf_js_widget/kernel/webcontrol/wsf_page_control.e b/draft/library/wsf_js_widget/kernel/webcontrol/wsf_page_control.e index 9ec447df..4b49e234 100644 --- a/draft/library/wsf_js_widget/kernel/webcontrol/wsf_page_control.e +++ b/draft/library/wsf_js_widget/kernel/webcontrol/wsf_page_control.e @@ -23,8 +23,8 @@ feature {NONE} -- Initialization make (req: WSF_REQUEST; res: WSF_RESPONSE) -- Initialize do - control_name:=req.request_time_stamp.out - make_control ( "body") + control_name := req.request_time_stamp.out + make_control ("body") request := req response := res initialize_controls @@ -69,16 +69,21 @@ feature -- Implementation event := get_parameter ("event") event_parameter := get_parameter ("event_parameter") if attached event and attached event_control_name and attached control then - create states.make_empty - request.read_input_data_into (states) - create json_parser.make_parser (states) - if attached {JSON_OBJECT} json_parser.parse_json as sp then - set_state (sp) - else - if attached request.form_parameter ("file") as o then - response.put_string (o.name) + if not event.is_equal ("uploadfile") then + create states.make_empty + request.read_input_data_into (states) + create json_parser.make_parser (states) + if attached {JSON_OBJECT} json_parser.parse_json as sp then + set_state (sp) end - + else + if attached request.form_parameter ("state") as statedata then + create json_parser.make_parser (statedata.as_string.value) + if attached {JSON_OBJECT} json_parser.parse_json as sp then + set_state (sp) + end + end + event_parameter:=request.uploaded_files end handle_callback (event_control_name.split ('-'), event, event_parameter) create states_changes.make @@ -128,7 +133,6 @@ feature -- Implementation Result.append (");page.initialize();});") Result.append ("") end - end read_state_changes (states: WSF_JSON_OBJECT) @@ -152,7 +156,7 @@ feature -- Implementation feature -- Event handling - handle_callback (cname: LIST[STRING]; event: STRING; event_parameter: detachable ANY) + handle_callback (cname: LIST [STRING]; event: STRING; event_parameter: detachable ANY) -- Forward callback to control do control.handle_callback (cname, event, event_parameter) @@ -185,8 +189,10 @@ feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- State management Result.put (controls_state, "controls") Result.put (state, "state") end + feature - control_name:STRING + + control_name: STRING feature {NONE} -- Root control diff --git a/examples/widgetapp/assets/widget.coffee b/examples/widgetapp/assets/widget.coffee index 6ee695ff..0e7f7cc0 100644 --- a/examples/widgetapp/assets/widget.coffee +++ b/examples/widgetapp/assets/widget.coffee @@ -370,21 +370,22 @@ class WSF_FILE_CONTROL extends WSF_CONTROL constructor: ()-> super @uploading = false + start_upload: ()-> if @uploading return @uploading = true @$el.hide() - @progressbar = $ """
""" + @progressbar = $ """
""" @$el.parent().append(@progressbar) formData = new FormData(); action = @callback_url - control_name: @control_name + control_name: @get_full_control_name() event: "uploadfile" event_parameter: "" file = @$el[0].files[0]; - formData.append('our-file', file) + formData.append('file', file) formData.append('state', JSON.stringify(@get_context_state())) @sendXHRequest(formData, action) @@ -395,20 +396,15 @@ class WSF_FILE_CONTROL extends WSF_CONTROL onprogressHandler = (evt)-> percent = evt.loaded/evt.total*100 self.progressbar.find('.progress-bar').css {'width':percent+"%"} - onloadHandler = (evt)-> - alert "DONE" - xhr.upload.addEventListener('progress', onprogressHandler, false); - xhr.upload.addEventListener('load', onloadHandler, false); + onstatechange = (evt)-> + if xhr.readyState==4 && xhr.status==200 + self.get_page().process_update(JSON.parse(xhr.responseText)) + + xhr.upload.addEventListener('progress', onprogressHandler, false); - ###Set up events - xhr.upload.addEventListener('loadstart', onloadstartHandler, false); - - xhr.addEventListener('readystatechange', onreadystatechangeHandler, false); - ### - #Set up request + xhr.addEventListener('readystatechange', onstatechange, false); xhr.open('POST', uri, true); - #Fire! xhr.send(formData); attach_events: ()-> @@ -435,9 +431,10 @@ class WSF_FILE_CONTROL extends WSF_CONTROL return @$el.val() update: (state) -> - if state.text? - @state['text'] = state.text - @$el.val(state.text) + if state.upload_file? + @progressbar.hide() + @$el.parent().append($("""

""").addClass("form-control-static").text(@state['file'])) + @state['upload_file'] = state.upload_file class WSF_PASSWORD_CONTROL extends WSF_INPUT_CONTROL diff --git a/examples/widgetapp/assets/widget.css b/examples/widgetapp/assets/widget.css index 3f27bf68..9c215361 100644 --- a/examples/widgetapp/assets/widget.css +++ b/examples/widgetapp/assets/widget.css @@ -97,4 +97,9 @@ body { .CodeMirror-code{ line-height: 1.4em; +} + +.upload.progress{ + margin-top: 7px; + margin-bottom: 0px; } \ No newline at end of file diff --git a/examples/widgetapp/assets/widget.js b/examples/widgetapp/assets/widget.js index 8894892e..2dac6b4d 100644 --- a/examples/widgetapp/assets/widget.js +++ b/examples/widgetapp/assets/widget.js @@ -618,22 +618,22 @@ WSF_FILE_CONTROL = (function(_super) { } this.uploading = true; this.$el.hide(); - this.progressbar = $("
"); + this.progressbar = $("
"); this.$el.parent().append(this.progressbar); formData = new FormData(); action = this.callback_url({ - control_name: this.control_name, + control_name: this.get_full_control_name(), event: "uploadfile", event_parameter: "" }); file = this.$el[0].files[0]; - formData.append('our-file', file); + formData.append('file', file); formData.append('state', JSON.stringify(this.get_context_state())); return this.sendXHRequest(formData, action); }; WSF_FILE_CONTROL.prototype.sendXHRequest = function(formData, uri) { - var onloadHandler, onprogressHandler, self, xhr; + var onprogressHandler, onstatechange, self, xhr; xhr = new XMLHttpRequest(); self = this; onprogressHandler = function(evt) { @@ -643,18 +643,13 @@ WSF_FILE_CONTROL = (function(_super) { 'width': percent + "%" }); }; - onloadHandler = function(evt) { - return alert("DONE"); + onstatechange = function(evt) { + if (xhr.readyState === 4 && xhr.status === 200) { + return self.get_page().process_update(JSON.parse(xhr.responseText)); + } }; xhr.upload.addEventListener('progress', onprogressHandler, false); - xhr.upload.addEventListener('load', onloadHandler, false); - /*Set up events - xhr.upload.addEventListener('loadstart', onloadstartHandler, false); - - - xhr.addEventListener('readystatechange', onreadystatechangeHandler, false); - */ - + xhr.addEventListener('readystatechange', onstatechange, false); xhr.open('POST', uri, true); return xhr.send(formData); }; @@ -690,9 +685,10 @@ WSF_FILE_CONTROL = (function(_super) { }; WSF_FILE_CONTROL.prototype.update = function(state) { - if (state.text != null) { - this.state['text'] = state.text; - return this.$el.val(state.text); + if (state.upload_file != null) { + this.progressbar.hide(); + this.$el.parent().append($("

").addClass("form-control-static").text(this.state['file'])); + return this.state['upload_file'] = state.upload_file; } }; diff --git a/examples/widgetapp/sample_page.e b/examples/widgetapp/sample_page.e index 18ac3f7d..2a1d4c49 100644 --- a/examples/widgetapp/sample_page.e +++ b/examples/widgetapp/sample_page.e @@ -21,23 +21,19 @@ feature initialize_controls local - n0_container: WSF_FORM_ELEMENT_CONTROL [detachable WSF_PENDING_FILE] n1_container: WSF_FORM_ELEMENT_CONTROL [STRING] n2_container: WSF_FORM_ELEMENT_CONTROL [STRING] n3_container: WSF_FORM_ELEMENT_CONTROL [STRING] n4_container: WSF_FORM_ELEMENT_CONTROL [STRING] n5_container: WSF_FORM_ELEMENT_CONTROL [STRING] + n6_container: WSF_FORM_ELEMENT_CONTROL [detachable WSF_PENDING_FILE] + n7_container: WSF_FORM_ELEMENT_CONTROL [detachable WSF_PENDING_FILE] cats_container: WSF_FORM_ELEMENT_CONTROL [LIST [STRING]] source: INCREASING_PROGRESSSOURCE do Precursor create form.make form.add_class ("form-horizontal") - --File - create filebox.make - create n0_container.make ("File Upload", filebox) - n0_container.add_validator (create {WSF_FILESIZE_VALIDATOR}.make (100000,"File must be smaller than 100KB")) - form.add_control (n0_container) --Number 1 create textbox1.make ("1") create n1_container.make ("Number1", textbox1) @@ -67,9 +63,24 @@ feature cklist.add_control (create {WSF_CHECKBOX_CONTROL}.make ("Operating Systems", "os")) cklist.add_control (create {WSF_CHECKBOX_CONTROL}.make ("Formal Methods and Functional Programming", "fmfp")) create cats_container.make ("Categories", cklist) - cats_container.add_validator (create {WSF_MIN_VALIDATOR [LIST[STRING]]}.make (1, "Choose at least one category")) - cats_container.add_validator (create {WSF_MAX_VALIDATOR [LIST[STRING]]}.make (2, "Choose at most two category")) + cats_container.add_validator (create {WSF_MIN_VALIDATOR [LIST [STRING]]}.make (1, "Choose at least one category")) + cats_container.add_validator (create {WSF_MAX_VALIDATOR [LIST [STRING]]}.make (2, "Choose at most two category")) form.add_control (cats_container) + --File + create filebox.make + filebox.set_upload_function (agent upload_file) + create n6_container.make ("File Upload", filebox) + n6_container.add_validator (create {WSF_FILESIZE_VALIDATOR}.make (10000000, "File must be smaller than 10MB")) + form.add_control (n6_container) + --File + create filebox2.make + filebox2.set_upload_function (agent upload_file) + filebox2.set_change_event (agent do + filebox2.start_upload + end) + create n7_container.make ("Auto Upload", filebox2) + n7_container.add_validator (create {WSF_FILESIZE_VALIDATOR}.make (10000000, "File must be smaller than 10MB")) + form.add_control (n7_container) --Button 1 create button1.make ("Update") button1.set_click_event (agent handle_click) @@ -94,6 +105,16 @@ feature navbar.set_active (1) end + upload_file (f: ITERABLE [WSF_UPLOADED_FILE]): detachable String + do + -- Store file on server and return link + across + f as i + loop + Result:=i.item.filename + end + end + handle_click local text: STRING @@ -118,7 +139,7 @@ feature run_modal do - start_modal("/","Test Modal", true); + start_modal ("/", "Test Modal", true); end process @@ -131,6 +152,8 @@ feature filebox: WSF_FILE_CONTROL + filebox2: WSF_FILE_CONTROL + textbox1: WSF_INPUT_CONTROL textbox2: WSF_INPUT_CONTROL