Skip to content

Commit

Permalink
Frontend form field conditions ... (statamic#4949)
Browse files Browse the repository at this point in the history
...and CP forms only submit visible fields, in order to fix sometimes/required_if/etc validation rules. (statamic#5101)

Co-authored-by: Jason Varga <[email protected]>
Co-authored-by: StyleCI Bot <[email protected]>
Co-authored-by: Jason Varga <[email protected]>
  • Loading branch information
4 people committed Jan 27, 2022
1 parent 9b3c10d commit 4632bbf
Show file tree
Hide file tree
Showing 51 changed files with 1,544 additions and 153 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ jobs:
- name: Compile assets
run: npm run production

- name: Compile frontend assets
run: npm run frontend-prod

- name: Create zip
run: cd resources && tar -czvf dist.tar.gz dist
run: cd resources && tar -czvf dist.tar.gz dist dist-frontend

- name: Get Changelog
id: changelog
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ node_modules
.phpunit.result.cache
tests/Fakes/Composer/Package/test-package/composer.json
resources/dist
resources/dist-frontend
composer.lock
9 changes: 9 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
}
}]
]
};
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"extra": {
"download-dist": {
"url": "https://github.com/statamic/cms/releases/download/{$version}/dist.tar.gz",
"path": "resources/dist"
"path": "resources"
},
"laravel": {
"providers": [
Expand Down
9 changes: 9 additions & 0 deletions frontend.mix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const mix = require('laravel-mix');
const src = 'resources';
const dest = 'resources/dist-frontend';

mix.setPublicPath('./resources/dist-frontend');

mix.js(`${src}/js/frontend/helpers.js`, `${dest}/js`)

mix.sourceMaps();
8 changes: 4 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ module.exports = {
// snapshotSerializers: [],

// The test environment that will be used for testing
testEnvironment: "node",
testEnvironment: "jsdom",

// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
Expand Down Expand Up @@ -167,9 +167,9 @@ module.exports = {
// transform: null,

// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/"
// ],
transformIgnorePatterns: [
'node_modules/(?!(underscore)/)'
],

// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
Expand Down
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
"prod": "npm run production",
"production": "node node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"svgo": "svgo -f ./resources/svg/ -r",
"test": "cross-env NODE_ENV=test jest",
"test-watch": "npm run test -- --watch --notify"
"test": "cross-env NODE_ENV=test jest --silent",
"test-watch": "npm run test -- --watch --notify",
"frontend-dev": "npm run development -- --env.mixfile=frontend.mix",
"frontend-prod": "npm run production -- --env.mixfile=frontend.mix",
"frontend-watch": "npm run watch -- --env.mixfile=frontend.mix"
},
"dependencies": {
"@popperjs/core": "^2.5.3",
Expand Down Expand Up @@ -51,7 +54,7 @@
"svgo": "^2.6.1",
"sweetalert": "~1.0.1",
"tiptap-extensions": "^1.28.6",
"underscore": "~1.9.2",
"underscore": "~1.13.2",
"uniqid": "^5.2.0",
"v-calendar": "^1.0.1",
"v-tooltip": "^2.0.3",
Expand Down
6 changes: 5 additions & 1 deletion resources/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import Vue from 'vue';
import Toast from './mixins/Toast.js';
import Statamic from './components/Statamic.js';
import Alpine from 'alpinejs'
import * as Globals from './bootstrap/globals'

let global_functions = Object.keys(Globals)
global_functions.forEach(fnName => { global[fnName] = Globals[fnName] })
global.Cookies = require('cookies-js');

Vue.config.silent = false;
Vue.config.devtools = true;
Expand All @@ -14,7 +19,6 @@ window._ = require('underscore');
window.$ = window.jQuery = require('jquery');
window.rangy = require('rangy');

require('./bootstrap/globals');
require('./bootstrap/polyfills');
require('./bootstrap/underscore-mixins');
require('./bootstrap/jquery-plugins');
Expand Down
30 changes: 14 additions & 16 deletions resources/js/bootstrap/globals.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,50 @@
import { marked } from 'marked';
import { translate, translateChoice } from '../translations/translator';

global.cp_url = function(url) {
export function cp_url(url) {
url = Statamic.$config.get('cpUrl') + '/' + url;
return tidy_url(url);
};

global.docs_url = function(url) {
export function docs_url(url) {
return tidy_url('https://statamic.dev/' + url);
};

global.resource_url = function(url) {
export function resource_url(url) {
url = Statamic.$config.get('resourceUrl') + '/' + url;
return tidy_url(url);
};

global.tidy_url = function(url) {
export function tidy_url(url) {
return url.replace(/([^:])(\/\/+)/g, '$1/')
}

global.relative_url = function(url) {
export function relative_url(url) {
return url.replace(/^(?:\/\/|[^/]+)*\//, '/');
}

global.file_icon = function(extension) {
export function file_icon(extension) {
return resource_url('img/filetypes/'+ extension +'.png');
};

global.dd = function(args) {
export function dd(args) {
console.log(args);
};

global.data_get = function(obj, path, fallback=null) {
export function data_get(obj, path, fallback=null) {
// Source: https://stackoverflow.com/a/22129960
var properties = Array.isArray(path) ? path : path.split('.');
var value = properties.reduce((prev, curr) => prev && prev[curr], obj);
return value !== undefined ? value : fallback;
};

global.clone = function (value) {
export function clone(value) {
if (value === undefined) return undefined;

return JSON.parse(JSON.stringify(value));
}

global.Cookies = require('cookies-js');

global.tailwind_width_class = function (width) {
export function tailwind_width_class(width) {
const widths = {
25: '1/4',
33: '1/3',
Expand All @@ -59,18 +57,18 @@ global.tailwind_width_class = function (width) {
return `w-${widths[width] || 'full'}`;
}

global.markdown = function (value) {
export function markdown(value) {
return marked(value);
};

global.__ = function (string, replacements) {
export function __(string, replacements) {
return translate(string, replacements);
}
global.__n = function (string, number, replacements) {
export function __n(string, number, replacements) {
return translateChoice(string, number, replacements);
}

global.utf8btoa = function (stringToEncode) {
export function utf8btoa(stringToEncode) {
// first we convert it to utf-8
const utf8String = encodeURIComponent(stringToEncode)
.replace(/%([0-9A-F]{2})/g, (_, code) => String.fromCharCode(`0x${code}`));
Expand Down
9 changes: 7 additions & 2 deletions resources/js/components/assets/Editor/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@

<publish-container
v-if="fields"
name="publishContainer"
:name="publishContainer"
:blueprint="fieldset"
:values="values"
:meta="meta"
Expand Down Expand Up @@ -185,9 +185,14 @@
import EditorActions from './EditorActions.vue';
import FocalPointEditor from './FocalPointEditor.vue';
import PublishFields from '../../publish/Fields.vue';
import HasHiddenFields from '../../data-list/HasHiddenFields';
export default {
mixins: [
HasHiddenFields,
],
components: {
EditorActions,
FocalPointEditor,
Expand Down Expand Up @@ -332,7 +337,7 @@ export default {
this.saving = true;
const url = cp_url(`assets/${utf8btoa(this.id)}`);
this.$axios.patch(url, this.values).then(response => {
this.$axios.patch(url, this.visibleValues).then(response => {
this.$emit('saved', response.data.asset);
this.$toast.success(__('Saved'));
this.saving = false;
Expand Down
17 changes: 17 additions & 0 deletions resources/js/components/data-list/HasHiddenFields.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default {

computed: {

hiddenFields() {
return this.$store.state.publish[this.publishContainer].hiddenFields;
},

visibleValues() {
return _.omit(this.values, (_, handle) => {
return this.hiddenFields[handle];
});
},

}

}
4 changes: 3 additions & 1 deletion resources/js/components/entries/PublishForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -257,11 +257,13 @@ import PublishActions from './PublishActions';
import SaveButtonOptions from '../publish/SaveButtonOptions';
import RevisionHistory from '../revision-history/History';
import HasPreferences from '../data-list/HasPreferences';
import HasHiddenFields from '../data-list/HasHiddenFields';
export default {
mixins: [
HasPreferences,
HasHiddenFields,
],
components: {
Expand Down Expand Up @@ -464,7 +466,7 @@ export default {
performSaveRequest() {
// Once the hook has completed, we need to make the actual request.
// We build the payload here because the before hook may have modified values.
const payload = { ...this.values, ...{
const payload = { ...this.visibleValues, ...{
_blueprint: this.fieldset.handle,
_localized: this.localizedFields,
}};
Expand Down
15 changes: 11 additions & 4 deletions resources/js/components/field-conditions/Converter.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { OPERATORS, ALIASES } from './Constants.js';
import map from 'underscore/modules/map.js'
import each from 'underscore/modules/each.js'
import filter from 'underscore/modules/filter.js'
import chain from 'underscore/modules/chain.js'
import chainable from 'underscore/modules/mixin.js'

chainable({ chain, filter, each });

export default class {

fromBlueprint(conditions, prefix=null) {
return _.map(conditions, (condition, field) => this.splitRhs(field, condition, prefix));
return map(conditions, (condition, field) => this.splitRhs(field, condition, prefix));
}

toBlueprint(conditions) {
let converted = {};

_.each(conditions, condition => {
each(conditions, condition => {
converted[condition.field] = this.combineRhs(condition);
});

Expand All @@ -35,7 +42,7 @@ export default class {
getOperatorFromRhs(condition) {
let operator = '==';

_.chain(this.getOperatorsAndAliases())
chain(this.getOperatorsAndAliases())
.filter(value => new RegExp(`^${value} [^=]`).test(this.normalizeConditionString(condition)))
.each(value => operator = value);

Expand All @@ -51,7 +58,7 @@ export default class {
getValueFromRhs(condition) {
let rhs = this.normalizeConditionString(condition);

_.chain(this.getOperatorsAndAliases())
chain(this.getOperatorsAndAliases())
.filter(value => new RegExp(`^${value} [^=]`).test(rhs))
.each(value => rhs = rhs.replace(new RegExp(`^${value}[ ]*`), ''));

Expand Down
Loading

0 comments on commit 4632bbf

Please sign in to comment.