forked from 0x2620/oxjs
rename Ox.UI source files, remove Ox. prefix
This commit is contained in:
parent
005d50c389
commit
91e1065aab
101 changed files with 0 additions and 0 deletions
951
source/Ox.UI/js/Form/Input.js
Normal file
951
source/Ox.UI/js/Form/Input.js
Normal file
|
|
@ -0,0 +1,951 @@
|
|||
'use strict';
|
||||
|
||||
/*@
|
||||
Ox.Input <f:Ox.Element> Input Element
|
||||
([options[, self]]) -> <o> Input Element
|
||||
options <o> Options object
|
||||
arrows <b> if true, and type is 'float' or 'int', display arrows
|
||||
arrowStep <n> step when clicking arrows
|
||||
autocomplete <a> array of possible values, or
|
||||
<f> function(key, value, callback), returns one or more values
|
||||
autocompleteReplace <b> if true, value is replaced
|
||||
autocompleteReplaceCorrect <b> if true, only valid values can be entered
|
||||
autocompleteSelect <b> if true, menu is displayed
|
||||
autocompleteSelectHighlight <b> if true, value in menu is highlighted
|
||||
autocompleteSelectMaxWidth <n|0> Maximum width of autocomplete menu, or 0
|
||||
autocompleteSelectSubmit <b> if true, submit input on menu selection
|
||||
autocorrect <s|r|f|null> ('email', 'float', 'int', 'phone', 'url'), or
|
||||
<r> regexp(value), or
|
||||
<f> function(key, value, blur, callback), returns value
|
||||
autovalidate <f> --remote validation--
|
||||
clear <b> if true, has clear button
|
||||
changeOnKeypress <b> if true, fire change event while typing
|
||||
disabled <b> if true, is disabled
|
||||
height <n> px (for type='textarea' and type='range' with orientation='horizontal')
|
||||
id <s> element id
|
||||
key <s> to be passed to autocomplete and autovalidate functions
|
||||
label <s|''> Label
|
||||
labelWidth <n|64> Label width
|
||||
max <n> max value if type is 'int' or 'float'
|
||||
min <n> min value if type is 'int' or 'float'
|
||||
name <s> will be displayed by autovalidate function ('invalid ' + name)
|
||||
overlap <s> '', 'left' or 'right', will cause padding and negative margin
|
||||
picker <o> picker object
|
||||
rangeOptions <o> range options
|
||||
arrows <b>boolean, if true, display arrows
|
||||
//arrowStep <n> number, step when clicking arrows
|
||||
//arrowSymbols <a> array of two strings
|
||||
max <n> number, maximum value
|
||||
min <n> number, minimum value
|
||||
orientation <s> 'horizontal' or 'vertical'
|
||||
step <n> number, step
|
||||
thumbValue <b> boolean, if true, value is displayed on thumb, or
|
||||
<a> array of strings per value, or
|
||||
<f> function(value), returns string
|
||||
thumbSize <n> integer, px
|
||||
trackGradient <s> string, css gradient for track
|
||||
trackImage <s> string, image url, or
|
||||
<a> array of image urls
|
||||
//trackStep <n> number, 0 for 'scroll here', positive for step
|
||||
trackValues <b> boolean
|
||||
serialize <f> function used to serialize value in submit
|
||||
style <s> 'rounded' or 'square'
|
||||
textAlign <s> 'left', 'center' or 'right'
|
||||
type <s> 'float', 'int', 'password', 'text', 'textarea'
|
||||
value <s> string
|
||||
validate <f> remote validation
|
||||
width <n> px
|
||||
|
||||
change <!> input changed event
|
||||
submit <!> input submit event
|
||||
@*/
|
||||
|
||||
Ox.Input = function(options, self) {
|
||||
|
||||
self = self || {};
|
||||
var that = Ox.Element({
|
||||
element: options.element || '<div>'
|
||||
}, self)
|
||||
.defaults({
|
||||
arrows: false,
|
||||
arrowStep: 1,
|
||||
autocomplete: null,
|
||||
autocompleteReplace: false,
|
||||
autocompleteReplaceCorrect: false,
|
||||
autocompleteSelect: false,
|
||||
autocompleteSelectHighlight: false,
|
||||
autocompleteSelectMax: 0,
|
||||
autocompleteSelectMaxWidth: 0,
|
||||
autocompleteSelectSubmit: false,
|
||||
autovalidate: null,
|
||||
changeOnKeypress: false,
|
||||
clear: false,
|
||||
decimals: 0,
|
||||
disabled: false,
|
||||
height: 16,
|
||||
key: '',
|
||||
min: -Infinity,
|
||||
max: Infinity,
|
||||
label: '',
|
||||
labelWidth: 64,
|
||||
overlap: 'none',
|
||||
placeholder: '',
|
||||
serialize: null,
|
||||
style: 'rounded',
|
||||
textAlign: 'left',
|
||||
type: 'text',
|
||||
validate: null,
|
||||
value: '',
|
||||
width: 128
|
||||
})
|
||||
.options(options || {})
|
||||
.update(function(key, value) {
|
||||
var inputWidth;
|
||||
if ([
|
||||
'autocomplete', 'autocompleteReplace', 'autocompleteSelect', 'autovalidate'
|
||||
].indexOf(key) > -1) {
|
||||
if (self.options.autocomplete && self.options.autocompleteSelect) {
|
||||
self.$autocompleteMenu = constructAutocompleteMenu();
|
||||
}
|
||||
self.bindKeyboard = self.options.autocomplete || self.options.autovalidate;
|
||||
} else if (key == 'disabled') {
|
||||
self.$input.attr({disabled: value});
|
||||
} else if (key == 'height') {
|
||||
that.css({height: value + 'px'});
|
||||
self.$input.css({height: value - 6 + 'px'});
|
||||
} else if (key == 'labelWidth') {
|
||||
self.$label.options({width: value});
|
||||
inputWidth = getInputWidth();
|
||||
self.$input.css({
|
||||
width: inputWidth + 'px'
|
||||
});
|
||||
self.hasPasswordPlaceholder && self.$placeholder.css({
|
||||
width: inputWidth + 'px'
|
||||
});
|
||||
} else if (key == 'placeholder') {
|
||||
setPlaceholder();
|
||||
} else if (key == 'value') {
|
||||
if (self.options.type == 'float' && self.options.decimals) {
|
||||
self.options.value = self.options.value.toFixed(self.options.decimals);
|
||||
}
|
||||
self.$input.val(self.options.value);
|
||||
that.is('.OxError') && that.removeClass('OxError');
|
||||
setPlaceholder();
|
||||
} else if (key == 'width') {
|
||||
that.css({width: self.options.width + 'px'});
|
||||
inputWidth = getInputWidth();
|
||||
self.$input.css({
|
||||
width: inputWidth + 'px'
|
||||
});
|
||||
self.hasPasswordPlaceholder && self.$placeholder.css({
|
||||
width: inputWidth + 'px'
|
||||
});
|
||||
}
|
||||
})
|
||||
.addClass(
|
||||
'OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style) /*+ (
|
||||
self.options.overlap != 'none' ?
|
||||
' OxOverlap' + Ox.toTitleCase(self.options.overlap) : ''
|
||||
)*/
|
||||
)
|
||||
.css(
|
||||
Ox.extend({
|
||||
width: self.options.width + 'px'
|
||||
}, self.options.type == 'textarea' ? {
|
||||
height: self.options.height + 'px'
|
||||
} : {})
|
||||
)
|
||||
.bindEvent(Ox.extend(self.options.type != 'textarea' ? {
|
||||
key_enter: submit
|
||||
} : {}, {
|
||||
key_control_i: insert,
|
||||
key_escape: cancel,
|
||||
key_shift_enter: submit
|
||||
}));
|
||||
|
||||
if (
|
||||
Ox.isArray(self.options.autocomplete)
|
||||
&& self.options.autocompleteReplace
|
||||
&& self.options.autocompleteReplaceCorrect
|
||||
&& self.options.value === ''
|
||||
) {
|
||||
self.options.value = self.options.autocomplete[0]
|
||||
}
|
||||
|
||||
// fixme: set to min, not 0
|
||||
// fixme: validate self.options.value !
|
||||
if (self.options.type == 'float') {
|
||||
self.decimals = Ox.repeat('0', self.options.decimals || 1)
|
||||
Ox.extend(self.options, {
|
||||
autovalidate: 'float',
|
||||
textAlign: 'right',
|
||||
value: self.options.value || '0.' + self.decimals
|
||||
});
|
||||
} else if (self.options.type == 'int') {
|
||||
Ox.extend(self.options, {
|
||||
autovalidate: 'int',
|
||||
textAlign: 'right',
|
||||
value: self.options.value || '0'
|
||||
});
|
||||
}
|
||||
|
||||
if (self.options.label) {
|
||||
self.$label = Ox.Label({
|
||||
overlap: 'right',
|
||||
textAlign: 'right',
|
||||
title: self.options.label,
|
||||
width: self.options.labelWidth
|
||||
})
|
||||
.css({
|
||||
float: 'left' // fixme: use css rule
|
||||
})
|
||||
.click(function() {
|
||||
// fixme: ???
|
||||
// that.focus();
|
||||
})
|
||||
.appendTo(that);
|
||||
}
|
||||
|
||||
if (self.options.arrows) {
|
||||
self.arrows = [];
|
||||
self.arrows[0] = [
|
||||
Ox.Button({
|
||||
overlap: 'right',
|
||||
title: 'left',
|
||||
type: 'image'
|
||||
})
|
||||
.css({
|
||||
float: 'left'
|
||||
})
|
||||
.click(function() {
|
||||
clickArrow(0);
|
||||
})
|
||||
.appendTo(that),
|
||||
Ox.Button({
|
||||
overlap: 'left',
|
||||
title: 'right',
|
||||
type: 'image'
|
||||
})
|
||||
.css({
|
||||
float: 'right'
|
||||
})
|
||||
.click(function() {
|
||||
clickArrow(1);
|
||||
})
|
||||
.appendTo(that)
|
||||
]
|
||||
}
|
||||
|
||||
self.bindKeyboard = self.options.autocomplete
|
||||
|| self.options.autovalidate
|
||||
|| self.options.changeOnKeypress;
|
||||
self.hasPasswordPlaceholder = self.options.type == 'password'
|
||||
&& self.options.placeholder;
|
||||
self.inputWidth = getInputWidth();
|
||||
|
||||
if (self.options.clear) {
|
||||
self.$button = Ox.Button({
|
||||
overlap: 'left',
|
||||
title: 'close',
|
||||
type: 'image'
|
||||
})
|
||||
.css({
|
||||
float: 'right' // fixme: use css rule
|
||||
})
|
||||
.click(clear)
|
||||
.appendTo(that);
|
||||
}
|
||||
|
||||
self.$input = $(self.options.type == 'textarea' ? '<textarea>' : '<input>')
|
||||
.addClass('OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style))
|
||||
.attr({
|
||||
disabled: self.options.disabled,
|
||||
type: self.options.type == 'password' ? 'password' : 'text'
|
||||
})
|
||||
.css(
|
||||
Ox.extend({
|
||||
width: self.inputWidth + 'px',
|
||||
textAlign: self.options.textAlign
|
||||
}, self.options.type == 'textarea' ? {
|
||||
height: self.options.height - 6 + 'px'
|
||||
} : {})
|
||||
)
|
||||
.val(self.options.value)
|
||||
.blur(blur)
|
||||
.change(change)
|
||||
.focus(focus)
|
||||
.appendTo(that.$element);
|
||||
|
||||
if (self.options.type == 'textarea') {
|
||||
Ox.Log('Form', 'TEXTAREA', self.options.width, self.options.height, '...', that.css('width'), that.css('height'), '...', self.$input.css('width'), self.$input.css('height'), '...', self.$input.css('border'))
|
||||
}
|
||||
|
||||
// fixme: is there a better way than this one?
|
||||
// should at least go into ox.ui.theme.foo.js
|
||||
// probably better: divs in the background
|
||||
/*
|
||||
if (self.options.type == 'textarea') {
|
||||
Ox.extend(self, {
|
||||
colors: Ox.Theme() == 'classic' ?
|
||||
[208, 232, 244] :
|
||||
//[0, 16, 32],
|
||||
[32, 48, 64],
|
||||
colorstops: [8 / self.options.height, self.options.height - 8 / self.options.height]
|
||||
});
|
||||
self.$input.css({
|
||||
background: '-moz-linear-gradient(top, rgb(' +
|
||||
[self.colors[0], self.colors[0], self.colors[0]].join(', ') + '), rgb(' +
|
||||
[self.colors[1], self.colors[1], self.colors[1]].join(', ') + ') ' +
|
||||
Math.round(self.colorstops[0] * 100) + '%, rgb(' +
|
||||
[self.colors[1], self.colors[1], self.colors[1]].join(', ') + ') ' +
|
||||
Math.round(self.colorstops[1] * 100) + '%, rgb(' +
|
||||
[self.colors[2], self.colors[2], self.colors[2]].join(', ') + '))'
|
||||
});
|
||||
self.$input.css({
|
||||
background: '-webkit-linear-gradient(top, rgb(' +
|
||||
[self.colors[0], self.colors[0], self.colors[0]].join(', ') + '), rgb(' +
|
||||
[self.colors[1], self.colors[1], self.colors[1]].join(', ') + ') ' +
|
||||
Math.round(self.colorstops[0] * 100) + '%, rgb(' +
|
||||
[self.colors[1], self.colors[1], self.colors[1]].join(', ') + ') ' +
|
||||
Math.round(self.colorstops[1] * 100) + '%, rgb(' +
|
||||
[self.colors[2], self.colors[2], self.colors[2]].join(', ') + '))'
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
if (self.hasPasswordPlaceholder) {
|
||||
self.$input.hide();
|
||||
self.$placeholder = $('<input>')
|
||||
.addClass('OxInput OxMedium Ox' +
|
||||
Ox.toTitleCase(self.options.style) +
|
||||
' OxPlaceholder')
|
||||
.attr({
|
||||
type: 'text'
|
||||
})
|
||||
.css({
|
||||
//float: 'left',
|
||||
width: self.inputWidth + 'px'
|
||||
})
|
||||
.val(self.options.placeholder)
|
||||
.focus(focus)
|
||||
.appendTo(that.$element);
|
||||
}
|
||||
|
||||
if (self.options.autocomplete && self.options.autocompleteSelect) {
|
||||
self.$autocompleteMenu = constructAutocompleteMenu();
|
||||
}
|
||||
|
||||
self.options.placeholder && setPlaceholder();
|
||||
|
||||
function autocomplete(oldValue, oldCursor) {
|
||||
|
||||
oldValue = Ox.isUndefined(oldValue) ? self.options.value : oldValue;
|
||||
oldCursor = Ox.isUndefined(oldCursor) ? cursor() : oldCursor;
|
||||
|
||||
Ox.Log('AUTO', 'autocomplete', oldValue, oldCursor)
|
||||
|
||||
if (self.options.value || self.options.autocompleteReplaceCorrect) {
|
||||
if (Ox.isFunction(self.options.autocomplete)) {
|
||||
if (self.options.key) {
|
||||
self.options.autocomplete(
|
||||
self.options.key, self.options.value, autocompleteCallback
|
||||
);
|
||||
} else {
|
||||
self.options.autocomplete(
|
||||
self.options.value, autocompleteCallback
|
||||
);
|
||||
}
|
||||
} else {
|
||||
autocompleteCallback(autocompleteFunction(self.options.value));
|
||||
}
|
||||
}
|
||||
if (!self.options.value) {
|
||||
if (self.options.autocompleteSelect) {
|
||||
self.$autocompleteMenu
|
||||
.unbindEvent('select')
|
||||
.hideMenu();
|
||||
self.selectEventBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
function autocompleteFunction() {
|
||||
return Ox.find(
|
||||
self.options.autocomplete,
|
||||
self.options.value,
|
||||
self.options.autocompleteReplace
|
||||
);
|
||||
}
|
||||
|
||||
function autocompleteCallback(values) {
|
||||
|
||||
//Ox.Log('Form', 'autocompleteCallback', values[0], self.options.value, self.options.value.length, oldValue, oldCursor)
|
||||
|
||||
var length = self.options.value.length,
|
||||
newValue, newLength,
|
||||
pos = cursor(),
|
||||
selected = -1,
|
||||
selectEnd = length == 0 || (values[0] && values[0].length),
|
||||
value;
|
||||
|
||||
if (values[0]) {
|
||||
if (self.options.autocompleteReplace) {
|
||||
newValue = values[0];
|
||||
} else {
|
||||
newValue = self.options.value;
|
||||
}
|
||||
} else {
|
||||
if (self.options.autocompleteReplaceCorrect) {
|
||||
newValue = oldValue;
|
||||
} else {
|
||||
newValue = self.options.value
|
||||
}
|
||||
}
|
||||
newLength = newValue.length;
|
||||
|
||||
if (self.options.autocompleteReplace) {
|
||||
value = self.options.value;
|
||||
self.options.value = newValue;
|
||||
self.$input.val(self.options.value);
|
||||
if (selectEnd) {
|
||||
cursor(length, newLength);
|
||||
} else if (self.options.autocompleteReplaceCorrect) {
|
||||
cursor(oldCursor);
|
||||
} else {
|
||||
cursor(pos);
|
||||
}
|
||||
selected = 0;
|
||||
}
|
||||
|
||||
if (self.options.autocompleteSelect) {
|
||||
value = (
|
||||
self.options.autocompleteReplace
|
||||
? value : self.options.value
|
||||
).toLowerCase();
|
||||
if (values.length) {
|
||||
self.oldCursor = cursor();
|
||||
self.oldValue = self.options.value;
|
||||
self.$autocompleteMenu.options({
|
||||
items: Ox.filter(values, function(v, i) {
|
||||
var ret = false;
|
||||
if (
|
||||
!self.options.autocompleteSelectMax ||
|
||||
i < self.options.autocompleteSelectMax
|
||||
) {
|
||||
if (v.toLowerCase() === value) {
|
||||
selected = i;
|
||||
}
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}).map(function(v) {
|
||||
return {
|
||||
id: v.toLowerCase().replace(/ /g, '_'), // fixme: need function to do lowercase, underscores etc?
|
||||
title: self.options.autocompleteSelectHighlight ?
|
||||
Ox.highlight(v, value, 'OxHighlight') : v
|
||||
};
|
||||
})
|
||||
});
|
||||
if (!self.selectEventBound) {
|
||||
self.$autocompleteMenu.bindEvent({
|
||||
select: selectMenu
|
||||
});
|
||||
self.selectEventBound = true;
|
||||
}
|
||||
self.$autocompleteMenu.options({
|
||||
selected: selected
|
||||
}).showMenu();
|
||||
} else {
|
||||
self.$autocompleteMenu
|
||||
.unbindEvent('select')
|
||||
.hideMenu();
|
||||
self.selectEventBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
that.triggerEvent('autocomplete', {
|
||||
value: newValue
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function constructAutocompleteMenu() {
|
||||
var menu = Ox.Menu({
|
||||
element: self.$input,
|
||||
id: self.options.id + 'Menu', // fixme: we do this in other places ... are we doing it the same way? var name?,
|
||||
maxWidth: self.options.autocompleteSelectMaxWidth,
|
||||
offset: {
|
||||
left: 4,
|
||||
top: 0
|
||||
}
|
||||
//size: self.options.size
|
||||
})
|
||||
.addClass('OxAutocompleteMenu')
|
||||
.bindEvent({
|
||||
click: clickMenu
|
||||
});
|
||||
return menu;
|
||||
}
|
||||
|
||||
function autovalidate() {
|
||||
|
||||
var blur, oldCursor, oldValue;
|
||||
|
||||
if (arguments.length == 1) {
|
||||
blur = arguments[0];
|
||||
} else {
|
||||
blur = false;
|
||||
oldValue = arguments[0];
|
||||
oldCursor = arguments[1];
|
||||
}
|
||||
|
||||
if (Ox.isFunction(self.options.autovalidate)) {
|
||||
if (self.options.key) {
|
||||
self.options.autovalidate(
|
||||
self.options.key, self.options.value, blur, autovalidateCallback
|
||||
);
|
||||
} else {
|
||||
self.options.autovalidate(
|
||||
self.options.value, blur, autovalidateCallback
|
||||
);
|
||||
}
|
||||
} else if (Ox.isRegExp(self.options.autovalidate)) {
|
||||
autovalidateCallback(autovalidateFunction(self.options.value));
|
||||
} else {
|
||||
autovalidateTypeFunction(self.options.type, self.options.value);
|
||||
}
|
||||
|
||||
function autovalidateFunction(value) {
|
||||
value = value.split('').map(function(v) {
|
||||
return self.options.autovalidate.test(v) ? v : null;
|
||||
}).join('');
|
||||
return {
|
||||
valid: !!value.length,
|
||||
value: value
|
||||
};
|
||||
}
|
||||
|
||||
function autovalidateTypeFunction(type, value) {
|
||||
// fixme: remove trailing zeroes on blur
|
||||
// /(^\-?\d+\.?\d{0,8}$)/('-13000.12345678')
|
||||
var cursor,
|
||||
length,
|
||||
regexp = type == 'float' ? new RegExp(
|
||||
'(^' + (self.options.min < 0 ? '\\-?' : '') + '\\d+\\.?\\d'
|
||||
+ (self.options.decimals ? '{0,' + self.options.decimals + '}' : '*')
|
||||
+ '$)'
|
||||
) : new RegExp('(^' + (self.options.min < 0 ? '\\-?' : '') + '\\d+)');
|
||||
if (type == 'float') {
|
||||
if (value === '') {
|
||||
value = '0.' + self.decimals;
|
||||
cursor = [0, value.length];
|
||||
} else if (value == '-') {
|
||||
value = '-0.' + self.decimals;
|
||||
cursor = [1, value.length];
|
||||
} else if (value == '.') {
|
||||
value = '0.' + self.decimals;
|
||||
cursor = [2, value.length];
|
||||
} else if (!/\./.test(value)) {
|
||||
value += '.' + self.decimals;
|
||||
cursor = [value.indexOf('.'), value.length];
|
||||
} else if (/^\./.test(value)) {
|
||||
value = '0' + value;
|
||||
cursor = [2, value.length];
|
||||
} else if (/\.$/.test(value)) {
|
||||
value += self.decimals;
|
||||
cursor = [value.indexOf('.') + 1, value.length];
|
||||
} else if (/\./.test(value) && self.options.decimals) {
|
||||
length = value.split('.')[1].length;
|
||||
if (length > self.options.decimals) {
|
||||
value = value.slice(0, value.indexOf('.') + 1 + self.options.decimals);
|
||||
cursor = [oldCursor[0] + 1, oldCursor[1] + 1];
|
||||
} else if (length < self.options.decimals) {
|
||||
value += Ox.repeat('0', self.options.decimals - length);
|
||||
cursor = [value.indexOf('.') + 1 + length, value.length];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (value === '') {
|
||||
value = '0';
|
||||
cursor = [0, 1];
|
||||
}
|
||||
}
|
||||
while (/^0\d/.test(value)) {
|
||||
value = value.slice(1);
|
||||
}
|
||||
if (!regexp.test(value) || value < self.options.min || value > self.options.max) {
|
||||
value = oldValue;
|
||||
cursor = oldCursor;
|
||||
}
|
||||
autovalidateCallback({
|
||||
cursor: cursor,
|
||||
valid: true,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
function autovalidateCallback(data) {
|
||||
//Ox.Log('Form', 'autovalidateCallback', newValue, oldCursor)
|
||||
self.options.value = data.value;
|
||||
self.$input.val(self.options.value);
|
||||
!blur && cursor(
|
||||
data.cursor || (oldCursor[1] + data.value.length - oldValue.length)
|
||||
);
|
||||
that.triggerEvent('autovalidate', {
|
||||
valid: data.valid,
|
||||
value: data.value
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
function autovalidate(blur) {
|
||||
Ox.Log('Form', 'autovalidate', self.options.value, blur || false)
|
||||
self.autocorrectBlur = blur || false;
|
||||
self.autocorrectCursor = cursor();
|
||||
Ox.isFunction(self.options.autocorrect) ?
|
||||
(self.options.key ? self.options.autocorrect(
|
||||
self.options.key,
|
||||
self.options.value,
|
||||
self.autocorrectBlur,
|
||||
autocorrectCallback
|
||||
) : self.options.autocorrect(
|
||||
self.options.value,
|
||||
self.autocorrectBlur,
|
||||
autocorrectCallback
|
||||
)) : autocorrectCallback(autocorrect(self.options.value));
|
||||
}
|
||||
|
||||
function autovalidateFunction(value) {
|
||||
var length = value.length;
|
||||
return value.toLowerCase().split('').map(function(v) {
|
||||
if (new RegExp(self.options.autocorrect).test(v)) {
|
||||
return v;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}).join('');
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
function blur() {
|
||||
that.loseFocus();
|
||||
//that.removeClass('OxFocus');
|
||||
self.options.value = self.$input.val();
|
||||
self.options.autovalidate && autovalidate(true);
|
||||
self.options.placeholder && setPlaceholder();
|
||||
self.options.validate && validate();
|
||||
self.bindKeyboard && Ox.UI.$document.off('keydown', keydown);
|
||||
if (!self.cancelled && !self.submitted) {
|
||||
that.triggerEvent('blur', {
|
||||
value: self.options.value
|
||||
});
|
||||
self.options.value !== self.originalValue && that.triggerEvent('change', {
|
||||
value: self.options.value
|
||||
});
|
||||
}
|
||||
/*
|
||||
self.options.value !== self.originalValue && that.triggerEvent('change', {
|
||||
value: self.options.value
|
||||
});
|
||||
// fixme: for some reason, if options.type is set, no change event fires
|
||||
// as a workaround, blur sends a value. remove later...
|
||||
!self.cancelled && !self.submitted && that.triggerEvent('blur', {
|
||||
value: self.options.value
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
self.cancelled = true;
|
||||
self.$input.val(self.originalValue).blur();
|
||||
self.cancelled = false;
|
||||
that.triggerEvent('cancel');
|
||||
}
|
||||
|
||||
function change() {
|
||||
// change gets invoked before blur
|
||||
self.options.value = self.$input.val();
|
||||
self.originalValue = self.options.value;
|
||||
!self.options.changeOnKeypress && that.triggerEvent('change', {
|
||||
value: self.options.value
|
||||
});
|
||||
}
|
||||
|
||||
function clear() {
|
||||
// fixme: set to min, not zero
|
||||
// fixme: make this work for password
|
||||
that.triggerEvent('clear');
|
||||
self.options.value = '';
|
||||
if (self.options.type == 'float') {
|
||||
self.options.value = '0.0';
|
||||
} else if (self.options.type == 'int') {
|
||||
self.options.value = '0'
|
||||
}
|
||||
self.$input.val(self.options.value);
|
||||
cursor(0, self.options.value.length);
|
||||
self.options.changeOnKeypress && that.triggerEvent({
|
||||
change: {value: self.options.value}
|
||||
});
|
||||
}
|
||||
|
||||
function clickArrow(i) {
|
||||
self.options.value = Ox.limit(
|
||||
parseFloat(self.options.value) + (i == 0 ? -1 : 1) * self.options.arrowStep,
|
||||
self.options.min,
|
||||
self.options.max
|
||||
).toString();
|
||||
self.$input.val(self.options.value);//.focus();
|
||||
}
|
||||
|
||||
function clickMenu(data) {
|
||||
//Ox.Log('Form', 'clickMenu', data);
|
||||
self.options.value = data.title;
|
||||
self.$input.val(self.options.value).focus();
|
||||
that.gainFocus();
|
||||
self.options.autocompleteSelectSubmit && submit();
|
||||
}
|
||||
|
||||
function cursor(start, end) {
|
||||
/*
|
||||
cursor() returns [start, end]
|
||||
cursor(start) sets start
|
||||
cursor([start, end]) sets start and end
|
||||
cursor(start, end) sets start and end
|
||||
*/
|
||||
var isArray = Ox.isArray(start);
|
||||
if (arguments.length == 0) {
|
||||
return [self.$input[0].selectionStart, self.$input[0].selectionEnd];
|
||||
} else {
|
||||
end = isArray ? start[1] : (end ? end : start);
|
||||
start = isArray ? start[0] : start;
|
||||
//IE8 does not have setSelectionRange
|
||||
self.$input[0].setSelectionRange && self.$input[0].setSelectionRange(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
function deselectMenu() {
|
||||
return;
|
||||
//Ox.Log('Form', 'deselectMenu')
|
||||
self.options.value = self.oldValue;
|
||||
self.$input.val(self.options.value);
|
||||
cursor(self.oldCursor);
|
||||
}
|
||||
|
||||
function focus() {
|
||||
if (
|
||||
// that.hasClass('OxFocus') || // fixme: this is just a workaround, since for some reason, focus() gets called twice on focus
|
||||
(self.$autocompleteMenu && self.$autocompleteMenu.is(':visible')) ||
|
||||
(self.hasPasswordPlaceholder && self.$input.is(':visible'))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
self.originalValue = self.options.value;
|
||||
that.gainFocus();
|
||||
that.is('.OxError') && that.removeClass('OxError');
|
||||
self.options.placeholder && setPlaceholder();
|
||||
if (self.bindKeyboard) {
|
||||
// fixme: different in webkit and firefox (?), see keyboard handler, need generic function
|
||||
Ox.UI.$document.keydown(keydown);
|
||||
//Ox.UI.$document.keypress(keypress);
|
||||
// temporarily disabled autocomplete on focus
|
||||
//self.options.autocompleteSelect && setTimeout(autocomplete, 0); // fixme: why is the timeout needed?
|
||||
}
|
||||
that.triggerEvent('focus');
|
||||
}
|
||||
|
||||
function getInputWidth() {
|
||||
return self.options.width
|
||||
- (self.options.arrows ? 32 : 0)
|
||||
- (self.options.clear ? 16 : 0)
|
||||
- (self.options.label ? self.options.labelWidth : 0)
|
||||
- (self.options.style == 'rounded' ? 14 : 6);
|
||||
}
|
||||
|
||||
function insert() {
|
||||
var input = self.$input[0];
|
||||
that.triggerEvent('insert', {
|
||||
end: input.selectionEnd,
|
||||
id: that.oxid,
|
||||
selection: input.value.slice(input.selectionStart, input.selectionEnd),
|
||||
start: input.selectionStart,
|
||||
value: input.value
|
||||
});
|
||||
}
|
||||
|
||||
function keydown(event) {
|
||||
var oldCursor = cursor(),
|
||||
oldValue = self.options.value,
|
||||
newValue = oldValue.slice(0, oldCursor[0] - 1),
|
||||
hasDeletedSelectedEnd = (event.keyCode == 8 || event.keyCode == 46) &&
|
||||
oldCursor[0] < oldCursor[1] && oldCursor[1] == oldValue.length;
|
||||
if (
|
||||
event.keyCode != 9 // tab
|
||||
&& (self.options.type == 'textarea' || event.keyCode != 13) // enter
|
||||
&& event.keyCode != 27 // escape
|
||||
) { // fixme: can't 13 and 27 return false?
|
||||
setTimeout(function() { // wait for val to be set
|
||||
var value = self.$input.val();
|
||||
if ((self.options.autocompleteReplace || self.options.decimals) && hasDeletedSelectedEnd) {
|
||||
//Ox.Log('Form', 'HAS DELETED SELECTED END', event.keyCode)
|
||||
value = newValue;
|
||||
self.$input.val(value);
|
||||
}
|
||||
if (value != self.options.value) {
|
||||
self.options.value = value;
|
||||
Ox.Log('AUTO', 'call autocomplete from keydown')
|
||||
self.options.autocomplete && autocomplete(oldValue, oldCursor);
|
||||
self.options.autovalidate && autovalidate(oldValue, oldCursor);
|
||||
self.options.changeOnKeypress && that.triggerEvent({
|
||||
change: {value: self.options.value}
|
||||
});
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
if (
|
||||
(event.keyCode == 38 || event.keyCode == 40) // up/down
|
||||
&& self.options.autocompleteSelect
|
||||
&& self.$autocompleteMenu.is(':visible')
|
||||
) {
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
||||
function paste() {
|
||||
// fixme: unused
|
||||
var data = Ox.Clipboard.paste();
|
||||
data.text && self.$input.val(data.text);
|
||||
}
|
||||
|
||||
function selectMenu(data) {
|
||||
var pos = cursor();
|
||||
//if (self.options.value) {
|
||||
//Ox.Log('Form', 'selectMenu', pos, data.title)
|
||||
self.options.value = data.title
|
||||
self.$input.val(self.options.value);
|
||||
cursor(pos[0], self.options.value.length);
|
||||
self.options.changeOnKeypress && that.triggerEvent({
|
||||
change: {value: self.options.value}
|
||||
});
|
||||
//}
|
||||
}
|
||||
|
||||
function setPlaceholder() {
|
||||
if (self.options.placeholder) {
|
||||
if (that.hasClass('OxFocus')) {
|
||||
if (self.options.value === '') {
|
||||
if (self.options.type == 'password') {
|
||||
self.$placeholder.hide();
|
||||
self.$input.show().focus();
|
||||
} else {
|
||||
self.$input
|
||||
.removeClass('OxPlaceholder')
|
||||
.val('');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (self.options.value === '') {
|
||||
if (self.options.type == 'password') {
|
||||
self.$input.hide();
|
||||
self.$placeholder.show();
|
||||
} else {
|
||||
self.$input
|
||||
.addClass('OxPlaceholder')
|
||||
.val(self.options.placeholder)
|
||||
}
|
||||
} else {
|
||||
self.$input
|
||||
.removeClass('OxPlaceholder')
|
||||
.val(self.options.value)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.$input
|
||||
.removeClass('OxPlaceholder')
|
||||
.val(self.options.value);
|
||||
}
|
||||
}
|
||||
|
||||
function setWidth() {
|
||||
|
||||
}
|
||||
|
||||
function submit() {
|
||||
self.submitted = true;
|
||||
self.$input.blur();
|
||||
self.submitted = false;
|
||||
//self.options.type == 'textarea' && self.$input.blur();
|
||||
that.triggerEvent('submit', {
|
||||
value: self.options.value
|
||||
});
|
||||
}
|
||||
|
||||
function validate() {
|
||||
self.options.validate(self.options.value, function(data) {
|
||||
that.triggerEvent('validate', data);
|
||||
});
|
||||
}
|
||||
|
||||
/*@
|
||||
blurInput <f> blurInput
|
||||
@*/
|
||||
that.blurInput = function() {
|
||||
self.$input.blur();
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
clearInput <f> clearInput
|
||||
@*/
|
||||
that.clearInput = function() {
|
||||
clear();
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
focusInput <f> Focus input element
|
||||
(select) -> <o> Input object
|
||||
(start, end) -> <o> Input object
|
||||
select <b|false> If true, select all, otherwise position cursor at the end
|
||||
start <n> Selection start (can be negative)
|
||||
end <n> Selection end (can be negative), or equal to start if omitted
|
||||
@*/
|
||||
that.focusInput = function() {
|
||||
var length = self.$input.val().length,
|
||||
start = Ox.isNumber(arguments[0])
|
||||
? (arguments[0] < 0 ? length + arguments[0] : arguments[0])
|
||||
: arguments[0] ? 0 : length,
|
||||
stop = Ox.isNumber(arguments[1])
|
||||
? (arguments[1] < 0 ? length + arguments[1] : arguments[1])
|
||||
: Ox.isNumber(arguments[0]) ? arguments[0]
|
||||
: arguments[0] ? length : 0;
|
||||
self.$input.focus();
|
||||
cursor(start, stop);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
value <f> get/set value
|
||||
@*/
|
||||
// FIXME: deprecate, options are enough
|
||||
that.value = function() {
|
||||
if (arguments.length == 0) {
|
||||
var value = self.$input.hasClass('OxPlaceholder') ? '' : self.$input.val();
|
||||
if (self.options.type == 'float') {
|
||||
value = parseFloat(value);
|
||||
} else if (self.options.type == 'int') {
|
||||
value = parseInt(value); // cannot have leading zero
|
||||
}
|
||||
return value;
|
||||
} else {
|
||||
return that.options({value: arguments[0]});
|
||||
}
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue