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,54 +1530,157 @@ 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 || {})
.attr({ .addClass("OxInput Ox" + Ox.toTitleCase(self.options.size)),
placeholder: self.options.placeholder 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"
}) })
.addClass( .click(select)
"OxInput Ox" + Ox.toTitleCase(self.options.size) + .appendTo(that);
" OxPlaceholder" self.placeholderId = self.options.id + "_placeholder";
) self.placeholderMenu = new Ox.Menu({
.focus(focus)
.blur(blur)
.change(change);
if (options.autocomplete) {
self.element = that.$element[0];
self.menuId = self.options.id + "_menu"; // fixme: we do this in other places ... are we doing it the same way? var name?
self.menu = new Ox.Menu({
element: that, element: that,
id: self.menuId, 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({
placeholder: self.placeholder,
type: self.options.type == "textarea" ? null : self.options.type
})
.addClass(
"OxInput Ox" + Ox.toTitleCase(self.options.size) +
" OxPlaceholder"
)
.focus(focus)
.blur(blur)
.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) {
self.autocompleteId = 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({
element: that,
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);
} }
if (options.type != "textarea") {
that.attr({ that.bindEvent({
type: self.options.type 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);
}
});
}
callback(items);
} }
function autocomplete(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,40 +332,74 @@
} }
] ]
}).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",
"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Boston",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida", "Chicago",
"Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Cleveland",
"Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Dallas",
"Maryland", "Massachusetts", "Michigan", "Minnessota", "Mississippi", "Denver",
"Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "Detroit",
"New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "El Paso",
"Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island", "Honululu",
"South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Houston",
"Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin", "Kansas City",
"Wyoming" "Las Vegas",
]; "Los Angeles",
if (value === "") { "Memphis",
items = states; "Miami",
} else { "Minneapolis",
$.each(states, function(i, state) { "Nashville",
if (state.toLowerCase().indexOf(value) > -1) { "New Orleans",
items.push(state.replace( "New York",
new RegExp("(" + value + ")", "ig"), "Oklahoma City",
"<span class=\"OxHighlight\">$1</span>") "Philadelphia",
); "Phoenix",
} "Pittsburgh",
}); "Portland",
} "San Antonio",
callback(items); "San Diego",
"San Francisco",
"St. Louis",
"St. Paul",
"Seattle",
"Washington"
],
State: [
"Alabama", "Alaska", "Arizona", "Arkansas", "California",
"Colorado", "Connecticut", "Delaware", "District of Columbia", "Florida",
"Georgia", "Hawaii", "Idaho", "Illinois", "Indiana",
"Iowa", "Kansas", "Kentucky", "Louisiana", "Maine",
"Maryland", "Massachusetts", "Michigan", "Minnessota", "Mississippi",
"Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire",
"New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota",
"Ohio", "Oklahoma", "Oregon", "Pennsylvania", "Rhode Island",
"South Carolina", "South Dakota", "Tennessee", "Texas", "Utah",
"Vermont", "Virginia", "Washington", "West Virginia", "Wisconsin",
"Wyoming"
]
}, },
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.