diff --git a/resources/js/components/field-conditions/Condition.vue b/resources/js/components/field-conditions/Condition.vue index 735395eaa00..24c0e6deb17 100644 --- a/resources/js/components/field-conditions/Condition.vue +++ b/resources/js/components/field-conditions/Condition.vue @@ -145,6 +145,7 @@ export default { 'not': __('not'), 'contains': __('contains'), 'contains_any': __('contains any'), + 'includes_any': __('includes any'), '===': '===', '!==': '!==', '>': '>', diff --git a/resources/js/components/field-conditions/Constants.js b/resources/js/components/field-conditions/Constants.js index 868a970e92f..dd866069dea 100644 --- a/resources/js/components/field-conditions/Constants.js +++ b/resources/js/components/field-conditions/Constants.js @@ -14,6 +14,7 @@ export const OPERATORS = [ 'not', 'contains', 'contains_any', + 'includes_any', '===', '!==', '>', @@ -29,5 +30,4 @@ export const ALIASES = { 'isnt': 'not', '!=': 'not', 'includes': 'contains', - 'includes_any': 'contains_any', }; diff --git a/resources/js/components/field-conditions/Validator.js b/resources/js/components/field-conditions/Validator.js index 42b2a5b8771..fa5433b57e4 100644 --- a/resources/js/components/field-conditions/Validator.js +++ b/resources/js/components/field-conditions/Validator.js @@ -122,7 +122,6 @@ export default class { return 'includes'; case 'includes_any': case 'contains_any': - return 'includes_any'; } return operator; @@ -137,7 +136,7 @@ export default class { } // When performing lhs.includes(), if lhs is not an object or array, cast to string. - if (operator === 'includes' && ! isObject(lhs)) { + if ((operator === 'includes' || operator == 'includes_any') && ! isObject(lhs)) { return lhs ? lhs.toString() : ''; } @@ -169,10 +168,15 @@ export default class { } // When performing a comparison that cannot be eval()'d, return rhs as is. - if (rhs === 'empty' || operator === 'includes' || operator === 'includes_any') { + if (rhs === 'empty' || operator === 'includes') { return rhs; } + // Comparisons with _any operators need to be arrayed + if (operator === 'contains_any' || operator === 'includes_any') { + return rhs.split(',').map(string => string.trim()); + } + // Prepare for eval() and return. return isString(rhs) ? JSON.stringify(rhs.trim()) @@ -222,6 +226,10 @@ export default class { return this.passesCustomCondition(condition); } + if (condition.operator === 'contains_any') { + return this.passesContainsAnyCondition(condition); + } + if (condition.operator === 'includes') { return this.passesIncludesCondition(condition); } @@ -247,13 +255,19 @@ export default class { } passesIncludesAnyCondition(condition) { - let values = condition.rhs.split(',').map(string => string.trim()); + if (Array.isArray(condition.lhs)) { + return intersection(condition.lhs, condition.rhs).length; + } + + return condition.rhs.includes(condition.lhs); + } + passesContainsAnyCondition(condition) { if (Array.isArray(condition.lhs)) { - return intersection(condition.lhs, values).length; + return intersection(condition.lhs, condition.rhs).length; } - return new RegExp(values.join('|')).test(condition.lhs); + return new RegExp(condition.rhs.join('|')).test(condition.lhs); } passesCustomCondition(condition) { diff --git a/resources/js/tests/FieldConditionsValidator.test.js b/resources/js/tests/FieldConditionsValidator.test.js index af54ca38c6c..a3835f7cdf9 100644 --- a/resources/js/tests/FieldConditionsValidator.test.js +++ b/resources/js/tests/FieldConditionsValidator.test.js @@ -200,13 +200,13 @@ test('it can use includes_any or contains_any operators in conditions', () => { }); expect(showFieldIf({cancellation_reasons: 'includes_any sick, other'})).toBe(true); - expect(showFieldIf({cancellation_reasons: 'contains_any sick, other'})).toBe(true); expect(showFieldIf({cancellation_reasons: 'includes_any sick, found another'})).toBe(false); - expect(showFieldIf({cancellation_reasons: 'contains_any sick, found another'})).toBe(false); + expect(showFieldIf({cancellation_reasons: 'contains_any sick, other'})).toBe(true); + expect(showFieldIf({cancellation_reasons: 'contains_any sick, expensive'})).toBe(false); - expect(showFieldIf({example_string: 'includes_any parrot, lazy dog'})).toBe(true); - expect(showFieldIf({example_string: 'contains_any parrot, lazy dog'})).toBe(true); + expect(showFieldIf({example_string: 'includes_any parrot, The quick brown fox jumps over the lazy dog'})).toBe(true); expect(showFieldIf({example_string: 'includes_any parrot, hops'})).toBe(false); + expect(showFieldIf({example_string: 'contains_any parrot, lazy dog'})).toBe(true); expect(showFieldIf({example_string: 'contains_any parrot, hops'})).toBe(false); expect(showFieldIf({age: 'includes_any fox, 13'})).toBe(true); diff --git a/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php b/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php index 90eb25ae91b..79714ba3d38 100644 --- a/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php +++ b/src/Fieldtypes/Concerns/ResolvesStatamicUrls.php @@ -13,11 +13,11 @@ trait ResolvesStatamicUrls */ protected function resolveStatamicUrls(string $content) { - return preg_replace_callback('/([("])statamic:\/\/([^()"]*)([)"])/im', function ($matches) { + return preg_replace_callback('/([("])statamic:\/\/([^()"?#]*)([^()"]*)([)"])/im', function ($matches) { $data = Data::find($matches[2]); - $url = $data ? $data->url() : ''; + $url = $data ? $data->url().$matches[3] : ''; - return $matches[1].$url.$matches[3]; + return $matches[1].$url.$matches[4]; }, $content); } }