1
0
Fork 0
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:
rolux 2011-04-27 21:24:33 +02:00
commit 4489e88f44
596 changed files with 115093 additions and 17682 deletions

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
}

File diff suppressed because it is too large Load diff

View 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;
};

View 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;
};

View 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;
}

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};

View 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;
};