forked from 0x2620/oxjs
better filesystem structure for modules and themes; 'minified' ui if debug option not set; dynamially generated map markers
This commit is contained in:
parent
358ee1bc96
commit
4489e88f44
596 changed files with 115093 additions and 17682 deletions
164
source/Ox.UI/js/Form/Ox.Button.js
Normal file
164
source/Ox.UI/js/Form/Ox.Button.js
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Button = function(options, self) {
|
||||
|
||||
/**
|
||||
methods:
|
||||
toggleDisabled enable/disable button
|
||||
toggleSelected select/unselect button
|
||||
toggleTitle if more than one title was provided,
|
||||
toggle to next title.
|
||||
events:
|
||||
click non-selectable button was clicked
|
||||
deselect selectable button was deselected
|
||||
select selectable button was selected
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('input', self)
|
||||
.defaults({
|
||||
disabled: false,
|
||||
group: false,
|
||||
id: '',
|
||||
overlap: 'none',
|
||||
selectable: false,
|
||||
selected: false,
|
||||
size: 'medium',
|
||||
// fixme: 'default' or ''?
|
||||
style: 'default', // can be default, checkbox, symbol, or tab
|
||||
title: '',
|
||||
tooltip: '',
|
||||
type: 'text',
|
||||
width: 'auto'
|
||||
})
|
||||
.options(options || {})
|
||||
.attr({
|
||||
disabled: self.options.disabled ? 'disabled' : '',
|
||||
type: self.options.type == 'text' ? 'button' : 'image'
|
||||
})
|
||||
.addClass('OxButton Ox' + Ox.toTitleCase(self.options.size) +
|
||||
(self.options.disabled ? ' OxDisabled': '') +
|
||||
(self.options.selected ? ' OxSelected': '') +
|
||||
(self.options.style != 'default' ? ' Ox' + Ox.toTitleCase(self.options.style) : '') +
|
||||
(self.options.overlap != 'none' ? ' OxOverlap' + Ox.toTitleCase(self.options.overlap) : ''))
|
||||
.css(self.options.width == 'auto' ? {} : {
|
||||
width: (self.options.width - 14) + 'px'
|
||||
})
|
||||
.mousedown(mousedown)
|
||||
.click(click);
|
||||
|
||||
$.extend(self, Ox.isArray(self.options.title) ? {
|
||||
selectedTitle: Ox.setPropertyOnce(self.options.title, 'selected'),
|
||||
titles: self.options.title
|
||||
} : {
|
||||
selectedTitle: 0,
|
||||
titles: [{
|
||||
id: '',
|
||||
title: self.options.title
|
||||
}]
|
||||
});
|
||||
|
||||
setTitle(self.titles[self.selectedTitle].title);
|
||||
|
||||
if (self.options.tooltip) {
|
||||
self.tooltips = Ox.isArray(self.options.tooltip) ? self.options.tooltip : [self.options.tooltip];
|
||||
self.$tooltip = new Ox.Tooltip({
|
||||
title: self.tooltips[self.selectedTitle]
|
||||
});
|
||||
that.mouseenter(mouseenter)
|
||||
.mouseleave(mouseleave);
|
||||
}
|
||||
|
||||
function click() {
|
||||
if (!self.options.disabled) {
|
||||
var data = self.titles[self.selectedTitle];
|
||||
if (!self.options.selectable) {
|
||||
that.triggerEvent('click', data);
|
||||
} else {
|
||||
//self.options.selected = !self.options.selected;
|
||||
//that.toggleClass('OxSelected');
|
||||
if (self.options.group) {
|
||||
that.triggerEvent('select', data);
|
||||
} else {
|
||||
that.toggleSelected();
|
||||
//that.triggerEvent('change', {selected: self.options.selected});
|
||||
}
|
||||
}
|
||||
if (self.titles.length == 2) {
|
||||
that.toggleTitle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function mousedown(e) {
|
||||
if (self.options.type == 'image' && $.browser.safari) {
|
||||
// keep image from being draggable
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function mouseenter(e) {
|
||||
self.$tooltip.show(e.clientX, e.clientY);
|
||||
}
|
||||
|
||||
function mouseleave() {
|
||||
self.$tooltip.hide();
|
||||
}
|
||||
|
||||
function setTitle(title) {
|
||||
self.title = title;
|
||||
if (self.options.type == 'image') {
|
||||
that.attr({
|
||||
src: Ox.UI.getImagePath(
|
||||
'symbol' + title[0].toUpperCase() + title.substr(1) + '.svg'
|
||||
)
|
||||
});
|
||||
} else {
|
||||
that.val(title);
|
||||
}
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
if (key == 'disabled') {
|
||||
that.attr({
|
||||
disabled: value ? 'disabled' : ''
|
||||
})
|
||||
.toggleClass('OxDisabled');
|
||||
} else if (key == 'selected') {
|
||||
if (value != that.hasClass('OxSelected')) { // fixme: neccessary?
|
||||
that.toggleClass('OxSelected');
|
||||
}
|
||||
that.triggerEvent('change');
|
||||
} else if (key == 'title') {
|
||||
setTitle(value);
|
||||
} else if (key == 'width') {
|
||||
that.$element.css({
|
||||
width: (value - 14) + 'px'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
that.toggleDisabled = function() {
|
||||
that.options({
|
||||
enabled: !self.options.disabled
|
||||
});
|
||||
//self.options.disabled = !self.options.disabled;
|
||||
}
|
||||
|
||||
that.toggleSelected = function() {
|
||||
that.options({
|
||||
selected: !self.options.selected
|
||||
});
|
||||
//self.options.selected = !self.options.selected;
|
||||
}
|
||||
|
||||
that.toggleTitle = function() {
|
||||
self.selectedTitle = 1 - self.selectedTitle;
|
||||
setTitle(self.titles[self.selectedTitle].title);
|
||||
self.$tooltip && self.$tooltip.options({
|
||||
title: self.tooltips[self.selectedTitle]
|
||||
});
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
75
source/Ox.UI/js/Form/Ox.ButtonGroup.js
Normal file
75
source/Ox.UI/js/Form/Ox.ButtonGroup.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.ButtonGroup = function(options, self) {
|
||||
|
||||
/**
|
||||
options
|
||||
buttons array of buttons
|
||||
max integer, maximum number of selected buttons, 0 for all
|
||||
min integer, minimum number of selected buttons, 0 for none
|
||||
selectable if true, buttons are selectable
|
||||
type string, 'image' or 'text'
|
||||
methods:
|
||||
events:
|
||||
change {id, value} selection within a group changed
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
buttons: [],
|
||||
max: 1,
|
||||
min: 1,
|
||||
selectable: false,
|
||||
size: 'medium',
|
||||
style: '',
|
||||
type: 'text',
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxButtonGroup');
|
||||
|
||||
if (self.options.selectable) {
|
||||
self.optionGroup = new Ox.OptionGroup(
|
||||
self.options.buttons,
|
||||
self.options.min,
|
||||
self.options.max,
|
||||
'selected'
|
||||
);
|
||||
self.options.buttons = self.optionGroup.init();
|
||||
}
|
||||
|
||||
self.$buttons = [];
|
||||
self.options.buttons.forEach(function(button, position) {
|
||||
var id = self.options.id + Ox.toTitleCase(button.id)
|
||||
self.$buttons[position] = Ox.Button({
|
||||
disabled: button.disabled,
|
||||
group: true,
|
||||
id: id,
|
||||
selectable: self.options.selectable,
|
||||
selected: button.selected,
|
||||
size: self.options.size,
|
||||
style: self.options.style,
|
||||
title: button.title,
|
||||
type: self.options.type
|
||||
})
|
||||
.bindEvent('select', function() {
|
||||
selectButton(position);
|
||||
})
|
||||
.appendTo(that);
|
||||
});
|
||||
|
||||
function selectButton(pos) {
|
||||
var toggled = self.optionGroup.toggle(pos);
|
||||
if (toggled.length) {
|
||||
toggled.forEach(function(pos, i) {
|
||||
self.$buttons[pos].toggleSelected();
|
||||
});
|
||||
that.triggerEvent('change', {
|
||||
selected: $.map(self.optionGroup.selected(), function(v, i) {
|
||||
return self.options.buttons[v].id;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
};
|
||||
105
source/Ox.UI/js/Form/Ox.Checkbox.js
Normal file
105
source/Ox.UI/js/Form/Ox.Checkbox.js
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Checkbox = function(options, self) {
|
||||
|
||||
/**
|
||||
options
|
||||
disabled boolean, if true, checkbox is disabled
|
||||
id element id
|
||||
group boolean, if true, checkbox is part of a group
|
||||
checked boolean, if true, checkbox is checked
|
||||
title string, text on label
|
||||
width integer, width in px
|
||||
methods:
|
||||
toggleChecked function()
|
||||
toggles checked property
|
||||
returns that
|
||||
events:
|
||||
change triggered when checked property changes
|
||||
passes {checked, id, title}
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
disabled: false,
|
||||
id: '',
|
||||
group: false,
|
||||
checked: false,
|
||||
overlap: 'none',
|
||||
title: '',
|
||||
width: 'auto'
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxCheckbox' +
|
||||
(self.options.overlap == 'none' ? '' : ' OxOverlap' +
|
||||
Ox.toTitleCase(self.options.overlap))
|
||||
)
|
||||
.attr(self.options.disabled ? {
|
||||
disabled: 'disabled'
|
||||
} : {});
|
||||
|
||||
if (self.options.title) {
|
||||
self.options.width != 'auto' && that.css({
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
self.$title = new Ox.Label({
|
||||
disabled: self.options.disabled,
|
||||
id: self.options.id + 'Label',
|
||||
overlap: 'left',
|
||||
title: self.options.title,
|
||||
width: self.options.width - 16
|
||||
})
|
||||
.css({
|
||||
float: 'right'
|
||||
})
|
||||
.click(clickTitle)
|
||||
.appendTo(that);
|
||||
}
|
||||
|
||||
self.$button = new Ox.Button({
|
||||
disabled: self.options.disabled,
|
||||
id: self.options.id + 'Button',
|
||||
title: [
|
||||
{id: 'none', title: 'none', selected: !self.options.checked},
|
||||
{id: 'check', title: 'check', selected: self.options.checked}
|
||||
],
|
||||
type: 'image'
|
||||
})
|
||||
.addClass('OxCheckbox')
|
||||
.click(clickButton)
|
||||
.appendTo(that);
|
||||
|
||||
function clickButton() {
|
||||
self.options.checked = !self.options.checked;
|
||||
// click will have toggled the button,
|
||||
// if it is part of a group, we have to revert that
|
||||
self.options.group && that.toggleChecked();
|
||||
that.triggerEvent('change', {
|
||||
checked: self.options.checked,
|
||||
id: self.options.id,
|
||||
title: self.options.title
|
||||
});
|
||||
}
|
||||
|
||||
function clickTitle() {
|
||||
!self.options.disabled && self.$button.trigger('click');
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
if (key == 'checked') {
|
||||
that.toggleChecked();
|
||||
}
|
||||
};
|
||||
|
||||
that.checked = function() {
|
||||
return self.options.checked;
|
||||
}
|
||||
|
||||
that.toggleChecked = function() {
|
||||
self.$button.toggleTitle();
|
||||
return that;
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
71
source/Ox.UI/js/Form/Ox.CheckboxGroup.js
Normal file
71
source/Ox.UI/js/Form/Ox.CheckboxGroup.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.CheckboxGroup = function(options, self) {
|
||||
|
||||
/**
|
||||
options
|
||||
checkboxes [] array of checkboxes
|
||||
max 1 integer
|
||||
min 1 integer
|
||||
width integer, width in px
|
||||
events:
|
||||
change triggered when checked property changes
|
||||
passes {checked, id, title}
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
checkboxes: [],
|
||||
max: 1,
|
||||
min: 1,
|
||||
width: 256
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxCheckboxGroup');
|
||||
|
||||
self.optionGroup = new Ox.OptionGroup(
|
||||
self.options.checkboxes,
|
||||
self.options.min,
|
||||
self.options.max);
|
||||
self.options.checkboxes = self.optionGroup.init();
|
||||
|
||||
$.extend(self, {
|
||||
$checkboxes: [],
|
||||
checkboxWidth: $.map(Ox.divideInt(
|
||||
self.options.width + (self.options.checkboxes.length - 1) * 6,
|
||||
self.options.checkboxes.length
|
||||
), function(v, i) {
|
||||
return v + (i < self.options.checkboxes.length - 1 ? 10 : 0);
|
||||
})
|
||||
});
|
||||
self.options.checkboxes.forEach(function(checkbox, position) {
|
||||
var id = self.options.id + Ox.toTitleCase(checkbox.id)
|
||||
self.$checkboxes[position] = new Ox.Checkbox($.extend(checkbox, {
|
||||
group: true,
|
||||
id: id,
|
||||
width: self.checkboxWidth[position]
|
||||
}))
|
||||
.bindEvent('change', function() {
|
||||
change(position);
|
||||
})
|
||||
.appendTo(that);
|
||||
});
|
||||
|
||||
function change(pos) {
|
||||
var toggled = self.optionGroup.toggle(pos);
|
||||
//Ox.print('change', pos, 'toggled', toggled)
|
||||
if (toggled.length) {
|
||||
toggled.forEach(function(pos, i) {
|
||||
self.$checkboxes[pos].toggleChecked();
|
||||
});
|
||||
that.triggerEvent('change', {
|
||||
checked: $.map(self.optionGroup.checked(), function(v, i) {
|
||||
return self.options.checkboxes[v].id;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
72
source/Ox.UI/js/Form/Ox.ColorInput.js
Normal file
72
source/Ox.UI/js/Form/Ox.ColorInput.js
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.ColorInput = function(options, self) {
|
||||
|
||||
var self = $.extend(self || {}, {
|
||||
options: $.extend({
|
||||
id: '',
|
||||
value: '0, 0, 0'
|
||||
}, options)
|
||||
}),
|
||||
that;
|
||||
|
||||
self.values = self.options.value.split(', ');
|
||||
self.$inputs = [];
|
||||
['red', 'green', 'blue'].forEach(function(v, i) {
|
||||
self.$inputs[i] = new Ox.Input({
|
||||
id: v,
|
||||
max: 255,
|
||||
type: 'integer',
|
||||
value: self.values[i],
|
||||
width: 36
|
||||
})
|
||||
.bindEvent('autovalidate', change);
|
||||
});
|
||||
self.$inputs[3] = new Ox.Label({
|
||||
id: 'color',
|
||||
width: 36
|
||||
})
|
||||
.css({
|
||||
background: 'rgb(' + self.options.value + ')'
|
||||
});
|
||||
self.$inputs[4] = new Ox.ColorPicker({
|
||||
id: 'picker'
|
||||
})
|
||||
.bindEvent('change', function(event, data) {
|
||||
//Ox.print('change function called');
|
||||
self.options.value = data.value;
|
||||
self.values = data.value.split(', ');
|
||||
Ox.range(3).forEach(function(i) {
|
||||
self.$inputs[i].options({
|
||||
value: self.values[i]
|
||||
});
|
||||
});
|
||||
})
|
||||
.options({
|
||||
width: 16 // this is just a hack to make the InputGroup layout work
|
||||
});
|
||||
|
||||
that = new Ox.InputGroup({
|
||||
id: self.options.id,
|
||||
inputs: self.$inputs,
|
||||
separators: [
|
||||
{title: ',', width: 8},
|
||||
{title: ',', width: 8},
|
||||
{title: '', width: 8},
|
||||
{title: '', width: 8}
|
||||
],
|
||||
value: self.options.value // fixme: it'd be nicer if this would be taken care of by passing self
|
||||
}, self)
|
||||
.bindEvent('change', change);
|
||||
|
||||
function change() {
|
||||
self.options.value = $.map(self.$inputs, function(v, i) {
|
||||
return v.options('value');
|
||||
}).join(', ');
|
||||
self.$inputs[3].css({
|
||||
background: 'rgb(' + self.options.value + ')'
|
||||
});
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
92
source/Ox.UI/js/Form/Ox.ColorPicker.js
Normal file
92
source/Ox.UI/js/Form/Ox.ColorPicker.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.ColorPicker = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
id: '',
|
||||
value: '0, 0, 0'
|
||||
})
|
||||
.options(options || {});
|
||||
|
||||
//Ox.print(self)
|
||||
self.$ranges = [];
|
||||
self.rgb = ['red', 'green', 'blue'];
|
||||
self.values = self.options.value.split(', ');
|
||||
|
||||
Ox.range(3).forEach(function(i) {
|
||||
self.$ranges[i] = new Ox.Range({
|
||||
arrows: true,
|
||||
id: self.options.id + Ox.toTitleCase(self.rgb[i]),
|
||||
max: 255,
|
||||
size: 328, // 256 + 16 + 40 + 16
|
||||
thumbSize: 40,
|
||||
thumbValue: true,
|
||||
trackColors: getColors(i),
|
||||
value: self.values[i]
|
||||
})
|
||||
.css({
|
||||
position: 'absolute',
|
||||
top: (i * 15) + 'px'
|
||||
})
|
||||
.bindEvent('change', function(event, data) {
|
||||
change(i, data.value);
|
||||
})
|
||||
.appendTo(that);
|
||||
// fixme: make self.$ranges[i].children() work
|
||||
if (i == 0) {
|
||||
self.$ranges[i].$element.children('input.OxOverlapRight').css({
|
||||
MozBorderRadius: 0,
|
||||
WebkitBorderRadius: 0
|
||||
});
|
||||
self.$ranges[i].$element.children('input.OxOverlapLeft').css({
|
||||
MozBorderRadius: '0 8px 0 0',
|
||||
WebkitBorderRadius: '0 8px 0 0'
|
||||
});
|
||||
} else {
|
||||
self.$ranges[i].$element.children('input').css({
|
||||
MozBorderRadius: 0,
|
||||
WebkitBorderRadius: 0
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
that = new Ox.Picker({
|
||||
element: that,
|
||||
elementHeight: 46,
|
||||
elementWidth: 328,
|
||||
id: self.options.id
|
||||
});
|
||||
|
||||
function change(index, value) {
|
||||
self.values[index] = value;
|
||||
self.options.value = self.values.join(', ');
|
||||
that.$label.css({
|
||||
background: 'rgb(' + self.options.value + ')'
|
||||
});
|
||||
Ox.range(3).forEach(function(i) {
|
||||
if (i != index) {
|
||||
self.$ranges[i].options({
|
||||
trackColors: getColors(i)
|
||||
});
|
||||
}
|
||||
});
|
||||
that.triggerEvent('change', {
|
||||
value: self.options.value
|
||||
});
|
||||
}
|
||||
|
||||
function getColors(index) {
|
||||
return [
|
||||
'rgb(' + $.map(Ox.range(3), function(v) {
|
||||
return v == index ? 0 : self.values[v];
|
||||
}).join(', ') + ')',
|
||||
'rgb(' + $.map(Ox.range(3), function(v) {
|
||||
return v == index ? 255 : self.values[v];
|
||||
}).join(', ') + ')'
|
||||
]
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
218
source/Ox.UI/js/Form/Ox.DateInput.js
Normal file
218
source/Ox.UI/js/Form/Ox.DateInput.js
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.DateInput = function(options, self) {
|
||||
|
||||
/**
|
||||
options:
|
||||
format: 'short'
|
||||
value: date value
|
||||
weekday: false
|
||||
width: {
|
||||
day: 32,
|
||||
month: options.format == 'long' ? 80 : (options.format == 'medium' ? 40 : 32),
|
||||
weekday: options.format == 'long' ? 80 : 40,
|
||||
year: 48
|
||||
}
|
||||
*/
|
||||
|
||||
var self = $.extend(self || {}, {
|
||||
options: $.extend({
|
||||
format: 'short',
|
||||
value: Ox.formatDate(new Date(), '%F'),
|
||||
weekday: false,
|
||||
width: {
|
||||
day: 32,
|
||||
month: options.format == 'long' ? 80 : (options.format == 'medium' ? 40 : 32),
|
||||
weekday: options.format == 'long' ? 80 : 40,
|
||||
year: 48
|
||||
}
|
||||
}, options)
|
||||
}),
|
||||
that;
|
||||
|
||||
$.extend(self, {
|
||||
date: new Date(self.options.value.replace(/-/g, '/')),
|
||||
formats: {
|
||||
day: '%d',
|
||||
month: self.options.format == 'short' ? '%m' :
|
||||
(self.options.format == 'medium' ? '%b' : '%B'),
|
||||
weekday: self.options.format == 'long' ? '%A' : '%a',
|
||||
year: '%Y'
|
||||
},
|
||||
months: self.options.format == 'long' ? Ox.MONTHS : $.map(Ox.MONTHS, function(v, i) {
|
||||
return v.substr(0, 3);
|
||||
}),
|
||||
weekdays: self.options.format == 'long' ? Ox.WEEKDAYS : $.map(Ox.WEEKDAYS, function(v, i) {
|
||||
return v.substr(0, 3);
|
||||
})
|
||||
});
|
||||
|
||||
self.$input = $.extend(self.options.weekday ? {
|
||||
weekday: new Ox.Input({
|
||||
autocomplete: self.weekdays,
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'weekday',
|
||||
value: Ox.formatDate(self.date, self.formats.weekday),
|
||||
width: self.options.width.weekday
|
||||
})
|
||||
.bindEvent('autocomplete', changeWeekday),
|
||||
} : {}, {
|
||||
day: new Ox.Input({
|
||||
autocomplete: $.map(Ox.range(1, Ox.getDaysInMonth(
|
||||
parseInt(Ox.formatDate(self.date, '%Y'), 10),
|
||||
parseInt(Ox.formatDate(self.date, '%m'), 10)
|
||||
) + 1), function(v, i) {
|
||||
return self.options.format == 'short' ? Ox.pad(v, 2) : v.toString();
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'day',
|
||||
value: Ox.formatDate(self.date, self.formats.day),
|
||||
textAlign: 'right',
|
||||
width: self.options.width.day
|
||||
})
|
||||
.bindEvent('autocomplete', changeDay),
|
||||
month: new Ox.Input({
|
||||
autocomplete: self.options.format == 'short' ? $.map(Ox.range(1, 13), function(v, i) {
|
||||
return Ox.pad(v, 2);
|
||||
}) : self.months,
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'month',
|
||||
value: Ox.formatDate(self.date, self.formats.month),
|
||||
textAlign: self.options.format == 'short' ? 'right' : 'left',
|
||||
width: self.options.width.month
|
||||
})
|
||||
.bindEvent('autocomplete', changeMonthOrYear),
|
||||
year: new Ox.Input({
|
||||
autocomplete: $.map($.merge(Ox.range(1900, 3000), Ox.range(1000, 1900)), function(v, i) {
|
||||
return v.toString();
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'year',
|
||||
value: Ox.formatDate(self.date, self.formats.year),
|
||||
textAlign: 'right',
|
||||
width: self.options.width.year
|
||||
})
|
||||
.bindEvent('autocomplete', changeMonthOrYear)
|
||||
});
|
||||
|
||||
that = new Ox.InputGroup($.extend(self.options, {
|
||||
id: self.options.id,
|
||||
inputs: $.merge(self.options.weekday ? [
|
||||
self.$input.weekday
|
||||
] : [], self.options.format == 'short' ? [
|
||||
self.$input.year, self.$input.month, self.$input.day
|
||||
] : [
|
||||
self.$input.month, self.$input.day, self.$input.year
|
||||
]),
|
||||
separators: $.merge(self.options.weekday ? [
|
||||
{title: self.options.format == 'short' ? '' : ',', width: 8},
|
||||
] : [], self.options.format == 'short' ? [
|
||||
{title: '-', width: 8}, {title: '-', width: 8}
|
||||
] : [
|
||||
{title: '', width: 8}, {title: ',', width: 8}
|
||||
]),
|
||||
width: 0
|
||||
}), self);
|
||||
|
||||
//Ox.print('SELF', self)
|
||||
|
||||
function changeDay() {
|
||||
self.options.weekday && self.$input.weekday.options({
|
||||
value: Ox.formatDate(new Date([
|
||||
self.$input.month.options('value'),
|
||||
self.$input.day.options('value'),
|
||||
self.$input.year.options('value')
|
||||
].join(' ')), self.formats.weekday)
|
||||
});
|
||||
setValue();
|
||||
}
|
||||
|
||||
function changeMonthOrYear() {
|
||||
var day = self.$input.day.options('value'),
|
||||
month = self.$input.month.options('value'),
|
||||
year = self.$input.year.options('value'),
|
||||
days = Ox.getDaysInMonth(year, self.options.format == 'short' ? parseInt(month, 10) : month);
|
||||
day = day <= days ? day : days;
|
||||
//Ox.print(year, month, 'day days', day, days)
|
||||
self.options.weekday && self.$input.weekday.options({
|
||||
value: Ox.formatDate(new Date([month, day, year].join(' ')), self.formats.weekday)
|
||||
});
|
||||
self.$input.day.options({
|
||||
autocomplete: $.map(Ox.range(1, days + 1), function(v, i) {
|
||||
return self.options.format == 'short' ? Ox.pad(v, 2) : v.toString();
|
||||
}),
|
||||
value: self.options.format == 'short' ? Ox.pad(day, 2) : day.toString()
|
||||
});
|
||||
setValue();
|
||||
}
|
||||
|
||||
function changeWeekday() {
|
||||
var date = getDateInWeek(
|
||||
self.$input.weekday.options('value'),
|
||||
self.$input.month.options('value'),
|
||||
self.$input.day.options('value'),
|
||||
self.$input.year.options('value')
|
||||
);
|
||||
self.$input.month.options({value: date.month});
|
||||
self.$input.day.options({
|
||||
autocomplete: $.map(Ox.range(1, Ox.getDaysInMonth(date.year, date.month) + 1), function(v, i) {
|
||||
return self.options.format == 'short' ? Ox.pad(v, 2) : v.toString();
|
||||
}),
|
||||
value: date.day
|
||||
});
|
||||
self.$input.year.options({value: date.year});
|
||||
setValue();
|
||||
}
|
||||
|
||||
function getDateInWeek(weekday, month, day, year) {
|
||||
//Ox.print([month, day, year].join(' '))
|
||||
var date = new Date([month, day, year].join(' '));
|
||||
date = Ox.getDateInWeek(date, weekday);
|
||||
return {
|
||||
day: Ox.formatDate(date, self.formats.day),
|
||||
month: Ox.formatDate(date, self.formats.month),
|
||||
year: Ox.formatDate(date, self.formats.year)
|
||||
};
|
||||
}
|
||||
|
||||
function setValue() {
|
||||
self.options.value = Ox.formatDate(new Date(self.options.format == 'short' ? [
|
||||
self.$input.year.options('value'),
|
||||
self.$input.month.options('value'),
|
||||
self.$input.day.options('value')
|
||||
].join('/') : [
|
||||
self.$input.month.options('value'),
|
||||
self.$input.day.options('value'),
|
||||
self.$input.year.options('value')
|
||||
].join(' ')), '%F');
|
||||
}
|
||||
|
||||
/*
|
||||
function normalize() {
|
||||
var year = that.getInputById('year').options('value'),
|
||||
month = that.getInputById('month').options('value'),
|
||||
day = that.getInputById('day').options('value')
|
||||
return {
|
||||
year: year,
|
||||
month: self.options.format == 'short' ? month :
|
||||
Ox.pad((format == 'medium' ? Ox.WEEKDAYS.map(function(v, i) {
|
||||
return v.substr(0, 3);
|
||||
}) : Ox.WEEKDAYS).indexOf(month), 2),
|
||||
day: Ox.pad(day, 2)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
that.serialize = function() {
|
||||
var normal = normalize();
|
||||
return [normal.year, normal.month, normal.day].join('-');
|
||||
}
|
||||
*/
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
49
source/Ox.UI/js/Form/Ox.DateTimeInput.js
Normal file
49
source/Ox.UI/js/Form/Ox.DateTimeInput.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.DateTimeInput = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
ampm: false,
|
||||
format: 'short',
|
||||
seconds: false,
|
||||
value: Ox.formatDate(new Date(), '%F %T'),
|
||||
weekday: false
|
||||
})
|
||||
.options(options || {});
|
||||
|
||||
self.values = self.options.value.split(' ');
|
||||
//Ox.print(self.values)
|
||||
|
||||
that = new Ox.InputGroup({
|
||||
inputs: [
|
||||
new Ox.DateInput({
|
||||
format: self.options.format,
|
||||
id: 'date',
|
||||
value: self.values[0],
|
||||
weekday: self.options.weekday
|
||||
}),
|
||||
new Ox.TimeInput({
|
||||
ampm: self.options.ampm,
|
||||
id: 'time',
|
||||
value: self.values[1],
|
||||
seconds: self.options.seconds
|
||||
})
|
||||
],
|
||||
separators: [
|
||||
{title: '', width: 8}
|
||||
],
|
||||
value: self.options.value
|
||||
})
|
||||
.bindEvent('change', setValue);
|
||||
|
||||
function setValue() {
|
||||
self.options.value = [
|
||||
self.options('inputs')[0].options('value'),
|
||||
self.options('inputs')[1].options('value')
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
404
source/Ox.UI/js/Form/Ox.Filter.js
Normal file
404
source/Ox.UI/js/Form/Ox.Filter.js
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Filter = function(options, self) {
|
||||
|
||||
/***
|
||||
Options:
|
||||
Methods:
|
||||
Events:
|
||||
***/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
findKeys: [],
|
||||
query: {
|
||||
conditions: [],
|
||||
operator: '&'
|
||||
},
|
||||
sortKeys: [],
|
||||
viewKeys: []
|
||||
})
|
||||
.options(options || {});
|
||||
|
||||
Ox.print('Ox.Filter self.options', self.options)
|
||||
|
||||
$.extend(self, {
|
||||
conditionOperators: {
|
||||
date: [
|
||||
{id: '', title: 'is'},
|
||||
{id: '!', title: 'is not'},
|
||||
{id: '<', title: 'is before'},
|
||||
{id: '>', title: 'is after'},
|
||||
{id: '>&<', title: 'is between'},
|
||||
{id: '<|>', title: 'is not between'}
|
||||
],
|
||||
list: [
|
||||
{id: '', title: 'is'},
|
||||
{id: '!', title: 'is not'}
|
||||
],
|
||||
number: [
|
||||
{id: '', title: 'is'},
|
||||
{id: '!', title: 'is not'},
|
||||
{id: '<', title: 'is less than'},
|
||||
{id: '>', title: 'is greater than'},
|
||||
{id: '>&<', title: 'is between'},
|
||||
{id: '<|>', title: 'is not between'}
|
||||
],
|
||||
string: [
|
||||
{id: '=', title: 'is'},
|
||||
{id: '!=', title: 'is not'},
|
||||
{id: '^', title: 'begins with'},
|
||||
{id: '$', title: 'ends with'},
|
||||
{id: '', title: 'contains'},
|
||||
{id: '!', title: 'does not contain'}
|
||||
],
|
||||
text: [
|
||||
{id: '', title: 'contains'},
|
||||
{id: '!', title: 'does not contain'}
|
||||
]
|
||||
},
|
||||
operators: [
|
||||
{id: '&', title: 'all'},
|
||||
{id: '|', title: 'any'}
|
||||
]
|
||||
});
|
||||
|
||||
if (!self.options.query.conditions.length) {
|
||||
self.options.query.conditions = [{
|
||||
key: self.options.findKeys[0].id,
|
||||
value: '',
|
||||
operator: self.conditionOperators[
|
||||
getConditionType(self.options.findKeys[0].type)
|
||||
][0].id
|
||||
}];
|
||||
}
|
||||
|
||||
self.$operator = new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Label({
|
||||
title: 'Match',
|
||||
overlap: 'right',
|
||||
width: 48
|
||||
}),
|
||||
new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Select({
|
||||
items: self.operators,
|
||||
width: 48
|
||||
})
|
||||
.bindEvent({
|
||||
change: changeOperator
|
||||
}),
|
||||
new Ox.Label({
|
||||
overlap: 'left',
|
||||
title: 'of the following conditions',
|
||||
width: 160
|
||||
})
|
||||
],
|
||||
float: 'right',
|
||||
width: 208
|
||||
})
|
||||
],
|
||||
float: 'left',
|
||||
});
|
||||
|
||||
self.$buttons = [];
|
||||
self.$conditions = $.map(self.options.query.conditions, function(condition, i) {
|
||||
return constructCondition(condition, i);
|
||||
});
|
||||
|
||||
self.$limit = new Ox.InputGroup({
|
||||
inputs: [
|
||||
new Ox.Checkbox({
|
||||
width: 16
|
||||
}),
|
||||
new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Input({
|
||||
width: 56
|
||||
}),
|
||||
new Ox.Select({
|
||||
items: [
|
||||
{id: 'items', title: 'items'},
|
||||
{},
|
||||
{id: 'hours', title: 'hours'},
|
||||
{id: 'days', title: 'days'},
|
||||
{},
|
||||
{id: 'GB', title: 'GB'}
|
||||
],
|
||||
overlap: 'left',
|
||||
width: 64
|
||||
})
|
||||
],
|
||||
float: 'right',
|
||||
width: 120
|
||||
}),
|
||||
new Ox.Select({
|
||||
items: self.options.sortKeys,
|
||||
width: 128
|
||||
}),
|
||||
new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Select({
|
||||
items: [
|
||||
{id: 'ascending', title: 'ascending'},
|
||||
{id: 'descending', title: 'descending'}
|
||||
],
|
||||
width: 96
|
||||
}),
|
||||
new Ox.Label({
|
||||
overlap: 'left',
|
||||
title: 'order',
|
||||
width: 72
|
||||
})
|
||||
],
|
||||
float: 'right',
|
||||
width: 168
|
||||
})
|
||||
],
|
||||
separators: [
|
||||
{title: 'Limit to', width: 56},
|
||||
{title: 'sorted by', width: 64},
|
||||
{title: 'in', width: 32}
|
||||
]
|
||||
});
|
||||
|
||||
self.$view = new Ox.InputGroup({
|
||||
inputs: [
|
||||
new Ox.Checkbox({
|
||||
width: 16
|
||||
}),
|
||||
new Ox.Select({
|
||||
items: self.options.viewKeys,
|
||||
width: 128
|
||||
})
|
||||
],
|
||||
separators: [
|
||||
{title: 'By default, view', width: 112}
|
||||
]
|
||||
});
|
||||
|
||||
self.$save = new Ox.InputGroup({
|
||||
inputs: [
|
||||
new Ox.Checkbox({
|
||||
width: 16
|
||||
}),
|
||||
new Ox.Input({
|
||||
id: 'list',
|
||||
width: 128
|
||||
})
|
||||
],
|
||||
separators: [
|
||||
{title: 'Save as Smart List', width: 112}
|
||||
]
|
||||
});
|
||||
|
||||
self.$items = $.merge($.merge([self.$operator], self.$conditions), [self.$limit, self.$view, self.$save]);
|
||||
|
||||
self.$form = new Ox.Form({
|
||||
items: self.$items
|
||||
});
|
||||
that.$element = self.$form.$element;
|
||||
|
||||
function addCondition(pos) {
|
||||
var key = self.options.findKeys[0];
|
||||
self.options.query.conditions.splice(pos, 0, {
|
||||
key: key.id,
|
||||
value: '',
|
||||
operator: self.conditionOperators[key.type][0].id
|
||||
});
|
||||
self.$conditions.splice(pos, 0, constructCondition({}, pos));
|
||||
updateConditions();
|
||||
self.$form.addItem(pos + 1, self.$conditions[pos]);
|
||||
}
|
||||
|
||||
function addGroup(pos) {
|
||||
self.$form.addItem(pos + 1, constructGroup(pos))
|
||||
}
|
||||
|
||||
function changeConditionKey(pos, key) {
|
||||
Ox.print('changeConditionKey', pos, key);
|
||||
var oldOperator = self.options.query.conditions[pos].operator,
|
||||
oldType = Ox.getObjectById(
|
||||
self.options.findKeys, self.options.query.conditions[pos].key
|
||||
).type,
|
||||
newType = Ox.getObjectById(
|
||||
self.options.findKeys, key
|
||||
).type,
|
||||
oldConditionType = getConditionType(oldType),
|
||||
newConditionType = getConditionType(newType);
|
||||
changeConditionType = oldConditionType != newConditionType;
|
||||
Ox.print('old new', oldConditionType, newConditionType)
|
||||
self.options.query.conditions[pos].key = key;
|
||||
if (changeConditionType) {
|
||||
self.$conditions[pos].replaceElement(1, constructConditionOperator(pos, oldOperator));
|
||||
}
|
||||
}
|
||||
|
||||
function changeConditionOperator(pos, operator) {
|
||||
self.options.query.conditions[pos].operator = operator;
|
||||
}
|
||||
|
||||
function changeOperator(event, data) {
|
||||
self.options.query.operator = data.selected[0].id;
|
||||
}
|
||||
|
||||
function constructCondition(condition, pos) {
|
||||
var $condition;
|
||||
return $condition = new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Select({
|
||||
items: $.map(self.options.findKeys, function(key) {
|
||||
return {
|
||||
id: key.id,
|
||||
title: key.title
|
||||
};
|
||||
}),
|
||||
//items: $.extend({}, self.options.findKeys), // fixme: Ox.Menu messes with keys
|
||||
overlap: 'right',
|
||||
width: 128
|
||||
})
|
||||
.bindEvent({
|
||||
change: function(event, data) {
|
||||
Ox.print('event', event)
|
||||
changeConditionKey($condition.data('position'), data.selected[0].id);
|
||||
}
|
||||
}),
|
||||
constructConditionOperator(pos),
|
||||
new Ox.Input({
|
||||
width: 256
|
||||
}),
|
||||
new Ox.Button({
|
||||
disabled: self.options.query.conditions.length == 1,
|
||||
id: 'remove',
|
||||
title: 'remove',
|
||||
type: 'image'
|
||||
})
|
||||
.css({margin: '0 4px 0 8px'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
removeCondition($condition.data('position'));
|
||||
}
|
||||
}),
|
||||
new Ox.Button({
|
||||
id: 'add',
|
||||
title: 'add',
|
||||
type: 'image'
|
||||
})
|
||||
.css({margin: '0 4px 0 4px'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
Ox.print('add', $(this).parent().parent().data('position'))
|
||||
addCondition($condition.data('position') + 1)
|
||||
}
|
||||
}),
|
||||
new Ox.Button({
|
||||
id: 'addgroup',
|
||||
title: 'more',
|
||||
type: 'image'
|
||||
})
|
||||
.css({margin: '0 0 0 4px'})
|
||||
.bindEvent({
|
||||
click: function() {
|
||||
addGroup($condition.data('position') + 1)
|
||||
}
|
||||
})
|
||||
]
|
||||
})
|
||||
.data({position: pos});
|
||||
}
|
||||
|
||||
function constructConditionOperator(pos, selected) {
|
||||
return new Ox.Select({
|
||||
items: $.map(self.conditionOperators[getConditionType(
|
||||
Ox.getObjectById(
|
||||
self.options.findKeys,
|
||||
self.options.query.conditions[pos].key
|
||||
).type
|
||||
)], function(operator) {
|
||||
return {
|
||||
checked: operator.id == selected, // fixme: should be "selected", not "checked"
|
||||
id: operator.operator,
|
||||
title: operator.title
|
||||
};
|
||||
}),
|
||||
overlap: 'right',
|
||||
width: 128
|
||||
})
|
||||
.bindEvent({
|
||||
change: function(event, data) {
|
||||
changeConditionOperator(/*$condition.data('position')*/ pos, data.selected[0].id)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function constructGroup() {
|
||||
// fixme: duplicated
|
||||
return new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Label({
|
||||
title: self.options.operator == '&' ? 'and' : 'or',
|
||||
overlap: 'right',
|
||||
width: 48
|
||||
}),
|
||||
new Ox.FormElementGroup({
|
||||
elements: [
|
||||
new Ox.Select({
|
||||
items: $.map(self.operators, function(operator) {
|
||||
Ox.print('!!!!', {
|
||||
checked: operator.id != self.options.operator,
|
||||
id: operator.id,
|
||||
title: operator.title
|
||||
});
|
||||
return {
|
||||
//checked: operator.id != self.options.operator,
|
||||
id: operator.id,
|
||||
title: operator.title
|
||||
}
|
||||
}),
|
||||
width: 48
|
||||
})
|
||||
.bindEvent({
|
||||
change: changeOperator
|
||||
}),
|
||||
new Ox.Label({
|
||||
overlap: 'left',
|
||||
title: 'of the following conditions',
|
||||
width: 160
|
||||
})
|
||||
],
|
||||
float: 'right',
|
||||
width: 208
|
||||
})
|
||||
],
|
||||
float: 'left',
|
||||
});
|
||||
}
|
||||
|
||||
function getConditionType(type) {
|
||||
type = Ox.isArray(type) ? type[0] : type;
|
||||
if (['float', 'integer', 'year'].indexOf(type) > -1) {
|
||||
type = 'number';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function removeCondition(pos) {
|
||||
self.options.query.conditions.splice(pos, 1);
|
||||
self.$conditions.splice(pos, 1);
|
||||
updateConditions();
|
||||
self.$form.removeItem(pos + 1);
|
||||
}
|
||||
|
||||
function updateConditions() {
|
||||
self.$conditions.forEach(function(condition, pos) {
|
||||
condition.data({position: pos});
|
||||
});
|
||||
self.$conditions[0].options('elements')[3].options({
|
||||
disabled: self.options.query.conditions.length == 1
|
||||
});
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
122
source/Ox.UI/js/Form/Ox.Form.js
Normal file
122
source/Ox.UI/js/Form/Ox.Form.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Form = function(options, self) {
|
||||
|
||||
/**
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
error: '',
|
||||
id: '',
|
||||
items: [],
|
||||
submit: null
|
||||
})
|
||||
.options(options || {}) // fixme: the || {} can be done once, in the options function
|
||||
.addClass('OxForm');
|
||||
|
||||
$.extend(self, {
|
||||
$items: [],
|
||||
$messages: [],
|
||||
formIsValid: false,
|
||||
itemIds: [],
|
||||
itemIsValid: []
|
||||
});
|
||||
|
||||
// fixme: form isn't necessarily empty/invalid
|
||||
self.options.items.forEach(function(item, i) {
|
||||
self.itemIds[i] = item.options('id') || item.id;
|
||||
self.itemIsValid[i] = !!item.value().length;
|
||||
that.append(self.$items[i] = new Ox.FormItem({element: item}));
|
||||
item.bindEvent({
|
||||
/*
|
||||
blur: function(event, data) {
|
||||
validate(i, data.valid);
|
||||
if (data.valid) {
|
||||
self.$messages[i].html('').hide();
|
||||
} else {
|
||||
self.$messages[i].html(data.message).show();
|
||||
}
|
||||
},
|
||||
*/
|
||||
autovalidate: function(event, data) {
|
||||
data.valid = !!data.value.length;
|
||||
validate(i, data.valid);
|
||||
data.valid && self.$items[i].setMessage('');
|
||||
},
|
||||
submit: function(event, data) {
|
||||
self.formIsValid && that.submit();
|
||||
},
|
||||
validate: function(event, data) {
|
||||
validate(i, data.valid);
|
||||
self.$items[i].setMessage(data.valid ? '' : data.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function getItemPositionById(id) {
|
||||
return self.itemIds.indexOf(id);
|
||||
}
|
||||
|
||||
function submitCallback(data) {
|
||||
data.forEach(function(v, i) {
|
||||
self.$items[i].setMessage(v.message);
|
||||
});
|
||||
}
|
||||
|
||||
function validate(pos, valid) {
|
||||
//Ox.print('FORM validate', pos, valid)
|
||||
self.itemIsValid[pos] = valid;
|
||||
if (Ox.every(self.itemIsValid) != self.formIsValid) {
|
||||
self.formIsValid = !self.formIsValid;
|
||||
that.triggerEvent('validate', {
|
||||
valid: self.formIsValid
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
that.addItem = function(pos, item) {
|
||||
Ox.print('addItem', pos)
|
||||
self.options.items.splice(pos, 0, item);
|
||||
self.$items.splice(pos, 0, new Ox.FormItem({element: item}));
|
||||
pos == 0 ?
|
||||
self.$items[pos].insertBefore(self.$items[0]) :
|
||||
self.$items[pos].insertAfter(self.$items[pos - 1]);
|
||||
}
|
||||
|
||||
that.removeItem = function(pos) {
|
||||
Ox.print('removeItem', pos);
|
||||
self.$items[pos].removeElement();
|
||||
self.options.items.splice(pos, 1);
|
||||
self.$items.splice(pos, 1);
|
||||
}
|
||||
|
||||
that.submit = function() {
|
||||
//Ox.print('---- that.values()', that.values())
|
||||
self.options.submit(that.values(), submitCallback);
|
||||
};
|
||||
|
||||
that.values = function() { // fixme: can this be private?
|
||||
/*
|
||||
get/set form values
|
||||
call without arguments to get current form values
|
||||
pass values as array to set values (not implemented)
|
||||
*/
|
||||
var values = {};
|
||||
if (arguments.length == 0) {
|
||||
self.$items.forEach(function($item, i) {
|
||||
values[self.itemIds[i]] = self.$items[i].value();
|
||||
});
|
||||
//Ox.print('VALUES', values)
|
||||
return values;
|
||||
} else {
|
||||
Ox.each(arguments[0], function(val, key) {
|
||||
|
||||
});
|
||||
return that;
|
||||
}
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
74
source/Ox.UI/js/Form/Ox.FormElementGroup.js
Normal file
74
source/Ox.UI/js/Form/Ox.FormElementGroup.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.FormElementGroup = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
id: '',
|
||||
elements: [],
|
||||
float: 'left',
|
||||
separators: [],
|
||||
width: 0
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxInputGroup');
|
||||
|
||||
(
|
||||
self.options.float == 'left' ?
|
||||
self.options.elements : self.options.elements.reverse()
|
||||
).forEach(function($element, i) {
|
||||
$element.css({
|
||||
float: self.options.float // fixme: make this a class
|
||||
})
|
||||
.bindEvent({
|
||||
validate: function(event, data) {
|
||||
that.triggerEvent({
|
||||
validate: data
|
||||
});
|
||||
}
|
||||
})
|
||||
.appendTo(that);
|
||||
});
|
||||
|
||||
/*
|
||||
if (self.options.width) {
|
||||
setWidths();
|
||||
} else {
|
||||
self.options.width = getWidth();
|
||||
}
|
||||
that.css({
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
*/
|
||||
|
||||
function getWidth() {
|
||||
|
||||
}
|
||||
|
||||
function setWidth() {
|
||||
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
|
||||
};
|
||||
|
||||
that.replaceElement = function(pos, element) {
|
||||
Ox.print('Ox.FormElementGroup replaceElement', pos, element)
|
||||
self.options.elements[pos].replaceWith(element.$element);
|
||||
self.options.elements[pos] = element;
|
||||
};
|
||||
|
||||
that.value = function() {
|
||||
return $.map(self.options.elements, function(element) {
|
||||
var ret = null;
|
||||
['checked', 'selected', 'value'].forEach(function(v) {
|
||||
element[v] && (ret = element[v]());
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
28
source/Ox.UI/js/Form/Ox.FormItem.js
Normal file
28
source/Ox.UI/js/Form/Ox.FormItem.js
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.FormItem = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
element: null,
|
||||
error: '',
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxFormItem')
|
||||
.append(self.options.element);
|
||||
|
||||
self.$message = new Ox.Element()
|
||||
.addClass('OxFormMessage')
|
||||
.appendTo(that);
|
||||
|
||||
that.setMessage = function(message) {
|
||||
self.$message.html(message)[message !== '' ? 'show' : 'hide']();
|
||||
}
|
||||
|
||||
that.value = function() {
|
||||
return self.options.element.value();
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
}
|
||||
1764
source/Ox.UI/js/Form/Ox.Input.js
Normal file
1764
source/Ox.UI/js/Form/Ox.Input.js
Normal file
File diff suppressed because it is too large
Load diff
134
source/Ox.UI/js/Form/Ox.InputGroup.js
Normal file
134
source/Ox.UI/js/Form/Ox.InputGroup.js
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.InputGroup = function(options, self) {
|
||||
|
||||
/***
|
||||
Ox.InputGroup
|
||||
Options:
|
||||
Methods:
|
||||
Events:
|
||||
***/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
id: '',
|
||||
inputs: [],
|
||||
separators: [],
|
||||
width: 0
|
||||
})
|
||||
.options(options || {})
|
||||
.addClass('OxInputGroup')
|
||||
.click(click);
|
||||
|
||||
if (self.options.width) {
|
||||
setWidths();
|
||||
} else {
|
||||
self.options.width = getWidth();
|
||||
}
|
||||
that.css({
|
||||
width: self.options.width + 'px'
|
||||
});
|
||||
|
||||
$.extend(self, {
|
||||
//$input: [],
|
||||
$separator: []
|
||||
});
|
||||
|
||||
self.options.separators.forEach(function(v, i) {
|
||||
self.options.id == 'debug' && Ox.print('separator #' + i + ' ' + self.options.inputs[i].options('id') + ' ' + self.options.inputs[i].options('width'))
|
||||
self.$separator[i] = new Ox.Label({
|
||||
textAlign: 'center',
|
||||
title: v.title,
|
||||
width: v.width + 32
|
||||
})
|
||||
.addClass('OxSeparator')
|
||||
.css({
|
||||
marginLeft: (self.options.inputs[i].options('width') - (i == 0 ? 16 : 32)) + 'px'
|
||||
})
|
||||
.appendTo(that);
|
||||
});
|
||||
|
||||
self.options.inputs.forEach(function($input, i) {
|
||||
$input.options({
|
||||
id: self.options.id + Ox.toTitleCase($input.options('id')),
|
||||
parent: that
|
||||
})
|
||||
.css({
|
||||
marginLeft: -Ox.sum($.map(self.options.inputs, function(v_, i_) {
|
||||
return i_ > i ? self.options.inputs[i_ - 1].options('width') +
|
||||
self.options.separators[i_ - 1].width : (i_ == i ? 16 : 0);
|
||||
})) + 'px'
|
||||
})
|
||||
.bindEvent({
|
||||
change: change,
|
||||
submit: change,
|
||||
validate: validate
|
||||
})
|
||||
.appendTo(that);
|
||||
});
|
||||
|
||||
function change(event, data) {
|
||||
//Ox.print('InputGroup change')
|
||||
// fixme: would be good to pass a value here
|
||||
that.triggerEvent('change');
|
||||
}
|
||||
|
||||
function click(event) {
|
||||
if ($(event.target).hasClass('OxSeparator')) {
|
||||
self.options.inputs[0].focusInput();
|
||||
}
|
||||
}
|
||||
|
||||
function getWidth() {
|
||||
return Ox.sum($.map(self.options.inputs, function(v, i) {
|
||||
return v.options('width');
|
||||
})) + Ox.sum($.map(self.options.separators, function(v, i) {
|
||||
return v.width;
|
||||
})) + 2; // fixme: why + 2?
|
||||
}
|
||||
|
||||
function setWidths() {
|
||||
var length = self.options.inputs.length,
|
||||
inputWidths = Ox.divideInt(
|
||||
self.options.width - Ox.sum($.map(self.options.separators, function(v, i) {
|
||||
return v.width;
|
||||
})), length
|
||||
);
|
||||
self.options.inputs.forEach(function(v) {
|
||||
v.options({
|
||||
width: inputWidths[1]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function validate(event, data) {
|
||||
//Ox.print('INPUTGROUP TRIGGER VALIDATE')
|
||||
that.triggerEvent('validate', data);
|
||||
}
|
||||
|
||||
// fixme: is this used?
|
||||
that.getInputById = function(id) {
|
||||
var input = null;
|
||||
Ox.forEach(self.options.inputs, function(v, i) {
|
||||
//Ox.print(v, v.options('id'), id)
|
||||
if (v.options('id') == self.options.id + Ox.toTitleCase(id)) {
|
||||
input = v;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return input;
|
||||
};
|
||||
|
||||
that.value = function() {
|
||||
return $.map(self.options.inputs, function(input) {
|
||||
var ret = null;
|
||||
['checked', 'selected', 'value'].forEach(function(v) {
|
||||
input[v] && (ret = input[v]());
|
||||
});
|
||||
return ret;
|
||||
});
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
35
source/Ox.UI/js/Form/Ox.Label.js
Normal file
35
source/Ox.UI/js/Form/Ox.Label.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Label = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
disabled: false,
|
||||
id: '',
|
||||
overlap: 'none',
|
||||
textAlign: 'left',
|
||||
title: '',
|
||||
width: 'auto'
|
||||
})
|
||||
.options(options)
|
||||
.addClass(
|
||||
'OxLabel' + (self.options.disabled ? ' OxDisabled' : '') +
|
||||
(self.options.overlap != 'none' ?
|
||||
' OxOverlap' + Ox.toTitleCase(self.options.overlap) : '')
|
||||
)
|
||||
.css($.extend(self.options.width == 'auto' ? {} : {
|
||||
width: (self.options.width - 14) + 'px'
|
||||
}, {
|
||||
textAlign: self.options.textAlign
|
||||
}))
|
||||
.html(self.options.title);
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
if (key == 'title') {
|
||||
that.html(value);
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
104
source/Ox.UI/js/Form/Ox.OptionGroup.js
Normal file
104
source/Ox.UI/js/Form/Ox.OptionGroup.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.OptionGroup = function(items, min, max, property) {
|
||||
|
||||
/*
|
||||
to be used by ButtonGroup, CheckboxGroup, Select and Menu
|
||||
*/
|
||||
|
||||
var property = property || 'checked'
|
||||
length = items.length,
|
||||
max = max == -1 ? length : max;
|
||||
|
||||
function getLastBefore(pos) {
|
||||
// returns the position of the last checked item before position pos
|
||||
var last = -1;
|
||||
/*Ox.print(items, items.length, length, $.merge(
|
||||
pos > 0 ? Ox.range(pos - 1, -1, -1) : [],
|
||||
pos < items.length - 1 ? Ox.range(items.length - 1, pos, -1) : []
|
||||
))*/
|
||||
// fixme: why is length not == items.length here?
|
||||
Ox.forEach($.merge(
|
||||
pos > 0 ? Ox.range(pos - 1, -1, -1) : [],
|
||||
pos < items.length - 1 ? Ox.range(items.length - 1, pos, -1) : []
|
||||
), function(v) {
|
||||
//Ox.print(pos, v)
|
||||
if (items[v][property]) {
|
||||
last = v;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return last;
|
||||
}
|
||||
|
||||
function getNumber() {
|
||||
// returns the number of checked items
|
||||
var num = 0;
|
||||
items.forEach(function(item) {
|
||||
if (item[property]) {
|
||||
num++;
|
||||
}
|
||||
})
|
||||
return num;
|
||||
}
|
||||
|
||||
this[property] = function() {
|
||||
// returns an array with the positions of all checked item
|
||||
var checked = [];
|
||||
items.forEach(function(item, i) {
|
||||
if (item[property]) {
|
||||
checked.push(i);
|
||||
}
|
||||
})
|
||||
return checked;
|
||||
};
|
||||
|
||||
this.init = function() {
|
||||
var num = getNumber(),
|
||||
count = 0;
|
||||
//if (num < min || num > max) {
|
||||
items.forEach(function(item) {
|
||||
if (Ox.isUndefined(item[property])) {
|
||||
item[property] = false;
|
||||
}
|
||||
if (item[property]) {
|
||||
count++;
|
||||
if (count > max) {
|
||||
item[property] = false;
|
||||
}
|
||||
} else {
|
||||
if (num < min) {
|
||||
item[property] = true;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
});
|
||||
//}
|
||||
return items;
|
||||
};
|
||||
|
||||
this.toggle = function(pos) {
|
||||
var last,
|
||||
num = getNumber(),
|
||||
toggled = [];
|
||||
if (!items[pos][property]) { // check
|
||||
if (num >= max) {
|
||||
last = getLastBefore(pos);
|
||||
items[last][property] = false;
|
||||
toggled.push(last);
|
||||
}
|
||||
if (!items[pos][property]) {
|
||||
items[pos][property] = true;
|
||||
toggled.push(pos);
|
||||
}
|
||||
} else { // uncheck
|
||||
if (num > min) {
|
||||
items[pos][property] = false;
|
||||
toggled.push(pos);
|
||||
}
|
||||
}
|
||||
return toggled;
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
93
source/Ox.UI/js/Form/Ox.Picker.js
Normal file
93
source/Ox.UI/js/Form/Ox.Picker.js
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Picker = function(options, self) {
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self)
|
||||
.defaults({
|
||||
element: null,
|
||||
elementHeight: 128,
|
||||
elementWidth: 256,
|
||||
id: '',
|
||||
overlap: 'none'
|
||||
})
|
||||
.options(options || {});
|
||||
|
||||
self.$selectButton = new Ox.Button({
|
||||
overlap: self.options.overlap,
|
||||
title: 'select',
|
||||
type: 'image'
|
||||
})
|
||||
.click(showMenu)
|
||||
.appendTo(that);
|
||||
|
||||
self.$menu = new Ox.Element('div')
|
||||
.addClass('OxPicker')
|
||||
.css({
|
||||
width: self.options.elementWidth + 'px',
|
||||
height: (self.options.elementHeight + 24) + 'px'
|
||||
});
|
||||
|
||||
self.options.element
|
||||
.css({
|
||||
width: self.options.elementWidth + 'px',
|
||||
height: self.options.elementHeight + 'px'
|
||||
})
|
||||
.appendTo(self.$menu);
|
||||
|
||||
self.$bar = new Ox.Bar({
|
||||
orientation: 'horizontal',
|
||||
size: 24
|
||||
})
|
||||
.appendTo(self.$menu);
|
||||
|
||||
that.$label = new Ox.Label({
|
||||
width: self.options.elementWidth - 60
|
||||
})
|
||||
.appendTo(self.$bar);
|
||||
|
||||
self.$doneButton = new Ox.Button({
|
||||
title: 'Done',
|
||||
width: 48
|
||||
})
|
||||
.click(hideMenu)
|
||||
.appendTo(self.$bar);
|
||||
|
||||
self.$layer = $('<div>')
|
||||
.addClass('OxLayer')
|
||||
.click(hideMenu);
|
||||
|
||||
function hideMenu() {
|
||||
self.$menu.detach();
|
||||
self.$layer.detach();
|
||||
self.$selectButton
|
||||
.removeClass('OxSelected')
|
||||
.css({
|
||||
MozBorderRadius: '8px',
|
||||
WebkitBorderRadius: '8px'
|
||||
});
|
||||
that.triggerEvent('hide');
|
||||
};
|
||||
|
||||
function showMenu() {
|
||||
var offset = that.offset(),
|
||||
left = offset.left,
|
||||
top = offset.top + 15;
|
||||
self.$selectButton
|
||||
.addClass('OxSelected')
|
||||
.css({
|
||||
MozBorderRadius: '8px 8px 0 0',
|
||||
WebkitBorderRadius: '8px 8px 0 0'
|
||||
});
|
||||
self.$layer.appendTo(Ox.UI.$body);
|
||||
self.$menu
|
||||
.css({
|
||||
left: left + 'px',
|
||||
top: top + 'px'
|
||||
})
|
||||
.appendTo(Ox.UI.$body);
|
||||
that.triggerEvent('show');
|
||||
};
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
35
source/Ox.UI/js/Form/Ox.PlaceInput.js
Normal file
35
source/Ox.UI/js/Form/Ox.PlaceInput.js
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.PlaceInput = function(options, self) {
|
||||
|
||||
var self = $.extend(self || {}, {
|
||||
options: $.extend({
|
||||
id: '',
|
||||
value: 'United States'
|
||||
}, options)
|
||||
}),
|
||||
that;
|
||||
|
||||
that = new Ox.FormElementGroup({
|
||||
id: self.options.id,
|
||||
elements: [
|
||||
new Ox.Input({
|
||||
id: 'input',
|
||||
value: self.options.value
|
||||
}),
|
||||
new Ox.PlacePicker({
|
||||
id: 'picker',
|
||||
overlap: 'left',
|
||||
value: self.options.value
|
||||
})
|
||||
],
|
||||
float: 'right'
|
||||
}, self)
|
||||
.bindEvent('change', change);
|
||||
|
||||
function change() {
|
||||
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
143
source/Ox.UI/js/Form/Ox.PlacePicker.js
Normal file
143
source/Ox.UI/js/Form/Ox.PlacePicker.js
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.PlacePicker = function(options, self) {
|
||||
|
||||
var self = $.extend(self || {}, {
|
||||
options: $.extend({
|
||||
id: '',
|
||||
value: 'United States'
|
||||
}, options)
|
||||
}),
|
||||
that;
|
||||
|
||||
self.$element = new Ox.Element('div')
|
||||
.css({
|
||||
width: '256px',
|
||||
height: '192px'
|
||||
})
|
||||
.append(
|
||||
self.$topBar = new Ox.Bar({
|
||||
size: 16
|
||||
})
|
||||
.css({
|
||||
MozBorderRadius: '0 8px 0 0',
|
||||
WebkitBorderRadius: '0 8px 0 0'
|
||||
})
|
||||
.append(
|
||||
self.$input = new Ox.Input({
|
||||
clear: true,
|
||||
id: self.options.id + 'Input',
|
||||
placeholder: 'Find',
|
||||
width: 256
|
||||
})
|
||||
.bindEvent('submit', findPlace)
|
||||
)
|
||||
)
|
||||
.append(
|
||||
self.$container = new Ox.Element('div')
|
||||
.css({
|
||||
width: '256px',
|
||||
height: '160px'
|
||||
})
|
||||
)
|
||||
.append(
|
||||
self.$bottomBar = new Ox.Bar({
|
||||
size: 16
|
||||
})
|
||||
.append(
|
||||
self.$range = new Ox.Range({
|
||||
arrows: true,
|
||||
id: self.options.id + 'Range',
|
||||
max: 22,
|
||||
size: 256,
|
||||
thumbSize: 32,
|
||||
thumbValue: true
|
||||
})
|
||||
.bindEvent('change', changeZoom)
|
||||
)
|
||||
);
|
||||
|
||||
self.$input.$element.children('input[type=text]').css({
|
||||
width: '230px',
|
||||
paddingLeft: '2px',
|
||||
MozBorderRadius: '0 8px 8px 0',
|
||||
WebkitBorderRadius: '0 8px 8px 0'
|
||||
});
|
||||
self.$input.$element.children('input[type=image]').css({
|
||||
MozBorderRadius: '0 8px 0 0',
|
||||
WebkitBorderRadius: '0 8px 0 0'
|
||||
});
|
||||
self.$range.$element.children('input').css({
|
||||
MozBorderRadius: 0,
|
||||
WebkitBorderRadius: 0
|
||||
});
|
||||
|
||||
that = new Ox.Picker({
|
||||
element: self.$element,
|
||||
elementHeight: 192,
|
||||
elementWidth: 256,
|
||||
id: self.options.id,
|
||||
overlap: self.options.overlap,
|
||||
value: self.options.value
|
||||
}, self)
|
||||
.bindEvent('show', showPicker);
|
||||
|
||||
that.$label.bind('click', clickLabel)
|
||||
|
||||
self.map = false;
|
||||
|
||||
function changeZoom(event, data) {
|
||||
//Ox.print('changeZoom')
|
||||
self.$map.zoom(data.value);
|
||||
}
|
||||
|
||||
function clickLabel() {
|
||||
var name = that.$label.html();
|
||||
if (name) {
|
||||
self.$input.options({
|
||||
value: name
|
||||
})
|
||||
.triggerEvent('submit', {
|
||||
value: name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function findPlace(event, data) {
|
||||
//Ox.print('findPlace', data);
|
||||
self.$map.find(data.value, function(place) {
|
||||
place && that.$label.html(place.geoname);
|
||||
})
|
||||
}
|
||||
|
||||
function onSelect(event, data) {
|
||||
that.$label.html(data.geoname);
|
||||
}
|
||||
|
||||
function onZoom(event, data) {
|
||||
self.$range.options({
|
||||
value: data.value
|
||||
});
|
||||
}
|
||||
|
||||
function showPicker() {
|
||||
if (!self.map) {
|
||||
self.$map = new Ox.Map({
|
||||
id: self.options.id + 'Map',
|
||||
places: [self.options.value]
|
||||
})
|
||||
.css({
|
||||
width: '256px',
|
||||
height: '160px'
|
||||
})
|
||||
.bindEvent({
|
||||
select: onSelect,
|
||||
zoom: onZoom
|
||||
})
|
||||
.appendTo(self.$container);
|
||||
self.map = true;
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
249
source/Ox.UI/js/Form/Ox.Range.js
Normal file
249
source/Ox.UI/js/Form/Ox.Range.js
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Range = function(options, self) {
|
||||
|
||||
/**
|
||||
options
|
||||
arrows boolean if true, show arrows
|
||||
arrowStep number step when clicking arrows
|
||||
arrowSymbols array arrow symbols, like ['minus', 'plus']
|
||||
max number maximum value
|
||||
min number minimum value
|
||||
orientation string 'horizontal' or 'vertical'
|
||||
step number step between values
|
||||
size number width or height, in px
|
||||
thumbSize number minimum width or height of thumb, in px
|
||||
thumbValue boolean if true, display value on thumb
|
||||
trackGradient array colors
|
||||
trackImages string or array one or multiple track background image URLs
|
||||
trackStep number 0 (scroll here) or step when clicking track
|
||||
value number initial value
|
||||
valueNames array value names to display on thumb
|
||||
*/
|
||||
|
||||
var self = self || {},
|
||||
that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
arrows: false,
|
||||
arrowStep: 1,
|
||||
arrowSymbols: ['left', 'right'],
|
||||
max: 100,
|
||||
min: 0,
|
||||
orientation: 'horizontal',
|
||||
step: 1,
|
||||
size: 128,
|
||||
thumbSize: 16,
|
||||
thumbValue: false,
|
||||
trackColors: [],
|
||||
trackImages: [],
|
||||
trackStep: 0,
|
||||
value: 0,
|
||||
valueNames: null,
|
||||
})
|
||||
.options($.extend(options, {
|
||||
arrowStep: options.arrowStep ?
|
||||
options.arrowStep : options.step,
|
||||
trackImages: $.makeArray(options.trackImages || [])
|
||||
}))
|
||||
.addClass('OxRange')
|
||||
.css({
|
||||
width: self.options.size + 'px'
|
||||
});
|
||||
|
||||
$.extend(self, {
|
||||
trackColors: self.options.trackColors.length,
|
||||
trackImages: self.options.trackImages.length,
|
||||
values: (self.options.max - self.options.min + self.options.step) /
|
||||
self.options.step
|
||||
});
|
||||
setSizes();
|
||||
|
||||
if (self.options.arrows) {
|
||||
self.$arrows = [];
|
||||
Ox.range(0, 2).forEach(function(i) {
|
||||
self.$arrows[i] = new Ox.Button({
|
||||
overlap: i == 0 ? 'right' : 'left',
|
||||
title: self.options.arrowSymbols[i],
|
||||
type: 'image'
|
||||
})
|
||||
.addClass('OxArrow')
|
||||
.bindEvent({
|
||||
mousedown: function(event, e) {
|
||||
clickArrow(e, i, true);
|
||||
},
|
||||
mouserepeat: function(event, e) {
|
||||
clickArrow(e, i, false);
|
||||
}
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
});
|
||||
}
|
||||
|
||||
self.$track = new Ox.Element()
|
||||
.addClass('OxTrack')
|
||||
.css($.extend({
|
||||
width: (self.trackSize - 2) + 'px'
|
||||
}, self.trackImages == 1 ? {
|
||||
background: 'rgb(0, 0, 0)'
|
||||
} : {}))
|
||||
.bindEvent({
|
||||
mousedown: clickTrack,
|
||||
drag: dragTrack
|
||||
})
|
||||
.appendTo(that.$element);
|
||||
|
||||
self.trackColors && setTrackColors();
|
||||
|
||||
if (self.trackImages) {
|
||||
self.$trackImages = $('<div>')
|
||||
.css({
|
||||
width: self.trackSize + 'px',
|
||||
marginRight: (-self.trackSize - 1) + 'px'
|
||||
})
|
||||
.appendTo(self.$track.$element);
|
||||
self.options.trackImages.forEach(function(v, i) {
|
||||
//Ox.print(self.trackImageWidths[i])
|
||||
$('<img>')
|
||||
.attr({
|
||||
src: v
|
||||
})
|
||||
.addClass(i == 0 ? 'OxFirstChild' : '')
|
||||
.addClass(i == self.trackImages - 1 ? 'OxLastChild' : '')
|
||||
.css({
|
||||
width: self.trackImageWidths[i] + 'px'
|
||||
})
|
||||
.mousedown(function(e) {
|
||||
e.preventDefault(); // prevent drag
|
||||
})
|
||||
.appendTo(self.$trackImages);
|
||||
//left += self.trackImageWidths[i];
|
||||
});
|
||||
}
|
||||
|
||||
self.$thumb = Ox.Button({
|
||||
id: self.options.id + 'Thumb',
|
||||
title: self.options.thumbValue ? (self.options.valueNames ?
|
||||
self.options.valueNames[self.options.value] :
|
||||
self.options.value) : '',
|
||||
width: self.thumbSize
|
||||
})
|
||||
.addClass('OxThumb')
|
||||
/*
|
||||
.css({
|
||||
border: '1px solid rgb(255, 255, 255)',
|
||||
background: 'rgba(0, 0, 0, 0)'
|
||||
})
|
||||
*/
|
||||
.appendTo(self.$track);
|
||||
|
||||
setThumb();
|
||||
|
||||
function clickArrow(e, i, animate) {
|
||||
// fixme: shift doesn't work, see menu scrolling
|
||||
setValue(self.options.value + self.options.arrowStep * (i == 0 ? -1 : 1) * (e.shiftKey ? 2 : 1), animate);
|
||||
}
|
||||
|
||||
function clickTrack(event, e) {
|
||||
// fixme: thumb ends up a bit too far on the right
|
||||
var isThumb = $(e.target).hasClass('OxThumb');
|
||||
self.drag = {
|
||||
left: self.$track.offset().left,
|
||||
offset: isThumb ? e.clientX - self.$thumb.offset().left - 8 /*self.thumbSize / 2*/ : 0
|
||||
};
|
||||
setValue(getVal(e.clientX - self.drag.left - self.drag.offset), !isThumb);
|
||||
}
|
||||
|
||||
function dragTrack(event, e) {
|
||||
setValue(getVal(e.clientX - self.drag.left - self.drag.offset))
|
||||
}
|
||||
|
||||
function getPx(val) {
|
||||
var pxPerVal = (self.trackSize - self.thumbSize) /
|
||||
(self.options.max - self.options.min);
|
||||
return Math.ceil((val - self.options.min) * pxPerVal);
|
||||
}
|
||||
|
||||
/*
|
||||
function getTime(oldValue, newValue) {
|
||||
return self.animationTime * Math.abs(oldValue - newValue) / (self.options.max - self.options.min);
|
||||
}
|
||||
*/
|
||||
|
||||
function getVal(px) {
|
||||
var px = self.trackSize / self.values >= 16 ? px : px - 8,
|
||||
valPerPx = (self.options.max - self.options.min) /
|
||||
(self.trackSize - self.thumbSize);
|
||||
return Ox.limit(self.options.min +
|
||||
Math.floor(px * valPerPx / self.options.step) * self.options.step,
|
||||
self.options.min, self.options.max);
|
||||
}
|
||||
|
||||
function setSizes() {
|
||||
self.trackSize = self.options.size - self.options.arrows * 32;
|
||||
self.thumbSize = Math.max(self.trackSize / self.values, self.options.thumbSize);
|
||||
self.trackImageWidths = self.trackImages == 1 ? [self.trackSize - 16] :
|
||||
Ox.divideInt(self.trackSize - 2, self.trackImages);
|
||||
self.trackColorsStart = self.thumbSize / 2 / self.options.size;
|
||||
self.trackColorsStep = (self.options.size - self.thumbSize) /
|
||||
(self.trackColors - 1) / self.options.size;
|
||||
self.$track && self.$track.css({
|
||||
width: (self.trackSize - 2) + 'px'
|
||||
});
|
||||
self.$thumb && self.$thumb.options({
|
||||
width: self.thumbSize
|
||||
});
|
||||
}
|
||||
|
||||
function setThumb(animate) {
|
||||
self.$thumb.stop().animate({
|
||||
marginLeft: (getPx(self.options.value) - 1) + 'px',
|
||||
//width: self.thumbSize + 'px'
|
||||
}, animate ? 200 : 0, function() {
|
||||
if (self.options.thumbValue) {
|
||||
self.$thumb.options({
|
||||
title: self.options.valueNames ?
|
||||
self.options.valueNames[self.options.value] :
|
||||
self.options.value
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setTrackColors() {
|
||||
self.$track.css({
|
||||
backgroundImage: $.browser.mozilla ?
|
||||
('-moz-linear-gradient(left, ' +
|
||||
self.options.trackColors[0] + ' 0%, ' + $.map(self.options.trackColors, function(v, i) {
|
||||
return v + ' ' + ((self.trackColorsStart + self.trackColorsStep * i) * 100) + '%';
|
||||
}).join(', ') + ', ' + self.options.trackColors[self.trackColors - 1] + ' 100%)') :
|
||||
('-webkit-gradient(linear, left top, right top, color-stop(0, ' +
|
||||
self.options.trackColors[0] + '), ' + $.map(self.options.trackColors, function(v, i) {
|
||||
return 'color-stop(' + (self.trackColorsStart + self.trackColorsStep * i) + ', ' + v + ')';
|
||||
}).join(', ') + ', color-stop(1, ' + self.options.trackColors[self.trackColors - 1] + '))')
|
||||
});
|
||||
}
|
||||
|
||||
function setValue(value, animate) {
|
||||
var value = Ox.limit(value, self.options.min, self.options.max);
|
||||
if (value != self.options.value) {
|
||||
//time = getTime(self.options.value, value);
|
||||
self.options.value = value;
|
||||
setThumb(animate);
|
||||
that.triggerEvent('change', {
|
||||
value: value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
if (key == 'size') {
|
||||
setSizes();
|
||||
} else if (key == 'trackColors') {
|
||||
setTrackColors();
|
||||
} else if (key == 'value') {
|
||||
setThumb();
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
163
source/Ox.UI/js/Form/Ox.Select.js
Normal file
163
source/Ox.UI/js/Form/Ox.Select.js
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.Select = function(options, self) {
|
||||
|
||||
// fixme: selected item needs attribute "checked", not "selected" ... that's strange
|
||||
var self = self || {},
|
||||
that = new Ox.Element('div', self) // fixme: do we use 'div', or {}, or '', by default?
|
||||
.defaults({
|
||||
id: '',
|
||||
items: [],
|
||||
max: 1,
|
||||
min: 1,
|
||||
overlap: 'none', // can be none, left or right
|
||||
selectable: true,
|
||||
size: 'medium',
|
||||
title: '',
|
||||
type: 'text', // can be 'text' or 'image'
|
||||
width: 'auto'
|
||||
})
|
||||
// fixme: make default selection restorable
|
||||
// or allow for extra action items below options
|
||||
.options(options)
|
||||
.addClass(
|
||||
'OxSelect Ox' + Ox.toTitleCase(self.options.size) +
|
||||
(self.options.overlap == 'none' ? '' : ' OxOverlap' +
|
||||
Ox.toTitleCase(self.options.overlap))
|
||||
)
|
||||
.css(self.options.width == 'auto' ? {} : {
|
||||
width: self.options.width + 'px'
|
||||
})
|
||||
.bindEvent({
|
||||
key_escape: loseFocus,
|
||||
key_down: showMenu
|
||||
});
|
||||
|
||||
Ox.print('Ox.Select', self.options)
|
||||
|
||||
$.extend(self, {
|
||||
buttonId: self.options.id + 'Button',
|
||||
groupId: self.options.id + 'Group',
|
||||
menuId: self.options.id + 'Menu'
|
||||
});
|
||||
|
||||
if (self.options.selectable) {
|
||||
self.optionGroup = new Ox.OptionGroup(
|
||||
self.options.items,
|
||||
self.options.min,
|
||||
self.options.max
|
||||
);
|
||||
self.options.items = self.optionGroup.init();
|
||||
self.checked = self.optionGroup.checked();
|
||||
}
|
||||
|
||||
if (self.options.type == 'text') {
|
||||
self.$title = $('<div>')
|
||||
.addClass('OxTitle')
|
||||
.css({
|
||||
width: (self.options.width - 22) + 'px'
|
||||
})
|
||||
.html(
|
||||
self.options.title ? self.options.title :
|
||||
self.options.items[self.checked[0]].title
|
||||
)
|
||||
.click(showMenu)
|
||||
.appendTo(that.$element);
|
||||
}
|
||||
|
||||
self.$button = new Ox.Button({
|
||||
id: self.buttonId,
|
||||
style: 'symbol',
|
||||
title: 'select',
|
||||
type: 'image'
|
||||
})
|
||||
.bindEvent('click', showMenu)
|
||||
.appendTo(that);
|
||||
|
||||
self.$menu = new Ox.Menu({
|
||||
element: self.$title || self.$button,
|
||||
id: self.menuId,
|
||||
items: [self.options.selectable ? {
|
||||
group: self.groupId,
|
||||
items: self.options.items,
|
||||
max: self.options.max,
|
||||
min: self.options.min
|
||||
} : self.options.items],
|
||||
side: 'bottom',
|
||||
size: self.options.size
|
||||
})
|
||||
.bindEvent({
|
||||
change: changeMenu,
|
||||
click: clickMenu,
|
||||
hide: hideMenu
|
||||
});
|
||||
|
||||
self.options.type == 'image' && self.$menu.addClass('OxRight');
|
||||
|
||||
function clickMenu(event, data) {
|
||||
that.triggerEvent('click', data);
|
||||
}
|
||||
|
||||
function changeMenu(event, data) {
|
||||
//Ox.print('clickMenu: ', self.options.id, data)
|
||||
self.checked = self.optionGroup.checked();
|
||||
self.$title && self.$title.html(
|
||||
self.options.title ? self.options.title :
|
||||
data.checked[0].title
|
||||
);
|
||||
that.triggerEvent('change', {
|
||||
selected: data.checked
|
||||
});
|
||||
}
|
||||
|
||||
function hideMenu() {
|
||||
//Ox.print('%% hideMenu that', that, 'self', self)
|
||||
that.removeClass('OxSelected');
|
||||
// self.$button.removeClass('OxSelected');
|
||||
//Ox.print('%% hideMenu end')
|
||||
}
|
||||
|
||||
function loseFocus() {
|
||||
that.loseFocus();
|
||||
}
|
||||
|
||||
function showMenu() {
|
||||
that.gainFocus();
|
||||
that.addClass('OxSelected');
|
||||
self.$menu.showMenu();
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
|
||||
};
|
||||
|
||||
that.selected = function() {
|
||||
return $.map(/*self.checked*/self.optionGroup.checked(), function(v) {
|
||||
return {
|
||||
id: self.options.items[v].id,
|
||||
title: self.options.items[v].title
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
that.selectItem = function(id) {
|
||||
//Ox.print('selectItem', id, Ox.getObjectById(self.options.items, id).title)
|
||||
self.options.type == 'text' && self.$title.html(
|
||||
Ox.getObjectById(self.options.items, id).title[0] // fixme: title should not have become an array
|
||||
);
|
||||
self.$menu.checkItem(id);
|
||||
self.checked = self.optionGroup.checked();
|
||||
};
|
||||
|
||||
/*
|
||||
that.width = function(val) {
|
||||
// fixme: silly hack, and won't work for css() ... remove!
|
||||
that.$element.width(val + 16);
|
||||
that.$button.width(val);
|
||||
//that.$symbol.width(val);
|
||||
return that;
|
||||
};
|
||||
*/
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
153
source/Ox.UI/js/Form/Ox.TimeInput.js
Normal file
153
source/Ox.UI/js/Form/Ox.TimeInput.js
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// vim: et:ts=4:sw=4:sts=4:ft=js
|
||||
Ox.TimeInput = function(options, self) {
|
||||
|
||||
// fixme: seconds get set even if options.seconds is false
|
||||
var self = self || {},
|
||||
that = new Ox.Element({}, self)
|
||||
.defaults({
|
||||
ampm: false,
|
||||
seconds: false,
|
||||
milliseconds: false,
|
||||
value: Ox.formatDate(new Date(), '%T'),
|
||||
})
|
||||
.options(options || {});
|
||||
|
||||
if (self.options.milliseconds) {
|
||||
self.options.seconds = true;
|
||||
if (self.options.value.indexOf('.') == -1) {
|
||||
self.options.value += '.000';
|
||||
}
|
||||
}
|
||||
|
||||
self.date = getDate();
|
||||
self.values = getValues();
|
||||
|
||||
self.$input = {
|
||||
hours: new Ox.Input({
|
||||
autocomplete: $.map(self.options.ampm ? Ox.range(1, 13) : Ox.range(0, 24), function(v) {
|
||||
return Ox.pad(v, 2);
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'hours',
|
||||
textAlign: 'right',
|
||||
value: self.values.hours,
|
||||
width: 32
|
||||
}),
|
||||
minutes: new Ox.Input({
|
||||
autocomplete: $.map(Ox.range(0, 60), function(v) {
|
||||
return Ox.pad(v, 2);
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'minutes',
|
||||
textAlign: 'right',
|
||||
value: self.values.minutes,
|
||||
width: 32
|
||||
}),
|
||||
seconds: new Ox.Input({
|
||||
autocomplete: $.map(Ox.range(0, 60), function(v) {
|
||||
return Ox.pad(v, 2);
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'seconds',
|
||||
textAlign: 'right',
|
||||
value: self.values.seconds,
|
||||
width: 32
|
||||
}),
|
||||
milliseconds: new Ox.Input({
|
||||
autocomplete: $.map(Ox.range(0, 1000), function(v) {
|
||||
return Ox.pad(v, 3);
|
||||
}),
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'milliseconds',
|
||||
textAlign: 'right',
|
||||
value: self.values.milliseconds,
|
||||
width: 40
|
||||
}),
|
||||
ampm: new Ox.Input({
|
||||
autocomplete: ['AM', 'PM'],
|
||||
autocompleteReplace: true,
|
||||
autocompleteReplaceCorrect: true,
|
||||
id: 'ampm',
|
||||
value: self.values.ampm,
|
||||
width: 32
|
||||
})
|
||||
};
|
||||
|
||||
that = new Ox.InputGroup($.extend(self.options, {
|
||||
inputs: $.merge($.merge($.merge([
|
||||
self.$input.hours,
|
||||
self.$input.minutes,
|
||||
], self.options.seconds ? [
|
||||
self.$input.seconds
|
||||
] : []), self.options.milliseconds ? [
|
||||
self.$input.milliseconds
|
||||
] : []), self.options.ampm ? [
|
||||
self.$input.ampm
|
||||
] : []),
|
||||
separators: $.merge($.merge($.merge([
|
||||
{title: ':', width: 8},
|
||||
], self.options.seconds ? [
|
||||
{title: ':', width: 8}
|
||||
] : []), self.options.milliseconds ? [
|
||||
{title: '.', width: 8}
|
||||
] : []), self.options.ampm ? [
|
||||
{title: '', width: 8}
|
||||
] : []),
|
||||
//width: self.options.width || 128
|
||||
}), self)
|
||||
.bindEvent('change', setValue);
|
||||
|
||||
setValue();
|
||||
|
||||
function getDate() {
|
||||
return new Date('1970/01/01 ' + (
|
||||
self.options.milliseconds ?
|
||||
self.options.value.substr(0, self.options.value.length - 4) :
|
||||
self.options.value
|
||||
));
|
||||
}
|
||||
|
||||
function getValues() {
|
||||
self.date = getDate();
|
||||
return {
|
||||
ampm: Ox.formatDate(self.date, '%p'),
|
||||
hours: Ox.formatDate(self.date, self.options.ampm ? '%I' : '%H'),
|
||||
milliseconds: self.options.milliseconds ? self.options.value.substr(-3) : '000',
|
||||
minutes: Ox.formatDate(self.date, '%M'),
|
||||
seconds: Ox.formatDate(self.date, '%S')
|
||||
};
|
||||
}
|
||||
|
||||
function setValue() {
|
||||
self.options.value = Ox.formatDate(new Date('1970/01/01 ' + [
|
||||
self.$input.hours.options('value'),
|
||||
self.$input.minutes.options('value'),
|
||||
self.options.seconds ? self.$input.seconds.options('value') : '00'
|
||||
].join(':') + (self.options.ampm ? ' ' + self.$input.ampm.options('value') : '')),
|
||||
(self.options.seconds? '%T' : '%H:%M')) +
|
||||
(self.options.milliseconds ? '.' + self.$input.milliseconds.options('value') : '');
|
||||
//Ox.print('SETVALUE', self.options.value);
|
||||
}
|
||||
|
||||
function setValues() {
|
||||
self.values = getValues();
|
||||
Ox.forEach(self.$input, function(v, k) {
|
||||
self.$input[k].options({
|
||||
value: self.values[k]
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
self.onChange = function(key, value) {
|
||||
if (key == 'value') {
|
||||
setValues();
|
||||
}
|
||||
}
|
||||
|
||||
return that;
|
||||
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue