UNPKG

siesta-lite

Version:

Stress-free JavaScript unit testing and functional testing tool, works in NodeJS and browsers

218 lines (164 loc) 8.23 kB
/* Siesta 5.6.1 Copyright(c) 2009-2022 Bryntum AB https://bryntum.com/contact https://bryntum.com/products/siesta/license */ Class("Siesta.Util.TreeStoreFilterer", { has : { idProp : { required : true }, childNodesProp : { required : true }, parentNodeProp : { required : true }, isLeaf : { required : true } }, does : [ Siesta.Util.Role.CanEscapeRegExp ], methods : { parseFilterValue : function (filterValue) { var parts = filterValue.split(/\s*\>\s*/) var groupFilter = parts.length > 1 ? parts[ 0 ] : '' var leafFilter = parts.length > 1 ? parts[ 1 ] : parts[ 0 ] return { testFilterRegexps : this.splitTermByPipe(leafFilter), groupFilterRegexps : groupFilter ? this.splitTermByPipe(groupFilter) : null } }, checkCommonFilter : function (node, getTitle, testFilterRegexps, groupFilterRegexps) { if (groupFilterRegexps) { var currentNode = node var isInGroup = false while (currentNode && currentNode[ this.parentNodeProp ]) { var parent = currentNode[ this.parentNodeProp ] if (this.matchAnyOfRegExps(getTitle(parent), groupFilterRegexps)) { isInGroup = true break } currentNode = parent } if (!isInGroup) return false } if (this.matchAnyOfRegExps(getTitle(node), testFilterRegexps)) return true // if there's no name filtering testFilterRegexps - return true (show all elements) return !testFilterRegexps.length }, // split term by | first, then by whitespace splitTermByPipe : function (term) { var parts = term.split(/\s*\|\s*/); var regexps = [] var me = this for (var i = 0; i < parts.length; i++) { // ignore empty if (parts[ i ]) { regexps.push( Joose.A.map(parts[ i ].split(/\s+/), function (token) { return new RegExp(me.escapeRegExp(token), 'i') }) ) } } return regexps }, matchAnyOfRegExps : function (string, regexps) { for (var p = 0; p < regexps.length; p++) { var groupMatch = true var len = regexps[ p ].length // blazing fast "for" loop! :) for (var i = 0; i < len; i++) if (!regexps[ p ][ i ].test(string)) { groupMatch = false break } if (groupMatch) return true } return false }, collectNodes : function (root, params) { var me = this; var filter = params.filter; var scope = params.scope || this; var shallowScan = params.shallow; var checkParents = params.checkParents || shallowScan; var fullMatchingParents = params.fullMatchingParents; var onlyParents = params.onlyParents || fullMatchingParents; if (onlyParents && checkParents) throw new Error("Can't combine `onlyParents` and `checkParents` options"); var idProp = this.idProp var parentNodeProp = this.parentNodeProp var childNodesProp = this.childNodesProp var isLeaf = this.isLeaf var rootVisible = params.rootVisible var visibleNodes = {} var includeNodeInResults = function (node) { visibleNodes[ node[ idProp ] ] = true; var parent = node[ parentNodeProp ]; while (parent && !visibleNodes[ parent[ idProp ] ]) { visibleNodes[ parent[ idProp ] ] = true; parent = parent[ parentNodeProp ]; } }; var cascadeNode = function (node, func) { func(node) var childNodes = node[ childNodesProp ]; var length = childNodes.length; // at this point nodeMatches and fullMatchingParents can't be both true for (var k = 0; k < length; k++) if (isLeaf(node)) func(node) else cascadeNode(childNodes[ k ], func) } if (rootVisible) visibleNodes[ root[ idProp ] ] = true var collectNodes = function (node) { if (node.hidden) return; var nodeMatches, childNodes, length, k; // `collectNodes` should not be called for leafs at all if (isLeaf(node)) { if (filter.call(scope, node, visibleNodes)) { includeNodeInResults(node); } } else { if (onlyParents) { nodeMatches = filter.call(scope, node); if (nodeMatches) { includeNodeInResults(node); // if "fullMatchingParents" option enabled we gather all matched parent's sub-tree if (fullMatchingParents) { cascadeNode(node, function (currentNode) { visibleNodes[ currentNode[ idProp ] ] = true; }); return; } } childNodes = node[ childNodesProp ]; length = childNodes.length; // at this point nodeMatches and fullMatchingParents can't be both true for (k = 0; k < length; k++) if (nodeMatches && isLeaf(childNodes[ k ])) visibleNodes[ childNodes[ k ][ idProp ] ] = true; else if (!isLeaf(childNodes[ k ])) collectNodes(childNodes[ k ]); } else { // mark matching nodes to be kept in results if (checkParents) { nodeMatches = filter.call(scope, node, visibleNodes); if (nodeMatches) { includeNodeInResults(node); } } // recurse if // - we don't check parents // - shallow scan is not enabled // - shallow scan is enabled and parent node matches the filter or it does not, but its and invisible root, so we don't care if (!checkParents || !shallowScan || shallowScan && (nodeMatches || node == root && !rootVisible)) { childNodes = node[ childNodesProp ]; length = childNodes.length; for (k = 0; k < length; k++) collectNodes(childNodes[ k ]); } } } }; collectNodes(root); return visibleNodes } } });