Extended autocompletion with customized templates
This commit is contained in:
@@ -34,6 +34,8 @@ feature {NONE} -- Initialization
|
||||
-- router.map (create {WSF_URI_MAPPING}.make ("/hello", create {WSF_AGENT_URI_HANDLER}.make (agent execute_hello)))
|
||||
map_agent_uri ("/", agent execute_hello, Void)
|
||||
map_agent_uri ("/widget.js", agent load_js, Void)
|
||||
map_agent_uri ("/widget.css", agent load_css, Void)
|
||||
map_agent_uri ("/bootstrap.min.css", agent load_bootstrap, Void)
|
||||
end
|
||||
|
||||
feature -- Helper: mapping
|
||||
@@ -63,4 +65,20 @@ feature -- Execution
|
||||
res.send (f)
|
||||
end
|
||||
|
||||
load_css (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: WSF_FILE_RESPONSE
|
||||
do
|
||||
create f.make_html ("widget.css")
|
||||
res.send (f)
|
||||
end
|
||||
|
||||
load_bootstrap (req: WSF_REQUEST; res: WSF_RESPONSE)
|
||||
local
|
||||
f: WSF_FILE_RESPONSE
|
||||
do
|
||||
create f.make_html ("bootstrap.min.css")
|
||||
res.send (f)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
9
examples/widgetapp/bootstrap.min.css
vendored
Normal file
9
examples/widgetapp/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
48
examples/widgetapp/flag_autocompletion.e
Normal file
48
examples/widgetapp/flag_autocompletion.e
Normal file
@@ -0,0 +1,48 @@
|
||||
note
|
||||
description: "Summary description for {FLAG_AUTOCOMPLETION}."
|
||||
author: ""
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
FLAG_AUTOCOMPLETION
|
||||
|
||||
inherit
|
||||
|
||||
WSF_AUTOCOMPLETION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (l: ITERABLE [TUPLE [STRING, STRING]])
|
||||
do
|
||||
template := "<img src=%"http://www.famfamfam.com/lab/icons/flags/icons/gif/{{=flag}}.gif%"> {{=value}}";
|
||||
list := l
|
||||
end
|
||||
|
||||
feature -- Implementation
|
||||
|
||||
autocompletion (input: STRING): JSON_ARRAY
|
||||
local
|
||||
o: JSON_OBJECT
|
||||
do
|
||||
create Result.make_array
|
||||
across
|
||||
list as c
|
||||
loop
|
||||
if attached {STRING} c.item.item (1) as first and attached {STRING} c.item.item (2) as second then
|
||||
if second.as_lower.has_substring (input.as_lower) then
|
||||
create o.make
|
||||
o.put (create {JSON_STRING}.make_json (first), "flag")
|
||||
o.put (create {JSON_STRING}.make_json (second), "value")
|
||||
Result.add (o)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
list: ITERABLE [TUPLE [STRING, STRING]]
|
||||
|
||||
end
|
||||
@@ -21,10 +21,14 @@ feature
|
||||
form: WSF_FORM_CONTROL
|
||||
n1_container: WSF_FORM_ELEMENT_CONTROL [STRING]
|
||||
n2_container: WSF_FORM_ELEMENT_CONTROL [STRING]
|
||||
n3_container: WSF_FORM_ELEMENT_CONTROL [STRING]
|
||||
cats_container: WSF_FORM_ELEMENT_CONTROL [LIST [STRING]]
|
||||
s: FLAG_AUTOCOMPLETION
|
||||
do
|
||||
create s.make(<<["dz", "Algeria"], ["be", "Belgium"] , ["ca", "Canada"],["de", "Deutschland"], ["england", "England"], ["fi", "Finland"], ["gr", "Greece"], ["hu", "Hungary"]>>)
|
||||
create textbox1.make_input ("txtBox1", "1")
|
||||
create textbox2.make_input ("txtBox2", "2")
|
||||
create autocompletion1.make_autocomplete ("autocompletion1", s)
|
||||
create button1.make_button ("sample_button1", "SUM")
|
||||
create textbox_result.make_html ("txtBox3", "p", "")
|
||||
button1.set_click_event (agent handle_click)
|
||||
@@ -39,8 +43,10 @@ feature
|
||||
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"))
|
||||
create n3_container.make_form_element ("Autoc1", autocompletion1)
|
||||
form.add_control (n1_container)
|
||||
form.add_control (n2_container)
|
||||
form.add_control (n3_container)
|
||||
create cats_container.make_form_element ("Categories", cklist)
|
||||
cats_container.add_validator (create {WSF_MIN_VALIDATOR [STRING]}.make_min_validator (1, "Choose at least one category"))
|
||||
cats_container.add_validator (create {WSF_MAX_VALIDATOR [STRING]}.make_max_validator (1, "Choose at most one category"))
|
||||
@@ -82,6 +88,8 @@ feature
|
||||
|
||||
textbox2: WSF_INPUT_CONTROL
|
||||
|
||||
autocompletion1: WSF_AUTOCOMPLETE_CONTROL
|
||||
|
||||
cklist: WSF_CHECKBOX_LIST_CONTROL
|
||||
|
||||
textbox_result: WSF_HTML_CONTROL
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
cache = {}
|
||||
template = tmpl = (str, data) ->
|
||||
# Simple JavaScript Templating
|
||||
# John Resig - http://ejohn.org/ - MIT Licensed
|
||||
fn = (if not /\W/.test(str) then cache[str] = cache[str] or tmpl(str) else new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + "with(obj){p.push('" + str.replace(/[\r\t\n]/g, " ").split("{{").join("\t").replace(/((^|}})[^\t]*)'/g, "$1\r").replace(/\t=(.*?)}}/g, "',$1,'").split("\t").join("');").split("}}").join("p.push('").split("\r").join("\\'") + "');}return p.join('');"))
|
||||
(if data then fn(data) else fn)
|
||||
|
||||
Mini =
|
||||
compile:(t)->
|
||||
{
|
||||
render:template(t)
|
||||
}
|
||||
|
||||
trigger_callback = (control_name,event)->
|
||||
$.ajax
|
||||
data:
|
||||
control_name: control_name
|
||||
event: event
|
||||
states: JSON.stringify(states)
|
||||
states: JSON.stringify(window.states)
|
||||
cache: no
|
||||
.done (new_states)->
|
||||
#Update all classes
|
||||
@@ -118,11 +131,21 @@ class WSF_TEXTAREA_CONTROL extends WSF_INPUT_CONTROL
|
||||
class WSF_AUTOCOMPLETE_CONTROL extends WSF_INPUT_CONTROL
|
||||
attach_events: () ->
|
||||
super
|
||||
self = @
|
||||
@$el.typeahead({
|
||||
name: @control_name
|
||||
local: ["one",
|
||||
"two",
|
||||
"three"]
|
||||
template: window.states[@control_name]['template']
|
||||
engine: Mini
|
||||
remote:
|
||||
url:""
|
||||
replace: (url, uriEncodedQuery) ->
|
||||
window.states[self.control_name]['text'] = self.$el.val()
|
||||
'?' + $.param
|
||||
control_name: self.control_name
|
||||
event: 'autocomplete'
|
||||
states: JSON.stringify(window.states)
|
||||
filter: (parsedResponse) ->
|
||||
parsedResponse[self.control_name]['suggestions']
|
||||
})
|
||||
|
||||
class WSF_CHECKBOX_CONTROL extends WSF_CONTROL
|
||||
|
||||
77
examples/widgetapp/widget.css
Normal file
77
examples/widgetapp/widget.css
Normal file
@@ -0,0 +1,77 @@
|
||||
/* ignore this line */
|
||||
.container { margin:30px; }
|
||||
|
||||
.twitter-typeahead {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
.twitter-typeahead .tt-query,
|
||||
.twitter-typeahead .tt-hint {
|
||||
margin-bottom: 0;
|
||||
width:100%;
|
||||
height: 34px;
|
||||
position: absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
}
|
||||
.twitter-typeahead .tt-hint {
|
||||
color:#a1a1a1;
|
||||
z-index: 1;
|
||||
padding: 6px 12px;
|
||||
border:1px solid transparent;
|
||||
}
|
||||
.twitter-typeahead .tt-query {
|
||||
z-index: 2;
|
||||
border-radius: 4px!important;
|
||||
/* add these 2 statements if you have an appended input group */
|
||||
border-top-right-radius: 0!important;
|
||||
border-bottom-right-radius: 0!important;
|
||||
/* add these 2 statements if you have an prepended input group */
|
||||
/* border-top-left-radius: 0!important;
|
||||
border-bottom-left-radius: 0!important; */
|
||||
}
|
||||
|
||||
.tt-dropdown-menu {
|
||||
min-width: 160px;
|
||||
margin-top: 2px;
|
||||
padding: 5px 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid rgba(0,0,0,.2);
|
||||
*border-right-width: 2px;
|
||||
*border-bottom-width: 2px;
|
||||
-webkit-border-radius: 6px;
|
||||
-moz-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
box-shadow: 0 5px 10px rgba(0,0,0,.2);
|
||||
-webkit-background-clip: padding-box;
|
||||
-moz-background-clip: padding;
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
.tt-suggestion {
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor {
|
||||
color: #fff;
|
||||
background-color: #0081c2;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0077b3);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0077b3);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
|
||||
}
|
||||
|
||||
.tt-suggestion.tt-is-under-cursor a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.tt-suggestion p {
|
||||
margin: 0;
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
// Generated by CoffeeScript 1.6.1
|
||||
(function() {
|
||||
var $el, WSF_BUTTON_CONTROL, WSF_CHECKBOX_CONTROL, WSF_CHECKBOX_LIST_CONTROL, WSF_CONTROL, WSF_FORM_ELEMENT_CONTROL, WSF_HTML_CONTROL, WSF_INPUT_CONTROL, WSF_MAX_VALIDATOR, WSF_MIN_VALIDATOR, WSF_REGEXP_VALIDATOR, WSF_TEXTAREA_CONTROL, WSF_VALIDATOR, controls, name, state, trigger_callback, type, typemap, validatormap, _ref, _ref1, _ref2,
|
||||
var $el, Mini, WSF_AUTOCOMPLETE_CONTROL, WSF_BUTTON_CONTROL, WSF_CHECKBOX_CONTROL, WSF_CHECKBOX_LIST_CONTROL, WSF_CONTROL, WSF_FORM_ELEMENT_CONTROL, WSF_HTML_CONTROL, WSF_INPUT_CONTROL, WSF_MAX_VALIDATOR, WSF_MIN_VALIDATOR, WSF_REGEXP_VALIDATOR, WSF_TEXTAREA_CONTROL, WSF_VALIDATOR, cache, controls, name, state, template, tmpl, 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; };
|
||||
|
||||
cache = {};
|
||||
|
||||
template = tmpl = function(str, data) {
|
||||
var fn;
|
||||
fn = (!/\W/.test(str) ? cache[str] = cache[str] || tmpl(str) : new Function("obj", "var p=[],print=function(){p.push.apply(p,arguments);};" + "with(obj){p.push('" + str.replace(/[\r\t\n]/g, " ").split("{{").join("\t").replace(/((^|}})[^\t]*)'/g, "$1\r").replace(/\t=(.*?)}}/g, "',$1,'").split("\t").join("');").split("}}").join("p.push('").split("\r").join("\\'") + "');}return p.join('');"));
|
||||
if (data) {
|
||||
return fn(data);
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
Mini = {
|
||||
compile: function(t) {
|
||||
return {
|
||||
render: template(t)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
trigger_callback = function(control_name, event) {
|
||||
return $.ajax({
|
||||
data: {
|
||||
control_name: control_name,
|
||||
event: event,
|
||||
states: JSON.stringify(states)
|
||||
states: JSON.stringify(window.states)
|
||||
},
|
||||
cache: false
|
||||
}).done(function(new_states) {
|
||||
@@ -228,75 +248,46 @@
|
||||
return WSF_TEXTAREA_CONTROL.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
WSF_TEXTAREA_CONTROL.prototype.attach_events = function() {
|
||||
return WSF_TEXTAREA_CONTROL;
|
||||
|
||||
})(WSF_INPUT_CONTROL);
|
||||
|
||||
WSF_AUTOCOMPLETE_CONTROL = (function(_super) {
|
||||
|
||||
__extends(WSF_AUTOCOMPLETE_CONTROL, _super);
|
||||
|
||||
function WSF_AUTOCOMPLETE_CONTROL() {
|
||||
return WSF_AUTOCOMPLETE_CONTROL.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
WSF_AUTOCOMPLETE_CONTROL.prototype.attach_events = function() {
|
||||
var self;
|
||||
WSF_AUTOCOMPLETE_CONTROL.__super__.attach_events.apply(this, arguments);
|
||||
self = this;
|
||||
return this.$el.change(function() {
|
||||
return self.change();
|
||||
return this.$el.typeahead({
|
||||
name: this.control_name,
|
||||
template: window.states[this.control_name]['template'],
|
||||
engine: Mini,
|
||||
remote: {
|
||||
url: "",
|
||||
replace: function(url, uriEncodedQuery) {
|
||||
window.states[self.control_name]['text'] = self.$el.val();
|
||||
return '?' + $.param({
|
||||
control_name: self.control_name,
|
||||
event: 'autocomplete',
|
||||
states: JSON.stringify(window.states)
|
||||
});
|
||||
},
|
||||
filter: function(parsedResponse) {
|
||||
return parsedResponse[self.control_name]['suggestions'];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
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');
|
||||
};
|
||||
return WSF_AUTOCOMPLETE_CONTROL;
|
||||
|
||||
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) {
|
||||
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_INPUT_CONTROL);
|
||||
|
||||
WSF_CHECKBOX_CONTROL = (function(_super) {
|
||||
|
||||
@@ -476,6 +467,7 @@
|
||||
"WSF_BUTTON_CONTROL": WSF_BUTTON_CONTROL,
|
||||
"WSF_INPUT_CONTROL": WSF_INPUT_CONTROL,
|
||||
"WSF_TEXTAREA_CONTROL": WSF_TEXTAREA_CONTROL,
|
||||
"WSF_AUTOCOMPLETE_CONTROL": WSF_AUTOCOMPLETE_CONTROL,
|
||||
"WSF_CHECKBOX_CONTROL": WSF_CHECKBOX_CONTROL,
|
||||
"WSF_FORM_ELEMENT_CONTROL": WSF_FORM_ELEMENT_CONTROL,
|
||||
"WSF_HTML_CONTROL": WSF_HTML_CONTROL,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
|
||||
</option>
|
||||
<library name="default_nino" location="..\..\library\server\wsf\default\nino-safe.ecf"/>
|
||||
<library name="json" location="..\..\contrib\library\text\parser\json\library\json-safe.ecf"/>
|
||||
<cluster name="widgetapp" location=".\" recursive="true"/>
|
||||
</target>
|
||||
<target name="widgetapp_cgi" extends="common">
|
||||
|
||||
@@ -13,4 +13,6 @@ feature
|
||||
deferred
|
||||
end
|
||||
|
||||
template: detachable STRING
|
||||
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ create
|
||||
|
||||
feature {NONE}
|
||||
|
||||
make (l: LIST [STRING])
|
||||
make (l: ITERABLE [STRING])
|
||||
do
|
||||
list := l
|
||||
end
|
||||
@@ -41,6 +41,6 @@ feature -- Implementation
|
||||
|
||||
feature
|
||||
|
||||
list: LIST [STRING]
|
||||
list: ITERABLE [STRING]
|
||||
|
||||
end
|
||||
|
||||
@@ -11,7 +11,8 @@ inherit
|
||||
|
||||
WSF_INPUT_CONTROL
|
||||
redefine
|
||||
handle_callback
|
||||
handle_callback,
|
||||
state
|
||||
end
|
||||
|
||||
create
|
||||
@@ -22,12 +23,24 @@ feature {NONE} -- Creation
|
||||
make_autocomplete (n: STRING; c: WSF_AUTOCOMPLETION)
|
||||
do
|
||||
make_autocomplete_with_agent (n, agent c.autocompletion)
|
||||
if attached c.template as t then
|
||||
template := t
|
||||
end
|
||||
end
|
||||
|
||||
make_autocomplete_with_agent (n: STRING; c: FUNCTION [ANY, TUPLE [STRING], JSON_ARRAY])
|
||||
do
|
||||
make_input (n, "")
|
||||
create_json_list := c
|
||||
template := "{{=value}}"
|
||||
end
|
||||
|
||||
feature -- State
|
||||
|
||||
state: JSON_OBJECT
|
||||
do
|
||||
Result := Precursor {WSF_INPUT_CONTROL}
|
||||
Result.put (create {JSON_STRING}.make_json (template), create {JSON_STRING}.make_json ("template"))
|
||||
end
|
||||
|
||||
feature -- Callback
|
||||
@@ -44,4 +57,6 @@ feature -- Autocomplete
|
||||
|
||||
create_json_list: FUNCTION [ANY, TUPLE [STRING], JSON_ARRAY]
|
||||
|
||||
template: STRING
|
||||
|
||||
end
|
||||
|
||||
@@ -77,7 +77,8 @@ feature
|
||||
create states.make
|
||||
control.read_state (states)
|
||||
data := "<html><head>"
|
||||
data.append ("<link href=%"//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css%" rel=%"stylesheet%">")
|
||||
data.append ("<link href=%"/bootstrap.min.css%" rel=%"stylesheet%">")
|
||||
data.append ("<link href=%"/widget.css%" rel=%"stylesheet%">")
|
||||
data.append ("</head><body>")
|
||||
data.append (control.render)
|
||||
data.append ("<script type=%"text/javascript%">window.states=")
|
||||
|
||||
Reference in New Issue
Block a user