autocomplete, continued

This commit is contained in:
Rolux 2010-02-19 15:54:02 +05:30
parent 07ec8f30f7
commit c533678f44
7 changed files with 308 additions and 82 deletions

View file

@ -58,6 +58,7 @@ Forms
color: rgb(64, 64, 64); color: rgb(64, 64, 64);
} }
.OxThemeClassic .OxButton, .OxThemeClassic .OxButton,
.OxThemeClassic div.OxInput,
.OxThemeClassic .OxRange { .OxThemeClassic .OxRange {
//background: -moz-linear-gradient(left top, left bottom, from(rgb(192, 192, 192)), to(rgb(160, 160, 160))); //background: -moz-linear-gradient(left top, left bottom, from(rgb(192, 192, 192)), to(rgb(160, 160, 160)));
//background: -webkit-gradient(linear, left top, left bottom, from(rgb(192, 192, 192)), to(rgb(160, 160, 160))); //background: -webkit-gradient(linear, left top, left bottom, from(rgb(192, 192, 192)), to(rgb(160, 160, 160)));
@ -89,17 +90,17 @@ Forms
border-bottom: 1px solid rgb(192, 192, 192); border-bottom: 1px solid rgb(192, 192, 192);
} }
.OxThemeClassic .OxInput, .OxThemeClassic input.OxInput,
.OxThemeClassic .OxTrack { .OxThemeClassic .OxTrack {
background: -moz-linear-gradient(top, rgb(224, 224, 224), rgb(255, 255, 255)); background: -moz-linear-gradient(top, rgb(224, 224, 224), rgb(255, 255, 255));
background: -webkit-gradient(linear, left top, left bottom, from(rgb(224, 224, 224)), to(rgb(255, 255, 255))); background: -webkit-gradient(linear, left top, left bottom, from(rgb(224, 224, 224)), to(rgb(255, 255, 255)));
} }
.OxThemeClassic .OxInput:focus { .OxThemeClassic input.OxInput:focus {
border: 1px solid rgb(160, 160, 160); border: 1px solid rgb(160, 160, 160);
-moz-box-shadow: 0 0 2px rgb(128, 128, 128); -moz-box-shadow: 0 0 2px rgb(128, 128, 128);
-webkit-box-shadow: 0 2 4px rgb(128, 128, 128); -webkit-box-shadow: 0 0 2px rgb(128, 128, 128);
} }
.OxThemeClassic .OxInput.OxPlaceholder { .OxThemeClassic input.OxInput.OxPlaceholder {
color: rgb(160, 160, 160) color: rgb(160, 160, 160)
} }

View file

