reactjs-query-builder
Version:
296 lines (273 loc) • 12.1 kB
JavaScript
;
import last from 'lodash/last';
import pick from 'lodash/pick';
import pickBy from 'lodash/pickBy';
import merge from 'lodash/merge';
import mergeWith from 'lodash/mergeWith';
import cloneDeep from 'lodash/cloneDeep';
export const extendConfig = (config) => {
//operators, defaultOperator - merge
//widgetProps (including valueLabel, valuePlaceholder, hideOperator, operatorInlineLabel) - concrete by widget
//extend 'types' path
for (let type in config.types) {
let typeConfig = config.types[type];
let operators = null, defaultOperator = null;
typeConfig.mainWidget = typeConfig.mainWidget || Object.keys(typeConfig.widgets).filter(w => w != 'field')[0];
for (let widget in typeConfig.widgets) {
let typeWidgetConfig = typeConfig.widgets[widget];
if (typeWidgetConfig.operators) {
if (!operators)
operators = [];
operators = operators.concat(typeWidgetConfig.operators.slice());
}
if (typeWidgetConfig.defaultOperator)
defaultOperator = typeWidgetConfig.defaultOperator;
if (widget == typeConfig.mainWidget) {
typeWidgetConfig = merge({}, {widgetProps: typeConfig.mainWidgetProps || {}}, typeWidgetConfig);
}
typeConfig.widgets[widget] = typeWidgetConfig;
}
if (!typeConfig.valueSources)
typeConfig.valueSources = Object.keys(config.settings.valueSourcesInfo);
for (let valueSrc of typeConfig.valueSources) {
if (valueSrc != 'value' && !typeConfig.widgets[valueSrc]) {
typeConfig.widgets[valueSrc] = {
};
}
}
if (!typeConfig.operators && operators)
typeConfig.operators = Array.from(new Set(operators)); //unique
if (!typeConfig.defaultOperator && defaultOperator)
typeConfig.defaultOperator = defaultOperator;
config.types[type] = typeConfig;
}
//extend 'fields' path
function _extendFieldConfig(fieldConfig) {
let operators = null, defaultOperator = null;
let typeConfig = config.types[fieldConfig.type];
if (fieldConfig.type != '!struct') {
if (!fieldConfig.widgets)
fieldConfig.widgets = {};
fieldConfig.mainWidget = fieldConfig.mainWidget || typeConfig.mainWidget;
fieldConfig.valueSources = fieldConfig.valueSources || typeConfig.valueSources;
for (let widget in typeConfig.widgets) {
let fieldWidgetConfig = fieldConfig.widgets[widget] || {};
if (fieldWidgetConfig.operators) {
if (!operators)
operators = [];
operators = operators.concat(fieldWidgetConfig.operators.slice());
}
if (fieldWidgetConfig.defaultOperator)
defaultOperator = fieldWidgetConfig.defaultOperator;
if (widget == fieldConfig.mainWidget) {
fieldWidgetConfig = merge({}, {widgetProps: fieldConfig.mainWidgetProps || {}}, fieldWidgetConfig);
}
fieldConfig.widgets[widget] = fieldWidgetConfig;
}
if (!fieldConfig.operators && operators)
fieldConfig.operators = Array.from(new Set(operators));
if (!fieldConfig.defaultOperator && defaultOperator)
fieldConfig.defaultOperator = defaultOperator;
}
};
function _extendFieldsConfig(subconfig) {
for (let field in subconfig) {
_extendFieldConfig(subconfig[field]);
if (subconfig[field].subfields) {
_extendFieldsConfig(subconfig[field].subfields);
}
}
}
_extendFieldsConfig(config.fields);
//console.log(config);
return config;
};
export const getFieldRawConfig = (field, config) => {
if (!field || field == ':empty:')
return null;
const fieldSeparator = config.settings.fieldSeparator;
const parts = field.split(fieldSeparator);
let fields = config.fields;
let fieldConfig = null;
for (let i = 0 ; i < parts.length ; i++) {
const part = parts[i];
const tmpFieldConfig = fields[part];
if (!tmpFieldConfig)
return null;
if (i == parts.length-1) {
fieldConfig = tmpFieldConfig;
} else {
fields = tmpFieldConfig.subfields;
if (!fields)
return null;
}
}
return fieldConfig;
};
export const getFieldConfig = (field, config) => {
if (!field || field == ':empty:')
return null;
const fieldConfig = getFieldRawConfig(field, config);
if (!fieldConfig)
return null; //throw new Error("Can't find field " + field + ", please check your config");
//merge, but don't merge operators (rewrite instead)
const typeConfig = config.types[fieldConfig.type] || {};
let ret = mergeWith({}, typeConfig, fieldConfig || {}, (objValue, srcValue, key, object, source, stack) => {
if (Array.isArray(objValue)) {
return srcValue;
}
});
return ret;
};
export const getFirstField = (config) => {
const fieldSeparator = config.settings.fieldSeparator;
let firstField = null, key = null, keysPath = [];
if (Object.keys(config.fields).length > 0) {
key = Object.keys(config.fields)[0];
firstField = config.fields[key];
keysPath.push(key);
while (firstField.type == '!struct') {
const subfields = firstField.subfields;
if (!subfields || !Object.keys(subfields).length) {
firstField = key = null;
break;
}
key = Object.keys(subfields)[0];
keysPath.push(key);
firstField = subfields[key];
}
}
return keysPath.join(fieldSeparator);
};
export const getOperatorsForField = (config, field) => {
const fieldConfig = getFieldConfig(field, config);
const fieldOps = fieldConfig ? fieldConfig.operators : [];
return fieldOps;
};
export const getFirstOperator = (config, field) => {
const fieldOps = getOperatorsForField(config, field);
return fieldOps ? fieldOps[0] : null;
};
export const getFieldPath = (field, config) => {
if (!field || field == ':empty:')
return null;
const fieldSeparator = config.settings.fieldSeparator;
return field
.split(fieldSeparator)
.map((curr, ind, arr) => arr.slice(0, ind+1))
.map((parts) => parts.join(fieldSeparator));
};
export const getFieldPathLabels = (field, config) => {
if (!field || field == ':empty:')
return null;
const fieldSeparator = config.settings.fieldSeparator;
return field
.split(fieldSeparator)
.map((curr, ind, arr) => arr.slice(0, ind+1))
.map((parts) => parts.join(fieldSeparator))
.map(part => {
const cnf = getFieldConfig(part, config);
return cnf && cnf.label || last(part.split(fieldSeparator))
});
};
export const getOperatorConfig = (config, operator, field = null) => {
if (!operator)
return null;
const opConfig = config.operators[operator];
if (field) {
const fieldConfig = getFieldConfig(field, config);
const widget = getWidgetForFieldOp(config, field, operator);
const fieldWidgetConfig = (fieldConfig && fieldConfig.widgets ? fieldConfig.widgets[widget] : {}) || {};
const fieldWidgetOpProps = (fieldWidgetConfig.opProps || {})[operator];
const mergedOpConfig = merge({}, opConfig, fieldWidgetOpProps);
return mergedOpConfig;
} else {
return opConfig;
}
};
export const getFieldWidgetConfig = (config, field, operator, widget = null, valueSrc = null) => {
if (!field || !(operator || widget))
return null;
const fieldConfig = getFieldConfig(field, config);
if (!widget)
widget = getWidgetForFieldOp(config, field, operator, valueSrc);
const widgetConfig = config.widgets[widget] || {};
const fieldWidgetConfig = (fieldConfig && fieldConfig.widgets ? fieldConfig.widgets[widget] : {}) || {};
const fieldWidgetProps = (fieldWidgetConfig.widgetProps || {});
const mergedConfig = merge({}, widgetConfig, fieldWidgetProps);
return mergedConfig;
};
export const getValueLabel = (config, field, operator, delta, valueSrc = null, isSpecialRange = false) => {
const fieldWidgetConfig = getFieldWidgetConfig(config, field, operator, null, valueSrc) || {};
const mergedOpConfig = getOperatorConfig(config, operator, field) || {};
const cardinality = isSpecialRange ? 1 : mergedOpConfig.cardinality;
let ret = null;
if (cardinality > 1) {
const valueLabels = mergedOpConfig.valueLabels;
if (valueLabels)
ret = valueLabels[delta];
if (ret && typeof ret != 'object') {
ret = {label: ret, placeholder: ret};
}
if (!ret) {
ret = {
label: (config.settings.valueLabel || "Value") + " " + (delta+1),
placeholder: (config.settings.valuePlaceholder || "Value") + " " + (delta+1),
}
}
} else {
ret = {
label: fieldWidgetConfig.valueLabel || config.settings.valueLabel || "Value",
placeholder: fieldWidgetConfig.valuePlaceholder || config.settings.valuePlaceholder || "Value",
};
}
return ret;
};
function _getWidgetsAndSrcsForFieldOp (config, field, operator, valueSrc = null) {
let widgets = [];
let valueSrcs = [];
if (!field || !operator)
return {widgets, valueSrcs};
const fieldConfig = getFieldConfig(field, config);
//const typeConfig = config.types[fieldConfig.type] || {};
const opConfig = config.operators[operator];
if (fieldConfig && fieldConfig.widgets) {
for (let widget in fieldConfig.widgets) {
let widgetConfig = fieldConfig.widgets[widget];
let widgetValueSrc = config.widgets[widget].valueSrc;
let canAdd = widgetConfig.operators ? widgetConfig.operators.indexOf(operator) != -1 : valueSrc != 'value';
canAdd = canAdd && (!valueSrc || valueSrc == widgetValueSrc);
if (opConfig.isUnary && (widgetValueSrc != 'value'))
canAdd = false;
if (canAdd) {
widgets.push(widget);
if (fieldConfig.valueSources && fieldConfig.valueSources.indexOf(widgetValueSrc) != -1 && !valueSrcs.find(v => v == widgetValueSrc))
valueSrcs.push(widgetValueSrc);
}
}
}
widgets.sort((w1, w2) => {
let w1Main = fieldConfig.preferWidgets ? fieldConfig.preferWidgets.indexOf(w1) != -1 : w1 == fieldConfig.mainWidget;
let w2Main = fieldConfig.preferWidgets ? fieldConfig.preferWidgets.indexOf(w2) != -1 : w2 == fieldConfig.mainWidget;
if (w1 != w2) {
return w1Main ? -1 : +1;
}
return 0;
});
return {widgets, valueSrcs};
};
export const getWidgetsForFieldOp = (config, field, operator, valueSrc = null) => {
let {widgets, valueSrcs} = _getWidgetsAndSrcsForFieldOp(config, field, operator, valueSrc);
return widgets;
};
export const getValueSourcesForFieldOp = (config, field, operator) => {
let {widgets, valueSrcs} = _getWidgetsAndSrcsForFieldOp(config, field, operator, null);
return valueSrcs;
};
export const getWidgetForFieldOp = (config, field, operator, valueSrc = null) => {
let {widgets, valueSrcs} = _getWidgetsAndSrcsForFieldOp(config, field, operator, valueSrc);
let widget = null;
if (widgets.length)
widget = widgets[0];
return widget;
};