@bigfishtv/cockpit
Version:
508 lines (443 loc) • 18.5 kB
JavaScript
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
/**
* Tree Utilities
* @module Utilities/treeUtils
*/
import Immutable from 'immutable';
import cloneDeep from 'lodash/cloneDeep';
//// Immutable.js functions ////
/**
* Recursively iterates through tree looking for id
* @param {Number} id
* @param {Immutable.List} Branch
* @param {String} [iteratorKey=children]
* @return {Immutable.Map}
*/
export function getChildByIdImmutable(id, Branch) {
var iteratorKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
if (typeof id !== 'number' || (typeof Branch === 'undefined' ? 'undefined' : _typeof(Branch)) !== 'object' || typeof iteratorKey !== 'string' || !Immutable.List.isList(Branch)) return false;
var found = false;
Branch.map(function (item) {
if (!found) {
if (item.get('id') === id) found = item;else if (item.get(iteratorKey)) found = getChildByIdImmutable(id, item.get(iteratorKey));
}
});
return found;
}
/**
* @deprecated This function is super-inefficient and should not be used.
*
* Recursively iterates through tree looking for parent of child's id
* @param {Number} id
* @param {Immutable.List} Branch
* @param {String} [iteratorKey=children]
* @return {Immutable.Map}
*/
export function getParentByChildIdImmutable(id, Branch) {
var iteratorKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
if (typeof id !== 'number' || (typeof Branch === 'undefined' ? 'undefined' : _typeof(Branch)) !== 'object' || typeof iteratorKey !== 'string' || !Immutable.List.isList(Branch)) return false;
var found = false;
Branch.map(function (item) {
if (!found) {
if (item.get(iteratorKey)) item.get(iteratorKey).map(function (child) {
if (!found) {
if (child.get('id') === id) {
found = item;
} else found = getParentByChildIdImmutable(id, item.get(iteratorKey));
}
});
}
});
return found;
}
/**
* Recursively iterates through tree using a checker function to determine whether or not to add a branch's key to an array of values
* @param {Immutable.List} tree
* @param {String} key
* @param {Function} checker
* @param {String} [iteratorKey=children]
* @return {Array} - returns array of values
*/
export function collectValuesImmutable(tree, key, checker) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if ((typeof tree === 'undefined' ? 'undefined' : _typeof(tree)) !== 'object' || !Immutable.List.isList(tree) || typeof key !== 'string' || typeof checker !== 'function' || typeof iteratorKey !== 'string') return false;
var values = [];
tree.map(function (branch) {
if (checker(branch) && branch.get(key)) values.push(branch.get(key));
if (branch.get(iteratorKey) && branch.get(iteratorKey).size > 0) values = values.concat(collectValuesImmutable(branch.get(iteratorKey), key, checker, iteratorKey));
});
return values;
}
/**
* Prunes a tree's branches based on a key and an array of disallowed values
* @param {Immutable.List} tree
* @param {String} key
* @param {Array} values - array of key values that determine if a branch is to be pruned
* @param {String} [iteratorKey=children]
* @return {Immutable.List} - returns pruned tree
*/
export function pruneTreeImmutable(tree, key, values) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if ((typeof tree === 'undefined' ? 'undefined' : _typeof(tree)) !== 'object' || !Immutable.List.isList(tree) || typeof iteratorKey !== 'string') return false;
if (!(values instanceof Array)) values = [values];
tree = tree.filter(function (branch) {
return values.indexOf(branch.get(key)) < 0;
});
tree = tree.map(function (branch) {
if (branch.get(iteratorKey) && branch.get(iteratorKey).size > 0) {
return branch.set(iteratorKey, pruneTreeImmutable(branch.get(iteratorKey), key, values, iteratorKey));
}
return branch;
});
return tree;
}
//// Regular array/object functions ////
/**
* Recursively iterates through tree looking for id
* @param {Number} id
* @param {Object[]} Branch
* @param {String} [iteratorKey=children]
* @return {Object[]}
*/
export function getParentByChildId(id, Branch) {
var iteratorKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
if (typeof id !== 'number' || (typeof Branch === 'undefined' ? 'undefined' : _typeof(Branch)) !== 'object' || typeof iteratorKey !== 'string' || !(Branch instanceof Array)) return false;
var found = false;
Branch.map(function (item) {
if (!found) {
if (iteratorKey in item) item[iteratorKey].map(function (child) {
if (!found) {
if ('id' in child && child['id'] === id) {
found = item;
} else {
found = getParentByChildId(id, item[iteratorKey]);
}
}
});
}
});
return found;
}
//
/**
* Takes a flat array and makes it multidimensional
* @param {Object[]} FlatTree - flat array to be inflated
* @param {String} [idTag=id]
* @param {String} [parentTag=parent_id]
* @param {String} [childrenTag=children]
* @param {Number} [parent_id=null]
* @param {Number} [level=0]
* @return {Object[]}
*/
export function inflate(FlatTree) {
var idTag = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'id';
var parentTag = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'parent_id';
var childrenTag = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
var parent_id = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
var level = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
if (!(FlatTree instanceof Array) || typeof idTag !== 'string' || typeof parentTag !== 'string' || typeof childrenTag !== 'string') return false;
var branch = [];
FlatTree.map(function (_item) {
var item = cloneDeep(_item);
if (idTag in item && parentTag in item && item[parentTag] === parent_id) {
var children = inflate(FlatTree, idTag, parentTag, childrenTag, item[idTag], level + 1);
item[childrenTag] = children && children instanceof Array ? children : [];
// item.level = level;
branch.push(item);
}
});
return branch;
}
/**
* Takes a multidimensional array and flattens it
* @param {Object[]} Tree
* @param {String} [iteratorKey=children]
* @param {Number} [level=0]
* @return {Object[]}
*/
export function flatten(Tree) {
var iteratorKey = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'children';
var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
if (!(Tree instanceof Array) || typeof iteratorKey !== 'string') return false;
return Tree.reduce(function (list, branch) {
var rest = {};
Object.keys(branch).map(function (key) {
if (key !== iteratorKey) rest[key] = branch[key];
});
list.push(rest);
if (iteratorKey in branch) {
list = list.concat(flatten(branch[iteratorKey], iteratorKey, level + 1));
}
return list;
}, []);
}
/**
* Takes a multidimensional array and flattens it, excluding certain ids
* @param {Object[]} Tree
* @param {Number[]} ignoreIds
* @param {String} [iteratorKey=children]
* @param {Number} [level=0]
* @return {Object[]}
*/
export function flattenWithoutCollapsed(Tree) {
var ignoreIds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var iteratorKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'children';
var level = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
if (!(Tree instanceof Array) || !(ignoreIds instanceof Array) || typeof iteratorKey !== 'string') return false;
return Tree.reduce(function (list, branch) {
var rest = {};
Object.keys(branch).map(function (key) {
if (key !== iteratorKey) rest[key] = branch[key];
});
list.push(rest);
if (iteratorKey in branch && ignoreIds.indexOf(branch.id) < 0) {
list = list.concat(flattenWithoutCollapsed(branch[iteratorKey], ignoreIds, iteratorKey, level + 1));
}
return list;
}, []);
}
// takes a multidimensional array and flattens it
/**
* Takes a multidimensional array and flattens it with 'path' array
* @param {Object[]} branches
* @param {Array} path
* @return {Object[]}
*/
export function flattenWithPath(branches) {
var path = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var index = 0;
return branches.reduce(function (list, branch) {
var children = branch.children,
rest = _objectWithoutProperties(branch, ['children']);
var newPath = path.slice();
if (path.length) newPath.push('children');
newPath.push(index++);
var item = {
item: _extends({}, rest, { children: children }),
path: newPath
};
list.push(item);
if (children && children.length) {
list = list.concat(flattenWithPath(children, newPath));
}
return list;
}, []);
}
/**
* @param {Object[]} branches
* @param {Number} [parent_id=null]
* @return {Object[]}
*/
export function flattenWithParentIds(branches) {
var parent_id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
return branches.reduce(function (list, branch) {
var children = branch.children,
rest = _objectWithoutProperties(branch, ['children']);
var item = _extends({}, rest, { parent_id: parent_id });
list.push(item);
if (children && children.length) {
list = list.concat(flattenWithParentIds(children, item.id));
}
return list;
}, []);
}
/**
* Prunes a tree's branches based on a key and an array of disallowed values
* @param {Object[]} _tree
* @param {String} key
* @param {String[]} values
* @param {String} [iteratorKey=children]
* @return {Object[]}
*/
export function pruneTree(_tree, key, values) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if (!(_tree instanceof Array) || typeof key !== 'string' || typeof iteratorKey !== 'string') return false;
if (!(values instanceof Array)) values = [values];
var tree = cloneDeep(_tree);
tree = tree.filter(function (branch) {
return values.indexOf(branch[key]) < 0;
});
tree = tree.map(function (branch) {
if (iteratorKey in branch && branch[iteratorKey] instanceof Array) branch[iteratorKey] = pruneTree(branch[iteratorKey], key, values, iteratorKey);
return branch;
});
return tree;
}
/**
* Recursively iterates through tree using a checker function to determine whether or not to add a branch's key to an array of values
* @param {Object[]} tree
* @param {String} key
* @param {Function} checker
* @param {String} [iteratorKey=children]
* @return {Array} - returns array of values
*/
export function collectValues(tree, key, checker) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if (!(tree instanceof Array) || typeof key !== 'string' || typeof checker !== 'function' || typeof iteratorKey !== 'string') return false;
var values = [];
tree.map(function (branch) {
if (checker(branch) && key in branch) values.push(branch[key]);
if (iteratorKey in branch && branch[iteratorKey] instanceof Array) values = values.concat(collectValues(branch[iteratorKey], key, checker, iteratorKey));
});
return values;
}
/**
* Recursively iterates through tree to get a child by a key and a value
* @param {Object[]} tree
* @param {String} key
* @param {*} value - Can be anything
* @param {String} [iteratorKey=children]
* @return {Object}
*/
export function getChildByKeyValue(tree, key, value) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if (!(tree instanceof Array) || typeof key !== 'string' || typeof iteratorKey !== 'string') return false;
var found = false;
tree.map(function (item) {
if (!found) {
if (item[key] === value) found = item;else if (item[iteratorKey]) found = getChildByKeyValue(item[iteratorKey], key, value, iteratorKey);
}
});
return found;
}
/**
* Recursively iterates through tree and get all values of a set key
* @param {Object[]} _tree
* @param {Number} id
* @param {String} key
* @param {String} [iteratorKey=children]
* @return {String[]}
*/
export function collectChildrenKeyValues(_tree, id, key) {
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if (!(_tree instanceof Array) || typeof key !== 'string' || typeof id !== 'number' || typeof iteratorKey !== 'string') return false;
var branch = getChildByKeyValue(_tree, 'id', id, iteratorKey);
if (!branch[iteratorKey]) return [];
return collectValues(branch[iteratorKey], key, function (item) {
return true;
}, iteratorKey);
}
/**
* Recursively iterates through tree looking for a child and sets a value by key, returns new tree
* @param {Object[]} _tree
* @param {Number} id
* @param {String} setKey
* @param {*} setValue - Can be anything
* @param {Object[]}
*/
export function setKeyValueById(_tree, id, setKey, setValue) {
var iteratorKey = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'children';
var tree = cloneDeep(_tree);
return tree.map(function (item) {
if (item.id === id) item[setKey] = setValue;
if (item[iteratorKey]) item[iteratorKey] = setKeyValueById(item[iteratorKey], id, setKey, setValue, iteratorKey);
return item;
});
}
/**
* Recursively iterates through tree and sorts all branches by key, returns new tree
* @param {Object[]} _tree
* @param {String} key
* @param {Boolean} desc - Descending
* @param {String} [iteratorKey=children]
* @return {Object[]}
*/
export function sortByKey(_tree, key) {
var desc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
var tree = _tree.slice();
tree.sort(function (a, b) {
if (typeof a[key] == 'string') {
return a[key].localeCompare(b[key], undefined, { sensitivity: 'base' });
} else {
return a[key] - b[key];
}
});
if (desc) tree.reverse();
return tree.map(function (item) {
var _extends2;
if (!item[iteratorKey]) {
return item;
}
return _extends({}, item, (_extends2 = {}, _extends2[iteratorKey] = sortByKey(item[iteratorKey], key, desc, iteratorKey), _extends2));
});
}
/**
* Recursively iterates through tree and appends child to parent by parentId, returns new tree
* @param {Object[]} _tree
* @param {Number} parentId
* @param {Object} child
* @param {Number} [currentParentId=null]
* @param {String} [iteratorKey=children]
* @return {Object[]}
*/
export function appendChildToParent(_tree, parentId, child) {
var currentParentId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
var iteratorKey = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'children';
if (!(_tree instanceof Array) || typeof iteratorKey !== 'string') return false;
var tree = cloneDeep(_tree);
if (parentId === currentParentId) tree.push(child);else tree = tree.map(function (item) {
if (parentId === item.id && !item[iteratorKey]) item[iteratorKey] = [];
if (item[iteratorKey]) item[iteratorKey] = appendChildToParent(item[iteratorKey], parentId, child, item.id, iteratorKey);
return item;
});
return tree;
}
/**
* Recursively iterates through tree looking to replace a specific child by given key (children are preserved), returns new tree
* @param {Object[]} _tree
* @param {Object} child
* @param {String} [key=id]
* @param {String} [iteratorKey=children]
* @return {Object[]}
*/
export function replaceChild(_tree, child) {
var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'id';
var iteratorKey = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'children';
if (!(_tree instanceof Array) || typeof iteratorKey !== 'string') return false;
var tree = cloneDeep(_tree);
return tree.map(function (item) {
if (item[key] === child[key]) {
var _extends3;
if (item[iteratorKey] && item[iteratorKey].length) return _extends({}, child, (_extends3 = {}, _extends3[iteratorKey] = item[iteratorKey], _extends3));else return child;
}
if (item[iteratorKey]) item[iteratorKey] = replaceChild(item[iteratorKey], child, key, iteratorKey);
return item;
});
}
/**
* Recursively iterates through tree and concats branch chilren where supplied values match branch value
* @param {Object[]} _tree
* @param {Object[]} values
* @param {String} valueKey
* @param {String} key
* @param {String} iteratorKey
* @return {Object[]}
*/
export function mergeChildren(_tree, values) {
var valueKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'folder_id';
var key = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 'id';
var iteratorKey = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 'children';
if (!(_tree instanceof Array) || !(values instanceof Array)) return false;
var tree = cloneDeep(_tree);
var orphanedValues = values.filter(function (value) {
return value[valueKey] === null;
});
if (orphanedValues.length > 0) tree = [].concat(tree, orphanedValues.map(function (value) {
return _extends({}, value, { __injected: true });
}));
return tree.map(function (item) {
if (item.__injected) return item;
var injectValues = values.filter(function (value) {
return value[valueKey] == item[key];
});
if (item[iteratorKey] && item[iteratorKey].length > 0) {
item[iteratorKey] = [].concat(mergeChildren(item[iteratorKey], values, valueKey, key, iteratorKey), injectValues);
} else {
item[iteratorKey] = injectValues;
}
return item;
});
}