@ -274,6 +274,32 @@ OxButtonGroup
} }
/* /*
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
OxInput
--------------------------------------------------------------------------------
*/
div.OxInput {
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
}
div.OxInput.OxMedium {
height: 14px;
}
div.OxInput > .OxButton:first-child {
float: left;
margin-top: -1px;
}
div.OxInput > .OxButton:last-child {
float: left;
margin-left: -1px;
margin-top: -1px;
}
input.OxInput {
float: left;
margin-left: -1px;
margin-top: -1px;
}
/*
--------------------------------------------------------------------------------
OxRange OxRange
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */
@ -319,7 +345,7 @@ OxSelect
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
*/ */
.OxSelect.OxMedium { .OxSelect.OxMedium {
padding: 0 8px 0 8px;
} }
.OxSelect > .OxButton { .OxSelect > .OxButton {
text-align: left; text-align: left;
@ -331,7 +357,7 @@ OxSelect
-webkit-user-select: none; -webkit-user-select: none;
} }
.OxSelect.OxMedium > .OxSymbol { .OxSelect.OxMedium > .OxSymbol {
margin: -16px 8px 0 8px; margin: -16px 0 0 8px;
} }
/* /*

View file

@ -1530,20 +1530,83 @@ requires
*/ */
Ox.Input = function(options, self) { Ox.Input = function(options, self) {
/* options:
* autocomplete function, or array of values, or dict with array of values per label or placeholder
* clear boolean, clear button, or not
* highlight boolean, highlight value in autocomplete menu, or not
* id
* label string or array (select) -- label and placeholder are mutually exclusive
* labelWidth integer (px)
* placeholder string or array (select) -- label and placeholder are mutually exclusive
* selected integer, selected label or placeholder
* size "large", "medium" or "small"
* type "text", "password", "textarea", etc.
*/
var self = self || {}, var self = self || {},
that = new Ox.Element( that = new Ox.Element("div", self)
options.type == "textarea" ? "textarea" : "input", self
)
.defaults({ .defaults({
autocomplete: null, autocomplete: null,
clear: false,
highlight: false,
id: "", id: "",
placeholder: "", // can be [], will result in select label: "",
labelWidth: 0,
placeholder: "",
selected: 0,
size: "medium", size: "medium",
type: "text" type: "text"
}) })
.options(options || {}) .options(options || {})
.addClass("OxInput Ox" + Ox.toTitleCase(self.options.size)),
autocomplete;
if (self.options.label) {
self.options.label = Ox.makeArray(self.options.label);
self.label = self.options.label[0];
} else if (self.options.placeholder) {
self.options.placeholder = Ox.makeArray(self.options.placeholder);
self.placeholder = self.options.placeholder[0];
}
if (Ox.isArray(self.options.autocomplete)) {
autocomplete = self.options.autocomplete;
self.options.autocomplete = {};
self.options.autocomplete[self.placeholder] = autocomplete;
}
if (self.options.label) {
that.$label = "foo";
} else if (self.options.placeholder.length > 1) {
that.$select = new Ox.Button({
style: "symbol",
type: "image",
value: "select"
})
.click(select)
.appendTo(that);
self.placeholderId = self.options.id + "_placeholder";
self.placeholderMenu = new Ox.Menu({
element: that,
id: self.placeholderId,
items: $.map(self.options.placeholder, function(title, position) {
return {
checked: position == self.options.selected,
id: title.toLowerCase(),
group: self.placeholderId, // fixme: same id, works here, but should be different
title: title
};
})
});
that.bindEvent("change_" + self.placeholderId, changePlaceholder);
}
that.$input = new Ox.Element(
self.options.type == "textarea" ? "textarea" : "input", self
)
.attr({ .attr({
placeholder: self.options.placeholder placeholder: self.placeholder,
type: self.options.type == "textarea" ? null : self.options.type
}) })
.addClass( .addClass(
"OxInput Ox" + Ox.toTitleCase(self.options.size) + "OxInput Ox" + Ox.toTitleCase(self.options.size) +
@ -1551,33 +1614,73 @@ requires
) )
.focus(focus) .focus(focus)
.blur(blur) .blur(blur)
.change(change); .change(change)
.appendTo(that);
if (self.options.clear) {
that.$clear = new Ox.Button({
style: "symbol",
type: "image",
value: "clear"
})
.click(clear)
.appendTo(that);
}
if (options.autocomplete) { if (options.autocomplete) {
self.element = that.$element[0]; self.autocompleteId = self.options.id + "_menu"; // fixme: we do this in other places ... are we doing it the same way? var name?
self.menuId = self.options.id + "_menu"; // fixme: we do this in other places ... are we doing it the same way? var name? self.autocompleteMenu = new Ox.Menu({
self.menu = new Ox.Menu({
element: that, element: that,
id: self.menuId, id: self.autocompleteId,
offset: { offset: {
left: 4, left: 4,
top: 0 top: 0
}, },
size: self.options.size size: self.options.size
}); });
that.bindEvent("click_" + self.menuId, onClick); that.bindEvent("click_" + self.autocompleteId, onClick);
//that.bindEvent("deselect_" + self.menuId, onDeselect); }
//that.bindEvent("select_" + self.menuId, onSelect);
that.bindEvent({
key_enter: submit,
key_escape: cancel
});
function autocomplete(value, callback) {
value = value.toLowerCase();
var items = [];
if (value === "") {
items = self.options.autocomplete[self.placeholder];
} else {
$.each(self.options.autocomplete[self.placeholder], function(i, item) {
if (item.toLowerCase().indexOf(value) > -1) {
if (self.options.highlight) {
item = item.replace(
new RegExp("(" + value + ")", "ig"),
"<span class=\"OxHighlight\">$1</span>"
);
}
items.push(item);
} }
if (options.type != "textarea") {
that.attr({
type: self.options.type
}); });
} }
function autocomplete(items) { callback(items);
}
function call() {
var value = that.$input.val();
if (self.options.autocomplete) {
Ox.isFunction(self.options.autocomplete) ?
self.options.autocomplete(value, callback) :
autocomplete(value, callback);
}
}
function callback(items) {
var selected = 0; var selected = 0;
if (items.length) { if (items.length) {
items = $.map(items, function(title, position) { items = $.map(items, function(title, position) {
if (that.val().toLowerCase() == Ox.stripTags(title.toLowerCase())) { if (that.$input.val().toLowerCase() == Ox.stripTags(title.toLowerCase())) {
selected = position; selected = position;
} }
return { return {
@ -1585,54 +1688,88 @@ requires
title: title title: title
}; };
}); });
self.menu.options({ self.placeholderMenu.hideMenu();
self.autocompleteMenu.options({
items: items, items: items,
selected: selected selected: selected
}).showMenu(); }).showMenu();
} else { } else {
self.menu.hideMenu(); self.autocompleteMenu.hideMenu();
} }
} }
function cancel() {
that.$input.trigger("blur");
}
function clear() {
that.$input.val("");
}
function change() { function change() {
} }
function changePlaceholder(event, data) {
Ox.print("cP", event, data);
self.placeholder = data.value; // fixme: could be "title" as well
if (that.$input.is(".OxPlaceholder")) {
that.$input.val(self.placeholder);
}
call();
}
function blur() { function blur() {
if (that.val() === "") { that.loseFocus();
that.addClass("OxPlaceholder").val(that.attr("placeholder")); if (that.$input.val() === "") {
that.$input.addClass("OxPlaceholder").val(that.$input.attr("placeholder"));
} }
if (self.options.autocomplete) { if (self.options.autocomplete) {
$document.unbind("keydown", keypress); $document.unbind("keydown", keypress);
$document.unbind("keypress", keypress); $document.unbind("keypress", keypress);
} }
} }
function focus() { function focus() {
if (that.is(".OxPlaceholder")) { that.gainFocus();
that.val("").removeClass("OxPlaceholder"); if (that.$input.is(".OxPlaceholder")) {
that.$input.val("").removeClass("OxPlaceholder");
} }
if (self.options.autocomplete) { if (self.options.autocomplete) {
// fixme: different in webkit and firefox (?), see keyboard handler, need generic function // fixme: different in webkit and firefox (?), see keyboard handler, need generic function
$document.bind("keydown", keypress); $document.bind("keydown", keypress);
$document.bind("keypress", keypress); $document.bind("keypress", keypress);
self.options.autocomplete(that.val(), autocomplete); Ox.isFunction(self.options.autocomplete) ?
self.options.autocomplete(that.$input.val(), callback) :
autocomplete(that.$input.val(), callback);
} }
} }
function keypress(event) { function keypress(event) {
if (event.keyCode != 13) { if (event.keyCode != 13) {
setTimeout(function() { setTimeout(function() {
var value = that.val(); var value = that.$input.val();
if (self.options.autocomplete && value != self.value) { if (value != self.value) {
self.value = value; self.value = value;
self.options.autocomplete(value, autocomplete); call();
} }
}, 25); }, 25);
} }
} }
function onClick(event, data) { function onClick(event, data) {
Ox.print("onClick", data) Ox.print("onClick", data)
that.focus().val(Ox.stripTags(data.title)); that.$input.focus().val(Ox.stripTags(data.title));
self.menu.hideMenu(); self.autocompleteMenu.hideMenu();
submit();
} }
function select() {
self.placeholderMenu.showMenu();
}
function selection() { function selection() {
// fixme: not used!
var start, end; var start, end;
if (arguments.length == 0) { if (arguments.length == 0) {
return [self.element.selectionStart, self.element.selectionEnd]; return [self.element.selectionStart, self.element.selectionEnd];
@ -1642,7 +1779,22 @@ requires
self.element.setSelectionRange(start, end); self.element.setSelectionRange(start, end);
} }
} }
function submit() {
that.$input.trigger("blur");
that.triggerEvent("submit", that.$input.val());
}
that.width = function(value) {
that.$element.width(value);
that.$input.width(value - 2 - self.options.labelWidth -
(self.options.placeholder.length > 1) * 21 -
self.options.clear * 21);
return that; return that;
}
return that;
}; };
/* /*
@ -1874,7 +2026,7 @@ requires
Ox.Select = function(options, self) { Ox.Select = function(options, self) {
var self = self || {}, var self = self || {},
that = new Ox.Element("div", self) that = new Ox.Element("div", self) // fixme: do we use "div", or {}, or "", by default?
.defaults({ .defaults({
id: "", id: "",
items: [], items: [],
@ -1945,7 +2097,7 @@ requires
that.width = function(val) { that.width = function(val) {
// fixme: silly hack, and won't work for css() // fixme: silly hack, and won't work for css()
that.$element.width(val); that.$element.width(val + 16);
that.$button.width(val); that.$button.width(val);
that.$symbol.width(val); that.$symbol.width(val);
return that; return that;
@ -1982,14 +2134,21 @@ requires
Ox.MainMenu = function(options, self) { Ox.MainMenu = function(options, self) {
/* options:
* extras
* menus
* size
*/
var self = self || {}, var self = self || {},
that = new Ox.Bar({}, self) that = new Ox.Bar({}, self)
.defaults({ .defaults({
extras: [],
menus: [], menus: [],
size: "medium" size: "medium"
}) })
.options(options || {}) .options(options || {})
.addClass("OxMainMenu Ox" + Ox.toTitleCase(self.options.size)) // fixme: bar should accept small/medium/large .addClass("OxMainMenu Ox" + Ox.toTitleCase(self.options.size)) // fixme: bar should accept small/medium/large ... like toolbar
.click(click) .click(click)
.mousemove(mousemove); .mousemove(mousemove);
@ -2067,11 +2226,11 @@ requires
}; };
that.addMenuAfter = function() { that.addMenuAfter = function(id) {
}; };
that.addMenuBefore = function() { that.addMenuBefore = function(id) {
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -290,6 +290,12 @@
type: "text", type: "text",
value: "Foo" value: "Foo"
}).addClass("margin").appendTo(mainPanel); }).addClass("margin").appendTo(mainPanel);
Ox.Button({
selectable: true,
size: size,
type: "text",
value: "Bar"
}).addClass("margin").appendTo(mainPanel);
Ox.Select({ Ox.Select({
id: "select1", id: "select1",
items: [ items: [
@ -326,12 +332,56 @@
} }
] ]
}).addClass("margin").width(96).appendTo(mainPanel); }).addClass("margin").width(96).appendTo(mainPanel);
Ox.Button({
selectable: true,
size: size,
type: "text",
value: "Foo"
}).addClass("margin").appendTo(mainPanel);
Ox.Button({
selectable: true,
size: size,
type: "text",
value: "Bar"
}).addClass("margin").appendTo(mainPanel);
Ox.Input({ Ox.Input({
id: "state", autocomplete: {
autocomplete: function(value, callback) { City: [
value = value.toLowerCase(); "Albuquerque",
var items = [], "Austin",
states = [ "Baltimore",
"Boston",
"Chicago",
"Cleveland",
"Dallas",
"Denver",
"Detroit",
"El Paso",
"Honululu",
"Houston",
"Kansas City",
"Las Vegas",
"Los Angeles",
"Memphis",
"Miami",
"Minneapolis",
"Nashville",
"New Orleans",
"New York",
"Oklahoma City",
"Philadelphia",
"Phoenix",
"Pittsburgh",
"Portland",
"San Antonio",
"San Diego",
"San Francisco",
"St. Louis",
"St. Paul",
"Seattle",
"Washington"
],
State: [
"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida", "Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida",
"Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana",
@ -343,23 +393,13 @@
"South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah",
"Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin",
"Wyoming" "Wyoming"
]; ]
if (value === "") {
items = states;
} else {
$.each(states, function(i, state) {
if (state.toLowerCase().indexOf(value) > -1) {
items.push(state.replace(
new RegExp("(" + value + ")", "ig"),
"<span class=\"OxHighlight\">$1</span>")
);
}
});
}
callback(items);
}, },
placeholder: "State" clear: true,
}).addClass("margin").width(96).appendTo(mainPanel); highlight: true,
id: "citystate",
placeholder: ["City", "State"]
}).addClass("margin").width(128).appendTo(mainPanel);
//*/ //*/
function switchTheme() { function switchTheme() {
if (Ox.theme() == "classic") { if (Ox.theme() == "classic") {

Binary file not shown.