diff --git a/examples/widgetapp/own_validator.e b/examples/widgetapp/own_validator.e new file mode 100644 index 00000000..1ba0395a --- /dev/null +++ b/examples/widgetapp/own_validator.e @@ -0,0 +1,31 @@ +note + description: "Summary description for {OWN_VALIDATOR}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + OWN_VALIDATOR + +inherit + + WSF_VALIDATOR [STRING] + +create + make_own + +feature {NONE} + + make_own + do + error := "Input to long" + end + +feature + + is_valid (input: STRING): BOOLEAN + do + Result := input.count < 5 + end + +end diff --git a/examples/widgetapp/sample_page.e b/examples/widgetapp/sample_page.e index 6aec5cdf..91aa91de 100644 --- a/examples/widgetapp/sample_page.e +++ b/examples/widgetapp/sample_page.e @@ -19,19 +19,27 @@ feature initialize_controls local form: WSF_FORM_CONTROL + n1_container: WSF_FORM_ELEMENT_CONTROL [STRING] + n2_container: WSF_FORM_ELEMENT_CONTROL [STRING] do - create textbox1.make_text ("txtBox1", "1") - create textbox2.make_text ("txtBox2", "2") + create textbox1.make_input ("txtBox1", "1") + create textbox2.make_input ("txtBox2", "2") create button1.make_button ("sample_button1", "SUM") - create textbox_result.make_textarea ("txtBox3", "") + create textbox_result.make_html ("txtBox3","p", "") button1.set_click_event (agent handle_click) + button1.add_class ("col-lg-offset-2") create form.make_form_control ("panel") form.add_class ("form-horizontal") create cklist.make_checkbox_list_control ("categories") cklist.add_control (create {WSF_CHECKBOX_CONTROL}.make_checkbox ("net", "Network", "net")) cklist.add_control (create {WSF_CHECKBOX_CONTROL}.make_checkbox ("os", "Operating Systems", "os")) - form.add_control (create {WSF_FORM_ELEMENT_CONTROL [STRING]}.make_form_element ("Number1", textbox1)) - form.add_control (create {WSF_FORM_ELEMENT_CONTROL [STRING]}.make_form_element ("Number2", textbox2)) + create n1_container.make_form_element ("Number1", textbox1) + n1_container.add_validator (create {WSF_DECIMAL_VALIDATOR}.make_decimal_validator ("Invalid Number")) + n1_container.add_validator (create {OWN_VALIDATOR}.make_own) + create n2_container.make_form_element ("Number2", textbox2) + n2_container.add_validator (create {WSF_DECIMAL_VALIDATOR}.make_decimal_validator ("Invalid Number")) + form.add_control (n1_container) + form.add_control (n2_container) form.add_control (create {WSF_FORM_ELEMENT_CONTROL [LIST [STRING]]}.make_form_element ("Categories", cklist)) form.add_control (button1) form.add_control (create {WSF_FORM_ELEMENT_CONTROL [STRING]}.make_form_element ("Result", textbox_result)) @@ -42,13 +50,20 @@ feature local text: STRING do - text := textbox1.text + " + " + textbox2.text + " = " + (textbox1.text.to_integer_16 + textbox2.text.to_integer_16).out - across - cklist.value as s - loop - text.append ("%N-" + s.item) + if attached {WSF_FORM_CONTROL} control as form then + form.validate + if form.is_valid then + text := textbox1.text + " + " + textbox2.text + " = " + (textbox1.text.to_integer_64 + textbox2.text.to_integer_64).out + across + cklist.value as s + loop + text.append ("
-" + s.item) + end + textbox_result.set_html (text) + else + textbox_result.set_html ("VALIDATION ERROR") + end end - textbox_result.set_text (text) end process @@ -57,12 +72,12 @@ feature button1: WSF_BUTTON_CONTROL - textbox1: WSF_TEXT_CONTROL + textbox1: WSF_INPUT_CONTROL - textbox2: WSF_TEXT_CONTROL + textbox2: WSF_INPUT_CONTROL cklist: WSF_CHECKBOX_LIST_CONTROL - textbox_result: WSF_TEXTAREA_CONTROL + textbox_result: WSF_HTML_CONTROL end diff --git a/examples/widgetapp/widget.coffee b/examples/widgetapp/widget.coffee index 9ca48ee9..417c5eb9 100644 --- a/examples/widgetapp/widget.coffee +++ b/examples/widgetapp/widget.coffee @@ -10,17 +10,56 @@ trigger_callback = (control_name,event)-> for name,state of new_states controls[name]?.update(state) return +class WSF_VALIDATOR + constructor: (@parent_control, @settings)-> + @error = @settings.error + return + + validate: ()-> + return true + +class WSF_REGEXP_VALIDATOR extends WSF_VALIDATOR + constructor: ()-> + super + @pattern = new RegExp(@settings.expression,'g') + + validate: ()-> + val = @parent_control.value() + res = val.match(@pattern) + return (res!=null) + +validatormap = + "WSF_REGEXP_VALIDATOR":WSF_REGEXP_VALIDATOR class WSF_CONTROL constructor: (@control_name, @$el)-> - @attach_events() return attach_events: ()-> return update: (state)-> - return + return + + #Simple event listener + + #subscribe to an event + on: (name, callback, context)-> + if not @_events? + @_events = {} + if not @_events[name]? + @_events[name] = [] + @_events[name].push({callback:callback,context:context}) + return @ + + #trigger an event + trigger: (name)-> + if not @_events?[name]? + return @ + for ev in @_events[name] + ev.callback.call(ev.context) + return @ + controls = {} @@ -39,16 +78,21 @@ class WSF_BUTTON_CONTROL extends WSF_CONTROL window.states[@control_name]['text'] = state.text @$el.text(state.text) -class WSF_TEXT_CONTROL extends WSF_CONTROL +class WSF_INPUT_CONTROL extends WSF_CONTROL attach_events: ()-> self = @ @$el.change ()-> self.change() + change: ()-> #update local state window.states[@control_name]['text'] = @$el.val() if window.states[@control_name]['callback_change'] trigger_callback(@control_name, 'change') + @trigger('change') + + value:()-> + return @$el.val() update: (state) -> if state.text? @@ -65,6 +109,30 @@ class WSF_TEXTAREA_CONTROL extends WSF_CONTROL window.states[@control_name]['text'] = @$el.val() if window.states[@control_name]['callback_change'] trigger_callback(@control_name, 'change') + @trigger('change') + + value:()-> + return @$el.val() + + update: (state) -> + if state.text? + window.states[@control_name]['text'] = state.text + @$el.val(state.text) + +class WSF_TEXTAREA_CONTROL extends WSF_CONTROL + attach_events: () -> + self = @ + @$el.change () -> + self.change() + + change: () -> + window.states[@control_name]['text'] = @$el.val() + if window.states[@control_name]['callback_change'] + trigger_callback(@control_name, 'change') + @trigger('change') + + value:()-> + return @$el.val() update: (state) -> if state.text? @@ -76,23 +144,85 @@ class WSF_CHECKBOX_CONTROL extends WSF_CONTROL self = @ @$el.change ()-> self.change() + change: ()-> #update local state window.states[@control_name]['checked'] = @$el.is(':checked') if window.states[@control_name]['callback_change'] trigger_callback(@control_name, 'change') + @trigger('change') + + value:()-> + return @$el.is(':checked') update: (state) -> if state.text? window.states[@control_name]['checked'] = state.checked @$el.prop('checked',state.checked) +class WSF_FORM_ELEMENT_CONTROL extends WSF_CONTROL + attach_events: ()-> + self = @ + @value_control = controls[window.states[@control_name]['value_control']] + if @value_control? + #subscribe to change event on value_control + @value_control.on('change',@change,@) + @serverside_validator = false + #Initialize validators + @validators = [] + for validator in window.states[@control_name]['validators'] + if validatormap[validator.name]? + @validators.push new validatormap[validator.name](@,validator) + else + #Use serverside validator if no js implementation + @serverside_validator = true + return + + #value_control changed run validators + change: ()-> + for validator in @validators + if not validator.validate() + @showerror(validator.error) + return + @showerror("") + #If there is validator which is not implemented in js ask server to validate + if @serverside_validator + trigger_callback(@control_name, 'validate') + return + + showerror: (message)-> + @$el.removeClass("has-error") + @$el.find(".validation").remove() + if message.length>0 + @$el.addClass("has-error") + errordiv = $("
").addClass('help-block').addClass('validation').text(message) + @$el.find(".col-lg-10").append(errordiv) + + update: (state) -> + if state.error? + @showerror(state.error) + + value: ()-> + @value_control.value() + +class WSF_HTML_CONTROL extends WSF_CONTROL + + value:()-> + return @$el.html() + + update: (state) -> + if state.html? + window.states[@control_name]['html'] = state.html + @$el.html(state.html) + #map class name to effective class typemap = "WSF_BUTTON_CONTROL":WSF_BUTTON_CONTROL - "WSF_TEXT_CONTROL":WSF_TEXT_CONTROL + "WSF_INPUT_CONTROL":WSF_INPUT_CONTROL "WSF_TEXTAREA_CONTROL":WSF_TEXTAREA_CONTROL "WSF_CHECKBOX_CONTROL":WSF_CHECKBOX_CONTROL + "WSF_FORM_ELEMENT_CONTROL": WSF_FORM_ELEMENT_CONTROL + "WSF_HTML_CONTROL": WSF_HTML_CONTROL #create a js class for each control for name,state of window.states @@ -103,4 +233,6 @@ for name,state of window.states #create class if type? and typemap[type]? controls[name]=new typemap[type](name,$el) +for name,state of window.states + controls[name]?.attach_events() diff --git a/examples/widgetapp/widget.js b/examples/widgetapp/widget.js index 9cda85af..cab1a948 100644 --- a/examples/widgetapp/widget.js +++ b/examples/widgetapp/widget.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.6.1 (function() { - var $el, WSF_BUTTON_CONTROL, WSF_CHECKBOX_CONTROL, WSF_CONTROL, WSF_TEXTAREA_CONTROL, WSF_TEXT_CONTROL, controls, name, state, trigger_callback, type, typemap, _ref, + var $el, WSF_BUTTON_CONTROL, WSF_CHECKBOX_CONTROL, WSF_CONTROL, WSF_FORM_ELEMENT_CONTROL, WSF_HTML_CONTROL, WSF_INPUT_CONTROL, WSF_REGEXP_VALIDATOR, WSF_TEXTAREA_CONTROL, WSF_VALIDATOR, controls, name, state, trigger_callback, type, typemap, validatormap, _ref, _ref1, _ref2, __hasProp = {}.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; @@ -23,12 +23,52 @@ }); }; + WSF_VALIDATOR = (function() { + + function WSF_VALIDATOR(parent_control, settings) { + this.parent_control = parent_control; + this.settings = settings; + this.error = this.settings.error; + return; + } + + WSF_VALIDATOR.prototype.validate = function() { + return true; + }; + + return WSF_VALIDATOR; + + })(); + + WSF_REGEXP_VALIDATOR = (function(_super) { + + __extends(WSF_REGEXP_VALIDATOR, _super); + + function WSF_REGEXP_VALIDATOR() { + WSF_REGEXP_VALIDATOR.__super__.constructor.apply(this, arguments); + this.pattern = new RegExp(this.settings.expression, 'g'); + } + + WSF_REGEXP_VALIDATOR.prototype.validate = function() { + var res, val; + val = this.parent_control.value(); + res = val.match(this.pattern); + return res !== null; + }; + + return WSF_REGEXP_VALIDATOR; + + })(WSF_VALIDATOR); + + validatormap = { + "WSF_REGEXP_VALIDATOR": WSF_REGEXP_VALIDATOR + }; + WSF_CONTROL = (function() { function WSF_CONTROL(control_name, $el) { this.control_name = control_name; this.$el = $el; - this.attach_events(); return; } @@ -36,6 +76,33 @@ WSF_CONTROL.prototype.update = function(state) {}; + WSF_CONTROL.prototype.on = function(name, callback, context) { + if (this._events == null) { + this._events = {}; + } + if (this._events[name] == null) { + this._events[name] = []; + } + this._events[name].push({ + callback: callback, + context: context + }); + return this; + }; + + WSF_CONTROL.prototype.trigger = function(name) { + var ev, _i, _len, _ref, _ref1; + if (((_ref = this._events) != null ? _ref[name] : void 0) == null) { + return this; + } + _ref1 = this._events[name]; + for (_i = 0, _len = _ref1.length; _i < _len; _i++) { + ev = _ref1[_i]; + ev.callback.call(ev.context); + } + return this; + }; + return WSF_CONTROL; })(); @@ -76,15 +143,15 @@ })(WSF_CONTROL); - WSF_TEXT_CONTROL = (function(_super) { + WSF_INPUT_CONTROL = (function(_super) { - __extends(WSF_TEXT_CONTROL, _super); + __extends(WSF_INPUT_CONTROL, _super); - function WSF_TEXT_CONTROL() { - return WSF_TEXT_CONTROL.__super__.constructor.apply(this, arguments); + function WSF_INPUT_CONTROL() { + return WSF_INPUT_CONTROL.__super__.constructor.apply(this, arguments); } - WSF_TEXT_CONTROL.prototype.attach_events = function() { + WSF_INPUT_CONTROL.prototype.attach_events = function() { var self; self = this; return this.$el.change(function() { @@ -92,21 +159,26 @@ }); }; - WSF_TEXT_CONTROL.prototype.change = function() { + WSF_INPUT_CONTROL.prototype.change = function() { window.states[this.control_name]['text'] = this.$el.val(); if (window.states[this.control_name]['callback_change']) { - return trigger_callback(this.control_name, 'change'); + trigger_callback(this.control_name, 'change'); } + return this.trigger('change'); }; - WSF_TEXT_CONTROL.prototype.update = function(state) { + WSF_INPUT_CONTROL.prototype.value = function() { + return this.$el.val(); + }; + + WSF_INPUT_CONTROL.prototype.update = function(state) { if (state.text != null) { window.states[this.control_name]['text'] = state.text; return this.$el.val(state.text); } }; - return WSF_TEXT_CONTROL; + return WSF_INPUT_CONTROL; })(WSF_CONTROL); @@ -129,8 +201,52 @@ WSF_TEXTAREA_CONTROL.prototype.change = function() { window.states[this.control_name]['text'] = this.$el.val(); if (window.states[this.control_name]['callback_change']) { - return trigger_callback(this.control_name, 'change'); + trigger_callback(this.control_name, 'change'); } + return this.trigger('change'); + }; + + WSF_TEXTAREA_CONTROL.prototype.value = function() { + return this.$el.val(); + }; + + WSF_TEXTAREA_CONTROL.prototype.update = function(state) { + if (state.text != null) { + window.states[this.control_name]['text'] = state.text; + return this.$el.val(state.text); + } + }; + + return WSF_TEXTAREA_CONTROL; + + })(WSF_CONTROL); + + WSF_TEXTAREA_CONTROL = (function(_super) { + + __extends(WSF_TEXTAREA_CONTROL, _super); + + function WSF_TEXTAREA_CONTROL() { + return WSF_TEXTAREA_CONTROL.__super__.constructor.apply(this, arguments); + } + + WSF_TEXTAREA_CONTROL.prototype.attach_events = function() { + var self; + self = this; + return this.$el.change(function() { + return self.change(); + }); + }; + + WSF_TEXTAREA_CONTROL.prototype.change = function() { + window.states[this.control_name]['text'] = this.$el.val(); + if (window.states[this.control_name]['callback_change']) { + trigger_callback(this.control_name, 'change'); + } + return this.trigger('change'); + }; + + WSF_TEXTAREA_CONTROL.prototype.value = function() { + return this.$el.val(); }; WSF_TEXTAREA_CONTROL.prototype.update = function(state) { @@ -163,8 +279,13 @@ WSF_CHECKBOX_CONTROL.prototype.change = function() { window.states[this.control_name]['checked'] = this.$el.is(':checked'); if (window.states[this.control_name]['callback_change']) { - return trigger_callback(this.control_name, 'change'); + trigger_callback(this.control_name, 'change'); } + return this.trigger('change'); + }; + + WSF_CHECKBOX_CONTROL.prototype.value = function() { + return this.$el.is(':checked'); }; WSF_CHECKBOX_CONTROL.prototype.update = function(state) { @@ -178,11 +299,105 @@ })(WSF_CONTROL); + WSF_FORM_ELEMENT_CONTROL = (function(_super) { + + __extends(WSF_FORM_ELEMENT_CONTROL, _super); + + function WSF_FORM_ELEMENT_CONTROL() { + return WSF_FORM_ELEMENT_CONTROL.__super__.constructor.apply(this, arguments); + } + + WSF_FORM_ELEMENT_CONTROL.prototype.attach_events = function() { + var self, validator, _i, _len, _ref; + self = this; + this.value_control = controls[window.states[this.control_name]['value_control']]; + if (this.value_control != null) { + this.value_control.on('change', this.change, this); + } + this.serverside_validator = false; + this.validators = []; + _ref = window.states[this.control_name]['validators']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + validator = _ref[_i]; + if (validatormap[validator.name] != null) { + this.validators.push(new validatormap[validator.name](this, validator)); + } else { + this.serverside_validator = true; + } + } + }; + + WSF_FORM_ELEMENT_CONTROL.prototype.change = function() { + var validator, _i, _len, _ref; + _ref = this.validators; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + validator = _ref[_i]; + if (!validator.validate()) { + this.showerror(validator.error); + return; + } + } + this.showerror(""); + if (this.serverside_validator) { + trigger_callback(this.control_name, 'validate'); + } + }; + + WSF_FORM_ELEMENT_CONTROL.prototype.showerror = function(message) { + var errordiv; + this.$el.removeClass("has-error"); + this.$el.find(".validation").remove(); + if (message.length > 0) { + this.$el.addClass("has-error"); + errordiv = $("
").addClass('help-block').addClass('validation').text(message); + return this.$el.find(".col-lg-10").append(errordiv); + } + }; + + WSF_FORM_ELEMENT_CONTROL.prototype.update = function(state) { + if (state.error != null) { + return this.showerror(state.error); + } + }; + + WSF_FORM_ELEMENT_CONTROL.prototype.value = function() { + return this.value_control.value(); + }; + + return WSF_FORM_ELEMENT_CONTROL; + + })(WSF_CONTROL); + + WSF_HTML_CONTROL = (function(_super) { + + __extends(WSF_HTML_CONTROL, _super); + + function WSF_HTML_CONTROL() { + return WSF_HTML_CONTROL.__super__.constructor.apply(this, arguments); + } + + WSF_HTML_CONTROL.prototype.value = function() { + return this.$el.html(); + }; + + WSF_HTML_CONTROL.prototype.update = function(state) { + if (state.html != null) { + window.states[this.control_name]['html'] = state.html; + return this.$el.html(state.html); + } + }; + + return WSF_HTML_CONTROL; + + })(WSF_CONTROL); + typemap = { "WSF_BUTTON_CONTROL": WSF_BUTTON_CONTROL, - "WSF_TEXT_CONTROL": WSF_TEXT_CONTROL, + "WSF_INPUT_CONTROL": WSF_INPUT_CONTROL, "WSF_TEXTAREA_CONTROL": WSF_TEXTAREA_CONTROL, - "WSF_CHECKBOX_CONTROL": WSF_CHECKBOX_CONTROL + "WSF_CHECKBOX_CONTROL": WSF_CHECKBOX_CONTROL, + "WSF_FORM_ELEMENT_CONTROL": WSF_FORM_ELEMENT_CONTROL, + "WSF_HTML_CONTROL": WSF_HTML_CONTROL }; _ref = window.states; @@ -195,4 +410,12 @@ } } + _ref1 = window.states; + for (name in _ref1) { + state = _ref1[name]; + if ((_ref2 = controls[name]) != null) { + _ref2.attach_events(); + } + } + }).call(this); diff --git a/library/server/wsf_html/webcontrol/validators/wsf_decimal_validator.e b/library/server/wsf_html/webcontrol/validators/wsf_decimal_validator.e index f7fd7f6d..ad68866d 100644 --- a/library/server/wsf_html/webcontrol/validators/wsf_decimal_validator.e +++ b/library/server/wsf_html/webcontrol/validators/wsf_decimal_validator.e @@ -18,7 +18,7 @@ feature {NONE} make_decimal_validator (e: STRING) do - make_regexp_validator ("[0-9]+(\\.[0-9]*)?|\\.[0-9]+", e) + make_regexp_validator ("^[0-9]+(\.[0-9]*)?$|^\.[0-9]+$", e) end end diff --git a/library/server/wsf_html/webcontrol/validators/wsf_email_validator.e b/library/server/wsf_html/webcontrol/validators/wsf_email_validator.e index 68ff9360..552aead7 100644 --- a/library/server/wsf_html/webcontrol/validators/wsf_email_validator.e +++ b/library/server/wsf_html/webcontrol/validators/wsf_email_validator.e @@ -14,7 +14,7 @@ inherit create make_email_validator -feature{NONE} +feature {NONE} make_email_validator (e: STRING) do diff --git a/library/server/wsf_html/webcontrol/validators/wsf_regexp_validator.e b/library/server/wsf_html/webcontrol/validators/wsf_regexp_validator.e index 8e20b710..5dcc6e7c 100644 --- a/library/server/wsf_html/webcontrol/validators/wsf_regexp_validator.e +++ b/library/server/wsf_html/webcontrol/validators/wsf_regexp_validator.e @@ -10,6 +10,9 @@ class inherit WSF_VALIDATOR [STRING] + redefine + state + end create make_regexp_validator @@ -18,21 +21,32 @@ feature {NONE} make_regexp_validator (r, e: STRING) do - make(e) + make (e) regexp_string := r create regexp - regexp.compile (r) end feature -- Implementation - validate (input: STRING): BOOLEAN + is_valid (input: STRING): BOOLEAN do + --Only compile when used + if not regexp.is_compiled then + regexp.compile (regexp_string) + end Result := regexp.matches (input) end feature + state: JSON_OBJECT + do + create Result.make + Result.put (create {JSON_STRING}.make_json ("WSF_REGEXP_VALIDATOR"), create {JSON_STRING}.make_json ("name")) + Result.put (create {JSON_STRING}.make_json (regexp_string), create {JSON_STRING}.make_json ("expression")) + Result.put (create {JSON_STRING}.make_json (error), create {JSON_STRING}.make_json ("error")) + end + regexp_string: STRING regexp: REGULAR_EXPRESSION diff --git a/library/server/wsf_html/webcontrol/validators/wsf_validatable.e b/library/server/wsf_html/webcontrol/validators/wsf_validatable.e new file mode 100644 index 00000000..4b7a60fa --- /dev/null +++ b/library/server/wsf_html/webcontrol/validators/wsf_validatable.e @@ -0,0 +1,20 @@ +note + description: "Summary description for {WSF_VALIDATABLE}." + author: "" + date: "$Date$" + revision: "$Revision$" + +deferred class + WSF_VALIDATABLE + +feature + + validate + deferred + end + + is_valid: BOOLEAN + deferred + end + +end diff --git a/library/server/wsf_html/webcontrol/validators/wsf_validator.e b/library/server/wsf_html/webcontrol/validators/wsf_validator.e index 58415781..ad3f27bd 100644 --- a/library/server/wsf_html/webcontrol/validators/wsf_validator.e +++ b/library/server/wsf_html/webcontrol/validators/wsf_validator.e @@ -16,7 +16,14 @@ feature {NONE} feature - validate (input: G): BOOLEAN + state: JSON_OBJECT + do + create Result.make + Result.put (create {JSON_STRING}.make_json (generator), create {JSON_STRING}.make_json ("name")) + Result.put (create {JSON_STRING}.make_json (error), create {JSON_STRING}.make_json ("error")) + end + + is_valid (input: G): BOOLEAN deferred end diff --git a/library/server/wsf_html/webcontrol/wsf_button_control.e b/library/server/wsf_html/webcontrol/wsf_button_control.e index 2e9a901d..cfd5ec05 100644 --- a/library/server/wsf_html/webcontrol/wsf_button_control.e +++ b/library/server/wsf_html/webcontrol/wsf_button_control.e @@ -19,6 +19,8 @@ feature {NONE} make_button (n: STRING; t: STRING) do make (n, "button") + add_class ("btn") + add_class ("btn-default") text := t end diff --git a/library/server/wsf_html/webcontrol/wsf_checkbox_control.e b/library/server/wsf_html/webcontrol/wsf_checkbox_control.e index b1281ac2..42233d74 100644 --- a/library/server/wsf_html/webcontrol/wsf_checkbox_control.e +++ b/library/server/wsf_html/webcontrol/wsf_checkbox_control.e @@ -68,7 +68,7 @@ feature -- Implementation if checked then attributes := attributes + " checked" end - Result := render_tag_with_tagname ("div",render_tag_with_tagname ("label", render_tag ("", attributes) + " " + label, "",""), "","checkbox") + Result := render_tag_with_tagname ("div", render_tag_with_tagname ("label", render_tag ("", attributes) + " " + label, "", ""), "", "checkbox") end value: BOOLEAN diff --git a/library/server/wsf_html/webcontrol/wsf_control.e b/library/server/wsf_html/webcontrol/wsf_control.e index 9032e940..6f61e0b3 100644 --- a/library/server/wsf_html/webcontrol/wsf_control.e +++ b/library/server/wsf_html/webcontrol/wsf_control.e @@ -97,7 +97,7 @@ feature do l_attributes := attributes if not css_classes_string.is_empty then - l_attributes := " class=%"" + css_classes_string + "%"" + l_attributes := l_attributes + " class=%"" + css_classes_string + "%"" end Result := "<" + tag + " id=%"" + control_name + "%" data-name=%"" + control_name + "%" data-type=%"" + generator + "%" " + l_attributes if body.is_empty and not tag.is_equal ("textarea") then diff --git a/library/server/wsf_html/webcontrol/wsf_form_control.e b/library/server/wsf_html/webcontrol/wsf_form_control.e index dec7fa21..e4048080 100644 --- a/library/server/wsf_html/webcontrol/wsf_form_control.e +++ b/library/server/wsf_html/webcontrol/wsf_form_control.e @@ -11,6 +11,8 @@ inherit WSF_MULTI_CONTROL [WSF_CONTROL] + WSF_VALIDATABLE + create make_form_control @@ -24,22 +26,23 @@ feature {NONE} feature -- Validation - validate: BOOLEAN + validate do - Result := True + is_valid := True across controls as c until - Result = False + is_valid = False loop - -- TODO: Change generic parameter of elm from ANY to if something like that is available in Eiffel. - -- Otherwise, check separately for STRING, LIST... - if attached {WSF_FORM_ELEMENT_CONTROL[ANY]} c.item as elem then + if attached {WSF_VALIDATABLE} c.item as elem then + elem.validate if not elem.is_valid then - Result := False + is_valid := False end end end end + is_valid: BOOLEAN + end diff --git a/library/server/wsf_html/webcontrol/wsf_form_element_control.e b/library/server/wsf_html/webcontrol/wsf_form_element_control.e index 2550e79d..3fbf7d98 100644 --- a/library/server/wsf_html/webcontrol/wsf_form_element_control.e +++ b/library/server/wsf_html/webcontrol/wsf_form_element_control.e @@ -11,9 +11,13 @@ inherit WSF_CONTROL redefine - read_state_changes,load_state,read_state + read_state_changes, + load_state, + read_state end + WSF_VALIDATABLE + create make_form_element, make_form_element_with_validators @@ -31,31 +35,19 @@ feature {NONE} do make (c.control_name + "_container", "div") add_class ("form-group") - if attached {WSF_TEXT_CONTROL}c or attached {WSF_TEXTAREA_CONTROL}c then + if attached {WSF_INPUT_CONTROL} c or attached {WSF_TEXTAREA_CONTROL} c then c.add_class ("form-control") - end + if attached {WSF_HTML_CONTROL} c then + c.add_class ("form-control-static") + end + value_control := c validators := v label := a_label error := "" end -feature - - is_valid (): BOOLEAN - do - Result := True - across - validators as c - until - not Result - loop - if not c.item.validate (value_control.value) then - Result := False - end - end - end feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- STATE MANAGEMENT load_state (new_states: JSON_OBJECT) @@ -67,27 +59,37 @@ feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- STATE MANAGEMENT set_state (new_state: JSON_OBJECT) do - value_control.set_state(new_state) + value_control.set_state (new_state) end read_state (states: JSON_OBJECT) -- Read states in subcontrols do Precursor (states) - value_control.read_state(states) + value_control.read_state (states) end read_state_changes (states: JSON_OBJECT) -- Read states_changes in subcontrols do Precursor (states) - value_control.read_state_changes(states) + value_control.read_state_changes (states) end state: JSON_OBJECT --Read state + local + validator_description: JSON_ARRAY do create Result.make + create validator_description.make_array + across + validators as v + loop + validator_description.add (v.item.state) + end + Result.put (create {JSON_STRING}.make_json (value_control.control_name), create {JSON_STRING}.make_json ("value_control")) + Result.put (validator_description, create {JSON_STRING}.make_json ("validators")) end feature --EVENT HANDLING @@ -96,12 +98,15 @@ feature --EVENT HANDLING -- Pass callback to subcontrols do if equal (cname, control_name) then + if event.is_equal ("validate") then + validate + end else value_control.handle_callback (cname, event) end end -feature --Implementation +feature --Implementation render: STRING local @@ -117,6 +122,42 @@ feature --Implementation Result := render_tag (body, "") end +feature -- Validation + + add_validator (v: WSF_VALIDATOR [G]) + do + validators.extend (v) + end + + set_error (e: STRING) + do + error := e + state_changes.replace (create {JSON_STRING}.make_json (e), create {JSON_STRING}.make_json ("error")) + end + + validate + local + current_value: G + do + current_value := value_control.value + is_valid := True + across + validators as c + until + not is_valid + loop + if not c.item.is_valid (current_value) then + is_valid := False + set_error (c.item.error) + end + end + if is_valid then + set_error ("") + end + end + + is_valid: BOOLEAN + feature value_control: WSF_VALUE_CONTROL [G] diff --git a/library/server/wsf_html/webcontrol/wsf_html_control.e b/library/server/wsf_html/webcontrol/wsf_html_control.e new file mode 100644 index 00000000..0df4ebf6 --- /dev/null +++ b/library/server/wsf_html/webcontrol/wsf_html_control.e @@ -0,0 +1,74 @@ +note + description: "Summary description for {WSF_html_CONTROL}." + author: "" + date: "$Date$" + revision: "$Revision$" + +class + WSF_HTML_CONTROL + +inherit + + WSF_VALUE_CONTROL [STRING] + +create + make_html + +feature {NONE} + + make_html (n,t,v: STRING) + do + make (n, t) + html := v + end + +feature {WSF_PAGE_CONTROL, WSF_CONTROL} -- STATE MANAGEMENT + + set_state (new_state: JSON_OBJECT) + -- Restore html from json + do + if attached {JSON_STRING} new_state.item (create {JSON_STRING}.make_json ("html")) as new_html then + html := new_html.unescaped_string_32 + end + end + + state: JSON_OBJECT + -- Return state which contains the current html and if there is an event handle attached + do + create Result.make + Result.put (create {JSON_STRING}.make_json (html), create {JSON_STRING}.make_json ("html")) + end + +feature --EVENT HANDLING + + handle_callback (cname: STRING; event: STRING) + do + end + +feature -- Implementation + + render: STRING + do + Result := render_tag (html,"") + end + + set_html (t: STRING) + do + if not t.is_equal (html) then + html := t + state_changes.replace (create {JSON_STRING}.make_json (html), create {JSON_STRING}.make_json ("html")) + end + end + + value: STRING + do + Result := html + end + +feature + + html: STRING + + +end + diff --git a/library/server/wsf_html/webcontrol/wsf_text_control.e b/library/server/wsf_html/webcontrol/wsf_input_control.e similarity index 90% rename from library/server/wsf_html/webcontrol/wsf_text_control.e rename to library/server/wsf_html/webcontrol/wsf_input_control.e index 3a03340f..0499a1d9 100644 --- a/library/server/wsf_html/webcontrol/wsf_text_control.e +++ b/library/server/wsf_html/webcontrol/wsf_input_control.e @@ -5,20 +5,21 @@ note revision: "$Revision$" class - WSF_TEXT_CONTROL + WSF_INPUT_CONTROL inherit WSF_VALUE_CONTROL [STRING] create - make_text + make_input feature {NONE} - make_text (n: STRING; v: STRING) + make_input (n: STRING; v: STRING) do make (n, "input") + type := "text" text := v end @@ -61,7 +62,7 @@ feature -- Implementation render: STRING do - Result := render_tag ("", "type=%"text%" value=%"" + text + "%"") + Result := render_tag ("", "type=%"" + type + "%" value=%"" + text + "%"") end set_text (t: STRING) @@ -81,6 +82,8 @@ feature text: STRING + type: STRING + change_event: detachable PROCEDURE [ANY, TUPLE []] end diff --git a/library/server/wsf_html/webcontrol/wsf_multi_control.e b/library/server/wsf_html/webcontrol/wsf_multi_control.e index 20521e12..be5c952c 100644 --- a/library/server/wsf_html/webcontrol/wsf_multi_control.e +++ b/library/server/wsf_html/webcontrol/wsf_multi_control.e @@ -5,7 +5,7 @@ note revision: "$Revision$" class - WSF_MULTI_CONTROL[G -> WSF_CONTROL] + WSF_MULTI_CONTROL [G -> WSF_CONTROL] inherit diff --git a/library/server/wsf_html/webcontrol/wsf_page_control.e b/library/server/wsf_html/webcontrol/wsf_page_control.e index 615118b9..d15e1ff7 100644 --- a/library/server/wsf_html/webcontrol/wsf_page_control.e +++ b/library/server/wsf_html/webcontrol/wsf_page_control.e @@ -78,7 +78,6 @@ feature control.read_state (states) data := "" data.append ("") - data.append ("") data.append (control.render) data.append ("