404 lines
13 KiB
JavaScript
404 lines
13 KiB
JavaScript
// 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;
|
|
|
|
};
|