|
@@ -4,7 +4,7 @@
|
|
|
// goal is to filter complete documents by using the local filters for each
|
|
|
// fields.
|
|
|
function showFilterSidebar() {
|
|
|
- Sidebar.setView('filter');
|
|
|
+ Sidebar.setView('filter');
|
|
|
}
|
|
|
|
|
|
// Use a "set" filter for a field that is a set of documents uniquely
|
|
@@ -12,446 +12,446 @@ function showFilterSidebar() {
|
|
|
// use "subField" for searching inside object Fields.
|
|
|
// For instance '{ 'customFields._id': ['field1','field2']} (subField would be: _id)
|
|
|
class SetFilter {
|
|
|
- constructor(subField = '') {
|
|
|
- this._dep = new Tracker.Dependency();
|
|
|
- this._selectedElements = [];
|
|
|
- this.subField = subField;
|
|
|
+ constructor(subField = '') {
|
|
|
+ this._dep = new Tracker.Dependency();
|
|
|
+ this._selectedElements = [];
|
|
|
+ this.subField = subField;
|
|
|
+ }
|
|
|
+
|
|
|
+ isSelected(val) {
|
|
|
+ this._dep.depend();
|
|
|
+ return this._selectedElements.indexOf(val) > -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ add(val) {
|
|
|
+ if (this._indexOfVal(val) === -1) {
|
|
|
+ this._selectedElements.push(val);
|
|
|
+ this._dep.changed();
|
|
|
+ showFilterSidebar();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- isSelected(val) {
|
|
|
- this._dep.depend();
|
|
|
- return this._selectedElements.indexOf(val) > -1;
|
|
|
+ remove(val) {
|
|
|
+ const indexOfVal = this._indexOfVal(val);
|
|
|
+ if (this._indexOfVal(val) !== -1) {
|
|
|
+ this._selectedElements.splice(indexOfVal, 1);
|
|
|
+ this._dep.changed();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- add(val) {
|
|
|
- if (this._indexOfVal(val) === -1) {
|
|
|
- this._selectedElements.push(val);
|
|
|
- this._dep.changed();
|
|
|
- showFilterSidebar();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- remove(val) {
|
|
|
- const indexOfVal = this._indexOfVal(val);
|
|
|
- if (this._indexOfVal(val) !== -1) {
|
|
|
- this._selectedElements.splice(indexOfVal, 1);
|
|
|
- this._dep.changed();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- toggle(val) {
|
|
|
- if (this._indexOfVal(val) === -1) {
|
|
|
- this.add(val);
|
|
|
- } else {
|
|
|
- this.remove(val);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- reset() {
|
|
|
- this._selectedElements = [];
|
|
|
- this._dep.changed();
|
|
|
- }
|
|
|
-
|
|
|
- _indexOfVal(val) {
|
|
|
- return this._selectedElements.indexOf(val);
|
|
|
- }
|
|
|
-
|
|
|
- _isActive() {
|
|
|
- this._dep.depend();
|
|
|
- return this._selectedElements.length !== 0;
|
|
|
- }
|
|
|
-
|
|
|
- _getMongoSelector() {
|
|
|
- this._dep.depend();
|
|
|
- return {
|
|
|
- $in: this._selectedElements
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- _getEmptySelector() {
|
|
|
- this._dep.depend();
|
|
|
- let includeEmpty = false;
|
|
|
- this._selectedElements.forEach((el) => {
|
|
|
- if (el === undefined) {
|
|
|
- includeEmpty = true;
|
|
|
- }
|
|
|
- });
|
|
|
- return includeEmpty ? {
|
|
|
- $eq: []
|
|
|
- } : null;
|
|
|
+ toggle(val) {
|
|
|
+ if (this._indexOfVal(val) === -1) {
|
|
|
+ this.add(val);
|
|
|
+ } else {
|
|
|
+ this.remove(val);
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ reset() {
|
|
|
+ this._selectedElements = [];
|
|
|
+ this._dep.changed();
|
|
|
+ }
|
|
|
+
|
|
|
+ _indexOfVal(val) {
|
|
|
+ return this._selectedElements.indexOf(val);
|
|
|
+ }
|
|
|
+
|
|
|
+ _isActive() {
|
|
|
+ this._dep.depend();
|
|
|
+ return this._selectedElements.length !== 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ _getMongoSelector() {
|
|
|
+ this._dep.depend();
|
|
|
+ return {
|
|
|
+ $in: this._selectedElements,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ _getEmptySelector() {
|
|
|
+ this._dep.depend();
|
|
|
+ let includeEmpty = false;
|
|
|
+ this._selectedElements.forEach((el) => {
|
|
|
+ if (el === undefined) {
|
|
|
+ includeEmpty = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return includeEmpty ? {
|
|
|
+ $eq: [],
|
|
|
+ } : null;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
// Advanced filter forms a MongoSelector from a users String.
|
|
|
// Build by: Ignatz 19.05.2018 (github feuerball11)
|
|
|
class AdvancedFilter {
|
|
|
- constructor() {
|
|
|
- this._dep = new Tracker.Dependency();
|
|
|
- this._filter = '';
|
|
|
- this._lastValide = {};
|
|
|
+ constructor() {
|
|
|
+ this._dep = new Tracker.Dependency();
|
|
|
+ this._filter = '';
|
|
|
+ this._lastValide = {};
|
|
|
+ }
|
|
|
+
|
|
|
+ set(str) {
|
|
|
+ this._filter = str;
|
|
|
+ this._dep.changed();
|
|
|
+ }
|
|
|
+
|
|
|
+ reset() {
|
|
|
+ this._filter = '';
|
|
|
+ this._lastValide = {};
|
|
|
+ this._dep.changed();
|
|
|
+ }
|
|
|
+
|
|
|
+ _isActive() {
|
|
|
+ this._dep.depend();
|
|
|
+ return this._filter !== '';
|
|
|
+ }
|
|
|
+
|
|
|
+ _filterToCommands() {
|
|
|
+ const commands = [];
|
|
|
+ let current = '';
|
|
|
+ let string = false;
|
|
|
+ let regex = false;
|
|
|
+ let wasString = false;
|
|
|
+ let ignore = false;
|
|
|
+ for (let i = 0; i < this._filter.length; i++) {
|
|
|
+ const char = this._filter.charAt(i);
|
|
|
+ if (ignore) {
|
|
|
+ ignore = false;
|
|
|
+ current += char;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (char === '/') {
|
|
|
+ string = !string;
|
|
|
+ if (string) regex = true;
|
|
|
+ current += char;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (char === '\'') {
|
|
|
+ string = !string;
|
|
|
+ if (string) wasString = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (char === '\\' && !string) {
|
|
|
+ ignore = true;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (char === ' ' && !string) {
|
|
|
+ commands.push({
|
|
|
+ 'cmd': current,
|
|
|
+ 'string': wasString,
|
|
|
+ regex,
|
|
|
+ });
|
|
|
+ wasString = false;
|
|
|
+ current = '';
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ current += char;
|
|
|
}
|
|
|
-
|
|
|
- set(str) {
|
|
|
- this._filter = str;
|
|
|
- this._dep.changed();
|
|
|
+ if (current !== '') {
|
|
|
+ commands.push({
|
|
|
+ 'cmd': current,
|
|
|
+ 'string': wasString,
|
|
|
+ regex,
|
|
|
+ });
|
|
|
}
|
|
|
-
|
|
|
- reset() {
|
|
|
- this._filter = '';
|
|
|
- this._lastValide = {};
|
|
|
- this._dep.changed();
|
|
|
+ return commands;
|
|
|
+ }
|
|
|
+
|
|
|
+ _fieldNameToId(field) {
|
|
|
+ const found = CustomFields.findOne({
|
|
|
+ 'name': field,
|
|
|
+ });
|
|
|
+ return found._id;
|
|
|
+ }
|
|
|
+
|
|
|
+ _fieldValueToId(field, value) {
|
|
|
+ const found = CustomFields.findOne({
|
|
|
+ 'name': field,
|
|
|
+ });
|
|
|
+ if (found.settings.dropdownItems && found.settings.dropdownItems.length > 0) {
|
|
|
+ for (let i = 0; i < found.settings.dropdownItems.length; i++) {
|
|
|
+ if (found.settings.dropdownItems[i].name === value) {
|
|
|
+ return found.settings.dropdownItems[i]._id;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- _isActive() {
|
|
|
- this._dep.depend();
|
|
|
- return this._filter !== '';
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ _arrayToSelector(commands) {
|
|
|
+ try {
|
|
|
+ //let changed = false;
|
|
|
+ this._processSubCommands(commands);
|
|
|
+ } catch (e) {
|
|
|
+ return this._lastValide;
|
|
|
}
|
|
|
-
|
|
|
- _filterToCommands() {
|
|
|
- const commands = [];
|
|
|
- let current = '';
|
|
|
- let string = false;
|
|
|
- let regex = false;
|
|
|
- let wasString = false;
|
|
|
- let ignore = false;
|
|
|
- for (let i = 0; i < this._filter.length; i++) {
|
|
|
- const char = this._filter.charAt(i);
|
|
|
- if (ignore) {
|
|
|
- ignore = false;
|
|
|
- current += char;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (char === '/') {
|
|
|
- string = !string;
|
|
|
- if (string) regex = true;
|
|
|
- current += char;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (char === '\'') {
|
|
|
- string = !string;
|
|
|
- if (string) wasString = true;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (char === '\\' && !string) {
|
|
|
- ignore = true;
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (char === ' ' && !string) {
|
|
|
- commands.push({
|
|
|
- 'cmd': current,
|
|
|
- 'string': wasString,
|
|
|
- regex
|
|
|
- });
|
|
|
- wasString = false;
|
|
|
- current = '';
|
|
|
- continue;
|
|
|
- }
|
|
|
- current += char;
|
|
|
+ this._lastValide = {
|
|
|
+ $or: commands,
|
|
|
+ };
|
|
|
+ return {
|
|
|
+ $or: commands,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ _processSubCommands(commands) {
|
|
|
+ const subcommands = [];
|
|
|
+ let level = 0;
|
|
|
+ let start = -1;
|
|
|
+ for (let i = 0; i < commands.length; i++) {
|
|
|
+ if (commands[i].cmd) {
|
|
|
+ switch (commands[i].cmd) {
|
|
|
+ case '(':
|
|
|
+ {
|
|
|
+ level++;
|
|
|
+ if (start === -1) start = i;
|
|
|
+ continue;
|
|
|
}
|
|
|
- if (current !== '') {
|
|
|
- commands.push({
|
|
|
- 'cmd': current,
|
|
|
- 'string': wasString,
|
|
|
- regex
|
|
|
- });
|
|
|
+ case ')':
|
|
|
+ {
|
|
|
+ level--;
|
|
|
+ commands.splice(i, 1);
|
|
|
+ i--;
|
|
|
+ continue;
|
|
|
}
|
|
|
- return commands;
|
|
|
- }
|
|
|
-
|
|
|
- _fieldNameToId(field) {
|
|
|
- const found = CustomFields.findOne({
|
|
|
- 'name': field
|
|
|
- });
|
|
|
- return found._id;
|
|
|
- }
|
|
|
-
|
|
|
- _fieldValueToId(field, value) {
|
|
|
- const found = CustomFields.findOne({
|
|
|
- 'name': field
|
|
|
- });
|
|
|
- if (found.settings.dropdownItems && found.settings.dropdownItems.length > 0) {
|
|
|
- for (let i = 0; i < found.settings.dropdownItems.length; i++) {
|
|
|
- if (found.settings.dropdownItems[i].name === value) {
|
|
|
- return found.settings.dropdownItems[i]._id;
|
|
|
- }
|
|
|
- }
|
|
|
+ default:
|
|
|
+ {
|
|
|
+ if (level > 0) {
|
|
|
+ subcommands.push(commands[i]);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ i--;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
}
|
|
|
- return value;
|
|
|
- }
|
|
|
-
|
|
|
- _arrayToSelector(commands) {
|
|
|
- try {
|
|
|
- //let changed = false;
|
|
|
- this._processSubCommands(commands);
|
|
|
- } catch (e) {
|
|
|
- return this._lastValide;
|
|
|
}
|
|
|
- this._lastValide = {
|
|
|
- $or: commands
|
|
|
- };
|
|
|
- return {
|
|
|
- $or: commands
|
|
|
- };
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- _processSubCommands(commands) {
|
|
|
- const subcommands = [];
|
|
|
- let level = 0;
|
|
|
- let start = -1;
|
|
|
- for (let i = 0; i < commands.length; i++) {
|
|
|
- if (commands[i].cmd) {
|
|
|
- switch (commands[i].cmd) {
|
|
|
- case '(':
|
|
|
- {
|
|
|
- level++;
|
|
|
- if (start === -1) start = i;
|
|
|
- continue;
|
|
|
- }
|
|
|
- case ')':
|
|
|
- {
|
|
|
- level--;
|
|
|
- commands.splice(i, 1);
|
|
|
- i--;
|
|
|
- continue;
|
|
|
- }
|
|
|
- default:
|
|
|
- {
|
|
|
- if (level > 0) {
|
|
|
- subcommands.push(commands[i]);
|
|
|
- commands.splice(i, 1);
|
|
|
- i--;
|
|
|
- continue;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ if (start !== -1) {
|
|
|
+ this._processSubCommands(subcommands);
|
|
|
+ if (subcommands.length === 1)
|
|
|
+ commands.splice(start, 0, subcommands[0]);
|
|
|
+ else
|
|
|
+ commands.splice(start, 0, subcommands);
|
|
|
+ }
|
|
|
+ this._processConditions(commands);
|
|
|
+ this._processLogicalOperators(commands);
|
|
|
+ }
|
|
|
+
|
|
|
+ _processConditions(commands) {
|
|
|
+ for (let i = 0; i < commands.length; i++) {
|
|
|
+ if (!commands[i].string && commands[i].cmd) {
|
|
|
+ switch (commands[i].cmd) {
|
|
|
+ case '=':
|
|
|
+ case '==':
|
|
|
+ case '===':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ if (commands[i + 1].regex) {
|
|
|
+ const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
|
|
+ let regex = null;
|
|
|
+ if (match.length > 2)
|
|
|
+ regex = new RegExp(match[1], match[2]);
|
|
|
+ else
|
|
|
+ regex = new RegExp(match[1]);
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': regex,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $in: [this._fieldValueToId(field, str), parseInt(str, 10)],
|
|
|
+ },
|
|
|
+ };
|
|
|
+ }
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
}
|
|
|
- if (start !== -1) {
|
|
|
- this._processSubCommands(subcommands);
|
|
|
- if (subcommands.length === 1)
|
|
|
- commands.splice(start, 0, subcommands[0]);
|
|
|
+ case '!=':
|
|
|
+ case '!==':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ if (commands[i + 1].regex) {
|
|
|
+ const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
|
|
+ let regex = null;
|
|
|
+ if (match.length > 2)
|
|
|
+ regex = new RegExp(match[1], match[2]);
|
|
|
else
|
|
|
- commands.splice(start, 0, subcommands);
|
|
|
+ regex = new RegExp(match[1]);
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $not: regex,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $not: {
|
|
|
+ $in: [this._fieldValueToId(field, str), parseInt(str, 10)],
|
|
|
+ },
|
|
|
+ },
|
|
|
+ };
|
|
|
+ }
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
}
|
|
|
- this._processConditions(commands);
|
|
|
- this._processLogicalOperators(commands);
|
|
|
- }
|
|
|
-
|
|
|
- _processConditions(commands) {
|
|
|
- for (let i = 0; i < commands.length; i++) {
|
|
|
- if (!commands[i].string && commands[i].cmd) {
|
|
|
- switch (commands[i].cmd) {
|
|
|
- case '=':
|
|
|
- case '==':
|
|
|
- case '===':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- if (commands[i + 1].regex) {
|
|
|
- const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
|
|
- let regex = null;
|
|
|
- if (match.length > 2)
|
|
|
- regex = new RegExp(match[1], match[2]);
|
|
|
- else
|
|
|
- regex = new RegExp(match[1]);
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': regex
|
|
|
- };
|
|
|
- } else {
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $in: [this._fieldValueToId(field, str), parseInt(str, 10)]
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case '!=':
|
|
|
- case '!==':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- if (commands[i + 1].regex) {
|
|
|
- const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
|
|
- let regex = null;
|
|
|
- if (match.length > 2)
|
|
|
- regex = new RegExp(match[1], match[2]);
|
|
|
- else
|
|
|
- regex = new RegExp(match[1]);
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $not: regex
|
|
|
- }
|
|
|
- };
|
|
|
- } else {
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $not: {
|
|
|
- $in: [this._fieldValueToId(field, str), parseInt(str, 10)]
|
|
|
- }
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case '>':
|
|
|
- case 'gt':
|
|
|
- case 'Gt':
|
|
|
- case 'GT':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $gt: parseInt(str, 10)
|
|
|
- }
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case '>=':
|
|
|
- case '>==':
|
|
|
- case 'gte':
|
|
|
- case 'Gte':
|
|
|
- case 'GTE':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $gte: parseInt(str, 10)
|
|
|
- }
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case '<':
|
|
|
- case 'lt':
|
|
|
- case 'Lt':
|
|
|
- case 'LT':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $lt: parseInt(str, 10)
|
|
|
- }
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case '<=':
|
|
|
- case '<==':
|
|
|
- case 'lte':
|
|
|
- case 'Lte':
|
|
|
- case 'LTE':
|
|
|
- {
|
|
|
- const field = commands[i - 1].cmd;
|
|
|
- const str = commands[i + 1].cmd;
|
|
|
- commands[i] = {
|
|
|
- 'customFields._id': this._fieldNameToId(field),
|
|
|
- 'customFields.value': {
|
|
|
- $lte: parseInt(str, 10)
|
|
|
- }
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ case '>':
|
|
|
+ case 'gt':
|
|
|
+ case 'Gt':
|
|
|
+ case 'GT':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $gt: parseInt(str, 10),
|
|
|
+ },
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case '>=':
|
|
|
+ case '>==':
|
|
|
+ case 'gte':
|
|
|
+ case 'Gte':
|
|
|
+ case 'GTE':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $gte: parseInt(str, 10),
|
|
|
+ },
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case '<':
|
|
|
+ case 'lt':
|
|
|
+ case 'Lt':
|
|
|
+ case 'LT':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $lt: parseInt(str, 10),
|
|
|
+ },
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case '<=':
|
|
|
+ case '<==':
|
|
|
+ case 'lte':
|
|
|
+ case 'Lte':
|
|
|
+ case 'LTE':
|
|
|
+ {
|
|
|
+ const field = commands[i - 1].cmd;
|
|
|
+ const str = commands[i + 1].cmd;
|
|
|
+ commands[i] = {
|
|
|
+ 'customFields._id': this._fieldNameToId(field),
|
|
|
+ 'customFields.value': {
|
|
|
+ $lte: parseInt(str, 10),
|
|
|
+ },
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- _processLogicalOperators(commands) {
|
|
|
- for (let i = 0; i < commands.length; i++) {
|
|
|
- if (!commands[i].string && commands[i].cmd) {
|
|
|
- switch (commands[i].cmd) {
|
|
|
- case 'or':
|
|
|
- case 'Or':
|
|
|
- case 'OR':
|
|
|
- case '|':
|
|
|
- case '||':
|
|
|
- {
|
|
|
- const op1 = commands[i - 1];
|
|
|
- const op2 = commands[i + 1];
|
|
|
- commands[i] = {
|
|
|
- $or: [op1, op2]
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case 'and':
|
|
|
- case 'And':
|
|
|
- case 'AND':
|
|
|
- case '&':
|
|
|
- case '&&':
|
|
|
- {
|
|
|
- const op1 = commands[i - 1];
|
|
|
- const op2 = commands[i + 1];
|
|
|
- commands[i] = {
|
|
|
- $and: [op1, op2]
|
|
|
- };
|
|
|
- commands.splice(i - 1, 1);
|
|
|
- commands.splice(i, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- case 'not':
|
|
|
- case 'Not':
|
|
|
- case 'NOT':
|
|
|
- case '!':
|
|
|
- {
|
|
|
- const op1 = commands[i + 1];
|
|
|
- commands[i] = {
|
|
|
- $not: op1
|
|
|
- };
|
|
|
- commands.splice(i + 1, 1);
|
|
|
- //changed = true;
|
|
|
- i--;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ _processLogicalOperators(commands) {
|
|
|
+ for (let i = 0; i < commands.length; i++) {
|
|
|
+ if (!commands[i].string && commands[i].cmd) {
|
|
|
+ switch (commands[i].cmd) {
|
|
|
+ case 'or':
|
|
|
+ case 'Or':
|
|
|
+ case 'OR':
|
|
|
+ case '|':
|
|
|
+ case '||':
|
|
|
+ {
|
|
|
+ const op1 = commands[i - 1];
|
|
|
+ const op2 = commands[i + 1];
|
|
|
+ commands[i] = {
|
|
|
+ $or: [op1, op2],
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'and':
|
|
|
+ case 'And':
|
|
|
+ case 'AND':
|
|
|
+ case '&':
|
|
|
+ case '&&':
|
|
|
+ {
|
|
|
+ const op1 = commands[i - 1];
|
|
|
+ const op2 = commands[i + 1];
|
|
|
+ commands[i] = {
|
|
|
+ $and: [op1, op2],
|
|
|
+ };
|
|
|
+ commands.splice(i - 1, 1);
|
|
|
+ commands.splice(i, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'not':
|
|
|
+ case 'Not':
|
|
|
+ case 'NOT':
|
|
|
+ case '!':
|
|
|
+ {
|
|
|
+ const op1 = commands[i + 1];
|
|
|
+ commands[i] = {
|
|
|
+ $not: op1,
|
|
|
+ };
|
|
|
+ commands.splice(i + 1, 1);
|
|
|
+ //changed = true;
|
|
|
+ i--;
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- _getMongoSelector() {
|
|
|
- this._dep.depend();
|
|
|
- const commands = this._filterToCommands();
|
|
|
- return this._arrayToSelector(commands);
|
|
|
- }
|
|
|
+ _getMongoSelector() {
|
|
|
+ this._dep.depend();
|
|
|
+ const commands = this._filterToCommands();
|
|
|
+ return this._arrayToSelector(commands);
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -460,101 +460,101 @@ class AdvancedFilter {
|
|
|
// the need to provide a list of `_fields`. We also should move methods into the
|
|
|
// object prototype.
|
|
|
Filter = {
|
|
|
- // XXX I would like to rename this field into `labels` to be consistent with
|
|
|
- // the rest of the schema, but we need to set some migrations architecture
|
|
|
- // before changing the schema.
|
|
|
- labelIds: new SetFilter(),
|
|
|
- members: new SetFilter(),
|
|
|
- customFields: new SetFilter('_id'),
|
|
|
- advanced: new AdvancedFilter(),
|
|
|
-
|
|
|
- _fields: ['labelIds', 'members', 'customFields'],
|
|
|
-
|
|
|
- // We don't filter cards that have been added after the last filter change. To
|
|
|
- // implement this we keep the id of these cards in this `_exceptions` fields
|
|
|
- // and use a `$or` condition in the mongo selector we return.
|
|
|
- _exceptions: [],
|
|
|
- _exceptionsDep: new Tracker.Dependency(),
|
|
|
-
|
|
|
- isActive() {
|
|
|
- return _.any(this._fields, (fieldName) => {
|
|
|
- return this[fieldName]._isActive();
|
|
|
- }) || this.advanced._isActive();
|
|
|
- },
|
|
|
-
|
|
|
- _getMongoSelector() {
|
|
|
- if (!this.isActive())
|
|
|
- return {};
|
|
|
-
|
|
|
- const filterSelector = {};
|
|
|
- const emptySelector = {};
|
|
|
- let includeEmptySelectors = false;
|
|
|
- this._fields.forEach((fieldName) => {
|
|
|
- const filter = this[fieldName];
|
|
|
- if (filter._isActive()) {
|
|
|
- if (filter.subField !== '') {
|
|
|
- filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
|
|
|
- } else {
|
|
|
- filterSelector[fieldName] = filter._getMongoSelector();
|
|
|
- }
|
|
|
- emptySelector[fieldName] = filter._getEmptySelector();
|
|
|
- if (emptySelector[fieldName] !== null) {
|
|
|
- includeEmptySelectors = true;
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
-
|
|
|
- const exceptionsSelector = {
|
|
|
- _id: {
|
|
|
- $in: this._exceptions
|
|
|
- }
|
|
|
- };
|
|
|
- this._exceptionsDep.depend();
|
|
|
-
|
|
|
- const selectors = [exceptionsSelector];
|
|
|
-
|
|
|
- if (_.any(this._fields, (fieldName) => {
|
|
|
- return this[fieldName]._isActive();
|
|
|
- })) selectors.push(filterSelector);
|
|
|
- if (includeEmptySelectors) selectors.push(emptySelector);
|
|
|
- if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());
|
|
|
-
|
|
|
- return {
|
|
|
- $or: selectors
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- mongoSelector(additionalSelector) {
|
|
|
- const filterSelector = this._getMongoSelector();
|
|
|
- if (_.isUndefined(additionalSelector))
|
|
|
- return filterSelector;
|
|
|
- else
|
|
|
- return {
|
|
|
- $and: [filterSelector, additionalSelector]
|
|
|
- };
|
|
|
- },
|
|
|
-
|
|
|
- reset() {
|
|
|
- this._fields.forEach((fieldName) => {
|
|
|
- const filter = this[fieldName];
|
|
|
- filter.reset();
|
|
|
- });
|
|
|
- this.advanced.reset();
|
|
|
- this.resetExceptions();
|
|
|
- },
|
|
|
-
|
|
|
- addException(_id) {
|
|
|
- if (this.isActive()) {
|
|
|
- this._exceptions.push(_id);
|
|
|
- this._exceptionsDep.changed();
|
|
|
- Tracker.flush();
|
|
|
+ // XXX I would like to rename this field into `labels` to be consistent with
|
|
|
+ // the rest of the schema, but we need to set some migrations architecture
|
|
|
+ // before changing the schema.
|
|
|
+ labelIds: new SetFilter(),
|
|
|
+ members: new SetFilter(),
|
|
|
+ customFields: new SetFilter('_id'),
|
|
|
+ advanced: new AdvancedFilter(),
|
|
|
+
|
|
|
+ _fields: ['labelIds', 'members', 'customFields'],
|
|
|
+
|
|
|
+ // We don't filter cards that have been added after the last filter change. To
|
|
|
+ // implement this we keep the id of these cards in this `_exceptions` fields
|
|
|
+ // and use a `$or` condition in the mongo selector we return.
|
|
|
+ _exceptions: [],
|
|
|
+ _exceptionsDep: new Tracker.Dependency(),
|
|
|
+
|
|
|
+ isActive() {
|
|
|
+ return _.any(this._fields, (fieldName) => {
|
|
|
+ return this[fieldName]._isActive();
|
|
|
+ }) || this.advanced._isActive();
|
|
|
+ },
|
|
|
+
|
|
|
+ _getMongoSelector() {
|
|
|
+ if (!this.isActive())
|
|
|
+ return {};
|
|
|
+
|
|
|
+ const filterSelector = {};
|
|
|
+ const emptySelector = {};
|
|
|
+ let includeEmptySelectors = false;
|
|
|
+ this._fields.forEach((fieldName) => {
|
|
|
+ const filter = this[fieldName];
|
|
|
+ if (filter._isActive()) {
|
|
|
+ if (filter.subField !== '') {
|
|
|
+ filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
|
|
|
+ } else {
|
|
|
+ filterSelector[fieldName] = filter._getMongoSelector();
|
|
|
+ }
|
|
|
+ emptySelector[fieldName] = filter._getEmptySelector();
|
|
|
+ if (emptySelector[fieldName] !== null) {
|
|
|
+ includeEmptySelectors = true;
|
|
|
}
|
|
|
- },
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ const exceptionsSelector = {
|
|
|
+ _id: {
|
|
|
+ $in: this._exceptions,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ this._exceptionsDep.depend();
|
|
|
+
|
|
|
+ const selectors = [exceptionsSelector];
|
|
|
+
|
|
|
+ if (_.any(this._fields, (fieldName) => {
|
|
|
+ return this[fieldName]._isActive();
|
|
|
+ })) selectors.push(filterSelector);
|
|
|
+ if (includeEmptySelectors) selectors.push(emptySelector);
|
|
|
+ if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());
|
|
|
+
|
|
|
+ return {
|
|
|
+ $or: selectors,
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ mongoSelector(additionalSelector) {
|
|
|
+ const filterSelector = this._getMongoSelector();
|
|
|
+ if (_.isUndefined(additionalSelector))
|
|
|
+ return filterSelector;
|
|
|
+ else
|
|
|
+ return {
|
|
|
+ $and: [filterSelector, additionalSelector],
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ reset() {
|
|
|
+ this._fields.forEach((fieldName) => {
|
|
|
+ const filter = this[fieldName];
|
|
|
+ filter.reset();
|
|
|
+ });
|
|
|
+ this.advanced.reset();
|
|
|
+ this.resetExceptions();
|
|
|
+ },
|
|
|
+
|
|
|
+ addException(_id) {
|
|
|
+ if (this.isActive()) {
|
|
|
+ this._exceptions.push(_id);
|
|
|
+ this._exceptionsDep.changed();
|
|
|
+ Tracker.flush();
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
- resetExceptions() {
|
|
|
- this._exceptions = [];
|
|
|
- this._exceptionsDep.changed();
|
|
|
- },
|
|
|
+ resetExceptions() {
|
|
|
+ this._exceptions = [];
|
|
|
+ this._exceptionsDep.changed();
|
|
|
+ },
|
|
|
};
|
|
|
|
|
|
-Blaze.registerHelper('Filter', Filter);
|
|
|
+Blaze.registerHelper('Filter', Filter);
|