Ox.Filter, round 2

This commit is contained in:
rlx 2011-01-24 04:08:19 +00:00
parent 44530bceb9
commit 358c1ecebb
2 changed files with 384 additions and 230 deletions

View file

@ -1226,6 +1226,10 @@ Format functions
================================================================================ ================================================================================
*/ */
Ox.formatColor = function() {
};
Ox.formatCurrency = function(num, str, dec) { Ox.formatCurrency = function(num, str, dec) {
return str + formatNumber(num, dec); return str + formatNumber(num, dec);
}; };
@ -1511,6 +1515,10 @@ Ox.formatValue = function(num, str) {
return val; return val;
}; };
Ox.formatUnit = function(num, str) {
return num + ' ' + str;
};
/* /*
================================================================================ ================================================================================
Geo functions Geo functions

View file

@ -2085,71 +2085,80 @@ requires
============================================================================ ============================================================================
*/ */
/**
*/
Ox.Filter = function(options, self) { Ox.Filter = function(options, self) {
/***
Options:
Methods:
Events:
***/
var self = self || {}, var self = self || {},
that = new Ox.Element('div', self) that = new Ox.Element('div', self)
.defaults({ .defaults({
keys: [], findKeys: [],
query: { query: {
conditions: [], conditions: [],
operator: '&' operator: '&'
} },
sortKeys: [],
viewKeys: []
}) })
.options(options || {}); .options(options || {});
Ox.print('s.o', self.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) { if (!self.options.query.conditions.length) {
self.options.query.conditions = [{ self.options.query.conditions = [{
key: self.options.keys[0].id, key: self.options.findKeys[0].id,
value: '' value: '',
operator: self.conditionOperators[
getConditionType(self.options.findKeys[0].type)
][0].id
}]; }];
} }
$.extend(self, {
operators: [
{title: 'all', operator: '&'},
{title: 'any', operator: '|'}
],
relations: {
date: [
{title: 'is', operator: '='},
{title: 'is not', operator: '!'},
{title: 'is before', operator: '<'},
{title: 'is after', operator: '>'},
{title: 'is between', operator: '>&<'},
{title: 'is not between', operator: '<|>'}
],
list: [
{title: 'is', operator: '='},
{title: 'is not', operator: '!'}
],
number: [
{title: 'is', operator: '='},
{title: 'is not', operator: '!'},
{title: 'is less than', operator: '<'},
{title: 'is greater than', operator: '>'},
{title: 'is between', operator: '>&<'},
{title: 'is not between', operator: '<|>'}
],
string: [
{title: 'is', operator: '='},
{title: 'is not', operator: '!='},
{title: 'begins with', operator: '^'},
{title: 'ends with', operator: '$'},
{title: 'contains', operator: ''},
{title: 'does not contain', operator: '!'}
],
text: [
{title: 'contains', operator: ''},
{title: 'does not contain', operator: '!'}
]
}
});
self.$operator = new Ox.FormElementGroup({ self.$operator = new Ox.FormElementGroup({
elements: [ elements: [
new Ox.Label({ new Ox.Label({
@ -2157,18 +2166,24 @@ requires
overlap: 'right', overlap: 'right',
width: 48 width: 48
}), }),
new Ox.Select({ new Ox.FormElementGroup({
items: [ elements: [
{id: 'all', title: 'all'}, new Ox.Select({
{id: 'any', title: 'any'}, items: self.operators,
width: 48
})
.bindEvent({
change: changeOperator
}),
new Ox.Label({
overlap: 'left',
title: 'of the following conditions',
width: 160
})
], ],
overlap: 'right', float: 'right',
width: 48 width: 208
}), })
new Ox.Label({
title: 'of the following conditions',
width: 160
}),
], ],
float: 'left', float: 'left',
}); });
@ -2205,40 +2220,109 @@ requires
width: 120 width: 120
}), }),
new Ox.Select({ new Ox.Select({
/* items: self.options.sortKeys,
items: $.map(self.options.keys, function(key) {
return {id: key.id, title: key.title};
}),
*/
items: [
{id: "title", title: "Title"},
{id: "director", title: "Director"}
],
width: 128 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: [ separators: [
{title: 'Limit to', width: 56}, {title: 'Limit to', width: 56},
{title: 'sorted by', width: 64} {title: 'sorted by', width: 64},
{title: 'in', width: 32}
] ]
}); });
self.$items = $.merge($.merge([self.$operator], self.$conditions), [self.$limit]); 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}
]
});
that = new Ox.Form({ 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 items: self.$items
}, $.extend({}, self)); });
that.$element = self.$form.$element;
function addCondition(pos) { function addCondition(pos) {
var key = self.options.keys[0]; var key = self.options.findKeys[0];
self.options.query.conditions.splice(pos, 0, { self.options.query.conditions.splice(pos, 0, {
key: key.id, key: key.id,
value: '', value: '',
operator: self.relations[key.type][0].operator operator: self.conditionOperators[key.type][0].id
}); });
self.$conditions.splice(pos, 0, constructCondition({}, pos)); self.$conditions.splice(pos, 0, constructCondition({}, pos));
updateConditions(); updateConditions();
that.addItem(pos + 1, self.$conditions[pos]); self.$form.addItem(pos + 1, self.$conditions[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) {
}
function changeOperator(event, data) {
self.options.query.operator = data.selected[0].id;
} }
function constructCondition(condition, pos) { function constructCondition(condition, pos) {
@ -2246,17 +2330,23 @@ requires
return $condition = new Ox.FormElementGroup({ return $condition = new Ox.FormElementGroup({
elements: [ elements: [
new Ox.Select({ new Ox.Select({
items: $.extend({}, self.options.keys), // fixme: Ox.Menu messes with keys items: $.map(self.options.findKeys, function(key) {
overlap: 'right', return {
width: 128 id: key.id,
}), title: key.title
new Ox.Select({ };
items: $.map(self.relations[self.options.keys[0].type], function(relation) { }),
return {id: relation.title, title: relation.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);
}
}), }),
overlap: 'right', constructConditionOperator(pos),
width: 128
}),
new Ox.Input({ new Ox.Input({
width: 256 width: 256
}), }),
@ -2282,6 +2372,7 @@ requires
.css({margin: '0 4px 0 4px'}) .css({margin: '0 4px 0 4px'})
.bindEvent({ .bindEvent({
click: function() { click: function() {
Ox.print('add', $(this).parent().parent().data('position'))
addCondition($condition.data('position') + 1) addCondition($condition.data('position') + 1)
} }
}), }),
@ -2291,17 +2382,54 @@ requires
tooltip: 'Add Group of Conditions', tooltip: 'Add Group of Conditions',
type: 'image' type: 'image'
}) })
.css({margin: '0 0 0 4px'}), .css({margin: '0 0 0 4px'})
.bindEvent({
click: function() {
}
})
] ]
}) })
.data({position: pos}); .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 getConditionType(type) {
type = Ox.isArray(type) ? type[0] : type;
if (['float', 'integer', 'year'].indexOf(type) > 1) {
type = 'number';
}
return type;
}
function removeCondition(pos) { function removeCondition(pos) {
self.options.query.conditions.splice(pos, 1); self.options.query.conditions.splice(pos, 1);
self.$conditions.splice(pos, 1); self.$conditions.splice(pos, 1);
updateConditions(); updateConditions();
that.removeItem(pos + 1); self.$form.removeItem(pos + 1);
} }
function updateConditions() { function updateConditions() {
@ -2317,9 +2445,11 @@ requires
}; };
/**
*/
Ox.Form = function(options, self) { Ox.Form = function(options, self) {
/**
*/
var self = self || {}, var self = self || {},
that = new Ox.Element('div', self) that = new Ox.Element('div', self)
.defaults({ .defaults({
@ -2437,8 +2567,6 @@ requires
}; };
/**
*/
Ox.FormItem = function(options, self) { Ox.FormItem = function(options, self) {
var self = self || {}, var self = self || {},
@ -2471,18 +2599,20 @@ requires
Form Elements Form Elements
*/ */
/**
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
*/
Ox.Button = function(options, self) { 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 || {}, var self = self || {},
that = new Ox.Element('input', self) that = new Ox.Element('input', self)
.defaults({ .defaults({
@ -2632,18 +2762,20 @@ requires
}; };
/**
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
*/
Ox.ButtonGroup = function(options, self) { 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 || {}, var self = self || {},
that = new Ox.Element({}, self) that = new Ox.Element({}, self)
.defaults({ .defaults({
@ -2705,24 +2837,24 @@ requires
return that; return that;
}; };
/**
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}
*/
Ox.Checkbox = function(options, self) { 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 || {}, var self = self || {},
that = new Ox.Element('div', self) that = new Ox.Element('div', self)
@ -2810,18 +2942,19 @@ requires
}; };
/**
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}
*/
Ox.CheckboxGroup = function(options, self) { 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 || {}, var self = self || {},
that = new Ox.Element('div', self) that = new Ox.Element('div', self)
.defaults({ .defaults({
@ -2880,60 +3013,62 @@ requires
}; };
/**
options
arrows boolearn, if true, and type is 'float' or 'integer', display arrows
arrowStep number, step when clicking arrows
autocomplete array of possible values, or
function(key, value, callback), returns one or more values
autocompleteReplace boolean, if true, value is replaced
autocompleteReplaceCorrect boolean, if true, only valid values can be entered
autocompleteSelect boolean, if true, menu is displayed
autocompleteSelectHighlight boolean, if true, value in menu is highlighted
autocompleteSelectSubmit boolean, if true, submit input on menu selection
autocorrect string ('email', 'float', 'integer', 'phone', 'url'), or
regexp(value), or
function(key, value, blur, callback), returns value
auto validate --remote validation--
clear boolean, if true, has clear button
disabled boolean, if true, is disabled
height integer, px (for type='textarea' and type='range' with orientation='horizontal')
id string, element id
key string, to be passed to autocomplete and autovalidate functions
max number, max value if type is 'integer' or 'float'
min number, min value if type is 'integer' or 'float'
name string, will be displayed by autovalidate function ('invalid ' + name)
overlap string, '', 'left' or 'right', will cause padding and negative margin
picker
//rangeOptions
arrows boolean, if true, display arrows
//arrowStep number, step when clicking arrows
//arrowSymbols array of two strings
max number, maximum value
min number, minimum value
orientation 'horizontal' or 'vertical'
step number, step
thumbValue boolean, if true, value is displayed on thumb, or
array of strings per value, or
function(value), returns string
thumbSize integer, px
trackGradient string, css gradient for track
trackImage string, image url, or
array of image urls
//trackStep number, 0 for 'scroll here', positive for step
trackValues boolean
serialize
textAlign 'left', 'center' or 'right'
type 'float', 'integer', 'password', 'text'
value string
validate function, remote validation
width integer, px
methods:
events:
change
submit
*/
Ox.Input = function(options, self) { Ox.Input = function(options, self) {
/**
options
arrows boolearn, if true, and type is 'float' or 'integer', display arrows
arrowStep number, step when clicking arrows
autocomplete array of possible values, or
function(key, value, callback), returns one or more values
autocompleteReplace boolean, if true, value is replaced
autocompleteReplaceCorrect boolean, if true, only valid values can be entered
autocompleteSelect boolean, if true, menu is displayed
autocompleteSelectHighlight boolean, if true, value in menu is highlighted
autocompleteSelectSubmit boolean, if true, submit input on menu selection
autocorrect string ('email', 'float', 'integer', 'phone', 'url'), or
regexp(value), or
function(key, value, blur, callback), returns value
autovalidate --remote validation--
clear boolean, if true, has clear button
disabled boolean, if true, is disabled
height integer, px (for type='textarea' and type='range' with orientation='horizontal')
id string, element id
key string, to be passed to autocomplete and autovalidate functions
max number, max value if type is 'integer' or 'float'
min number, min value if type is 'integer' or 'float'
name string, will be displayed by autovalidate function ('invalid ' + name)
overlap string, '', 'left' or 'right', will cause padding and negative margin
picker
//rangeOptions
arrows boolean, if true, display arrows
//arrowStep number, step when clicking arrows
//arrowSymbols array of two strings
max number, maximum value
min number, minimum value
orientation 'horizontal' or 'vertical'
step number, step
thumbValue boolean, if true, value is displayed on thumb, or
array of strings per value, or
function(value), returns string
thumbSize integer, px
trackGradient string, css gradient for track
trackImage string, image url, or
array of image urls
//trackStep number, 0 for 'scroll here', positive for step
trackValues boolean
serialize
textAlign 'left', 'center' or 'right'
type 'float', 'integer', 'password', 'text'
value string
validate function, remote validation
width integer, px
methods:
events:
change
submit
*/
var self = self || {}, var self = self || {},
that = new Ox.Element('div', self) that = new Ox.Element('div', self)
.defaults({ .defaults({
@ -3809,20 +3944,21 @@ requires
}; };
/**
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
}
*/
Ox.DateInput = function(options, self) { 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 || {}, { var self = $.extend(self || {}, {
options: $.extend({ options: $.extend({
format: 'short', format: 'short',
@ -4402,25 +4538,27 @@ requires
} }
/**
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
*/
Ox.Range = function(options, self) { 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 || {}, var self = self || {},
that = new Ox.Element({}, self) that = new Ox.Element({}, self)
.defaults({ .defaults({
@ -4851,10 +4989,14 @@ requires
} }
self.onChange = function(key, value) { self.onChange = function(key, value) {
if (key == 'trackColors') {
};
}
} 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() { that.value = function() {
return $.map(self.options.elements, function(element) { return $.map(self.options.elements, function(element) {
@ -7817,6 +7959,8 @@ requires
.options(options || {}) .options(options || {})
.addClass('OxTextList'); .addClass('OxTextList');
Ox.print('Ox.TextList self.options', self.options)
$.each(self.options.columns, function(i, v) { // fixme: can this go into a generic ox.js function? $.each(self.options.columns, function(i, v) { // fixme: can this go into a generic ox.js function?
// fixme: and can't these just remain undefined? // fixme: and can't these just remain undefined?
if (Ox.isUndefined(v.align)) { if (Ox.isUndefined(v.align)) {
@ -8012,7 +8156,7 @@ requires
isSelected = self.options.sort[0].key == self.options.columns[i].id; isSelected = self.options.sort[0].key == self.options.columns[i].id;
that.sortList( that.sortList(
self.options.columns[i].id, isSelected ? self.options.columns[i].id, isSelected ?
(self.options.sort[0].operator === '' ? '-' : '') : (self.options.sort[0].operator == '+' ? '-' : '+') :
self.options.columns[i].operator self.options.columns[i].operator
); );
} }
@ -8050,7 +8194,7 @@ requires
$order = $('<div>') $order = $('<div>')
.addClass('OxOrder') .addClass('OxOrder')
.html(oxui.symbols['triangle_' + ( .html(oxui.symbols['triangle_' + (
v.operator === '' ? 'up' : 'down' v.operator == '+' ? 'up' : 'down'
)]) )])
.click(function() { .click(function() {
$(this).prev().trigger('click') $(this).prev().trigger('click')
@ -8367,7 +8511,7 @@ requires
var pos = getColumnPositionById(id); var pos = getColumnPositionById(id);
//Ox.print(id, pos) //Ox.print(id, pos)
that.$titles[pos].next().html(oxui.symbols[ that.$titles[pos].next().html(oxui.symbols[
'triangle_' + (self.options.sort[0].operator === '' ? 'up' : 'down') 'triangle_' + (self.options.sort[0].operator == '+' ? 'up' : 'down')
]); ]);
} }
@ -9423,7 +9567,7 @@ requires
that.items = []; that.items = [];
$.each(items, function(i, item) { $.each(items, function(i, item) {
var position; var position;
if (item.id) { if ('id' in item) {
that.items.push(new Ox.MenuItem($.extend(item, { that.items.push(new Ox.MenuItem($.extend(item, {
menu: that, menu: that,
position: position = that.items.length position: position = that.items.length
@ -9941,9 +10085,11 @@ requires
title: Ox.makeArray(options.title || self.defaults.title) title: Ox.makeArray(options.title || self.defaults.title)
})) }))
.addClass('OxItem' + (self.options.disabled ? ' OxDisabled' : '')) .addClass('OxItem' + (self.options.disabled ? ' OxDisabled' : ''))
/*
.attr({ .attr({
id: Ox.toCamelCase(self.options.menu.options('id') + '/' + self.options.id) id: Ox.toCamelCase(self.options.menu.options('id') + '/' + self.options.id)
}) })
*/
.data('group', self.options.group); // fixme: why? .data('group', self.options.group); // fixme: why?
if (self.options.group && self.options.checked === null) { if (self.options.group && self.options.checked === null) {