blob: f67b299025967d55b42f75bb814700174fdb3e6f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* A service for defining the FilterPattern class.
*/
angular.module('list').factory('FilterPattern', ['$injector',
function defineFilterPattern($injector) {
// Required types
var FilterToken = $injector.get('FilterToken');
var IPv4Network = $injector.get('IPv4Network');
var IPv6Network = $injector.get('IPv6Network');
// Required services
var $parse = $injector.get('$parse');
/**
* Object which handles compilation of filtering predicates as used by
* the Angular "filter" filter. Predicates are compiled from a user-
* specified search string.
*
* @constructor
* @param {String[]} expressions
* The Angular expressions whose values are to be filtered.
*/
var FilterPattern = function FilterPattern(expressions) {
/**
* Reference to this instance.
*
* @type FilterPattern
*/
var filterPattern = this;
/**
* Filter predicate which simply matches everything. This function
* always returns true.
*
* @returns {Boolean}
* true.
*/
var nullPredicate = function nullPredicate() {
return true;
};
/**
* Array of getters corresponding to the Angular expressions provided
* to the constructor of this class. The functions returns are those
* produced by the $parse service.
*
* @type Function[]
*/
var getters = [];
// Parse all expressions
angular.forEach(expressions, function parseExpression(expression) {
getters.push($parse(expression));
});
/**
* Determines whether the given object contains properties that match
* the given string, according to the provided getters.
*
* @param {Object} object
* The object to match against.
*
* @param {String} str
* The string to match.
*
* @returns {Boolean}
* true if the object matches the given string, false otherwise.
*/
var matchesString = function matchesString(object, str) {
// For each defined getter
for (var i=0; i < getters.length; i++) {
// Retrieve value of current getter
var value = getters[i](object);
// If the value matches the pattern, the whole object matches
if (String(value).toLowerCase().indexOf(str) !== -1)
return true;
}
// No matches found
return false;
};
/**
* Determines whether the given object contains properties that match
* the given IPv4 network, according to the provided getters.
*
* @param {Object} object
* The object to match against.
*
* @param {IPv4Network} network
* The IPv4 network to match.
*
* @returns {Boolean}
* true if the object matches the given network, false otherwise.
*/
var matchesIPv4 = function matchesIPv4(object, network) {
// For each defined getter
for (var i=0; i < getters.length; i++) {
// Test each possible IPv4 address within the string against
// the given IPv4 network
var addresses = String(getters[i](object)).split(/[^0-9.]+/);
for (var j=0; j < addresses.length; j++) {
var value = IPv4Network.parse(addresses[j]);
if (value && network.contains(value))
return true;
}
}
// No matches found
return false;
};
/**
* Determines whether the given object contains properties that match
* the given IPv6 network, according to the provided getters.
*
* @param {Object} object
* The object to match against.
*
* @param {IPv6Network} network
* The IPv6 network to match.
*
* @returns {Boolean}
* true if the object matches the given network, false otherwise.
*/
var matchesIPv6 = function matchesIPv6(object, network) {
// For each defined getter
for (var i=0; i < getters.length; i++) {
// Test each possible IPv6 address within the string against
// the given IPv6 network
var addresses = String(getters[i](object)).split(/[^0-9A-Fa-f:]+/);
for (var j=0; j < addresses.length; j++) {
var value = IPv6Network.parse(addresses[j]);
if (value && network.contains(value))
return true;
}
}
// No matches found
return false;
};
/**
* Determines whether the given object matches the given filter pattern
* token.
*
* @param {Object} object
* The object to match the token against.
*
* @param {FilterToken} token
* The token from the tokenized filter pattern to match aginst the
* given object.
*
* @returns {Boolean}
* true if the object matches the token, false otherwise.
*/
var matchesToken = function matchesToken(object, token) {
// Match depending on token type
switch (token.type) {
// Simple string literal
case 'LITERAL':
return matchesString(object, token.value);
// IPv4 network address / subnet
case 'IPV4_NETWORK':
return matchesIPv4(object, token.value);
// IPv6 network address / subnet
case 'IPV6_NETWORK':
return matchesIPv6(object, token.value);
// Unsupported token type
default:
return false;
}
};
/**
* The current filtering predicate.
*
* @type Function
*/
this.predicate = nullPredicate;
/**
* Compiles the given pattern string, assigning the resulting filter
* predicate. The resulting predicate will accept only objects that
* match the given pattern.
*
* @param {String} pattern
* The pattern to compile.
*/
this.compile = function compile(pattern) {
// If no pattern provided, everything matches
if (!pattern) {
filterPattern.predicate = nullPredicate;
return;
}
// Tokenize pattern, converting to lower case for case-insensitive matching
var tokens = FilterToken.tokenize(pattern.toLowerCase());
// Return predicate which matches against the value of any getter in the getters array
filterPattern.predicate = function matchesAllTokens(object) {
// False if any token does not match
for (var i=0; i < tokens.length; i++) {
if (!matchesToken(object, tokens[i]))
return false;
}
// True if all tokens matched
return true;
};
};
};
return FilterPattern;
}]);