Skip to content

Commit 11aa3fb

Browse files
authored
[6.x] Publish forms (#11787)
1 parent 976fe58 commit 11aa3fb

63 files changed

Lines changed: 2604 additions & 1823 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

resources/js/bootstrap/statamic.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import Echo from '../components/Echo';
3232
import Permission from '../components/Permission';
3333
import autosize from 'autosize';
3434
import DateFormatter from '@statamic/components/DateFormatter.js';
35+
import wait from '@statamic/util/wait.js';
3536

3637
let bootingCallbacks = [];
3738
let bootedCallbacks = [];
@@ -110,6 +111,18 @@ export default {
110111
return this.$app.config.globalProperties.$theme;
111112
},
112113

114+
get $fieldActions() {
115+
return this.$app.config.globalProperties.$fieldActions;
116+
},
117+
118+
get $dirty() {
119+
return this.$app.config.globalProperties.$dirty;
120+
},
121+
122+
get $events() {
123+
return this.$app.config.globalProperties.$events;
124+
},
125+
113126
get user() {
114127
return this.$config.get('user');
115128
},
@@ -189,9 +202,7 @@ export default {
189202
return permissions.includes('super') || permissions.includes(permission);
190203
},
191204
$wait(ms) {
192-
return new Promise((resolve) => {
193-
setTimeout(resolve, ms);
194-
});
205+
return wait(ms);
195206
},
196207
});
197208

resources/js/components/entries/PublishForm.vue

Lines changed: 167 additions & 293 deletions
Large diffs are not rendered by default.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import Validator from '@statamic/components/field-conditions/Validator.js';
2+
import { data_get } from '@statamic/bootstrap/globals.js';
3+
import { nextTick } from 'vue';
4+
5+
export default class {
6+
constructor(store, values, extraValues) {
7+
this.store = store;
8+
this.values = values;
9+
this.extraValues = extraValues;
10+
}
11+
12+
showField(field, dottedKey) {
13+
let dottedFieldPath = dottedKey || field.handle;
14+
let dottedPrefix = dottedKey ? dottedKey.replace(new RegExp('\.' + field.handle + '$'), '') : '';
15+
16+
// If we know the field is to permanently hidden, bypass validation.
17+
if (field.visibility === 'hidden' || this.shouldForceHiddenField(dottedFieldPath)) {
18+
this.setHiddenFieldState({
19+
dottedKey: dottedFieldPath,
20+
hidden: 'force',
21+
omitValue: false,
22+
});
23+
24+
return false;
25+
}
26+
27+
// Use validation to determine whether field should be shown.
28+
let validator = new Validator(field, { ...this.values, ...this.extraValues }, dottedFieldPath, this.store);
29+
let passes = validator.passesConditions();
30+
31+
// If the field is configured to always save, never omit value.
32+
if (field.always_save === true) {
33+
this.setHiddenFieldState({
34+
dottedKey: dottedFieldPath,
35+
hidden: !passes,
36+
omitValue: false,
37+
});
38+
39+
return passes;
40+
}
41+
42+
// Ensure DOM is updated to ensure all revealers are properly loaded and tracked before committing to store.
43+
nextTick(() => {
44+
this.setHiddenFieldState({
45+
dottedKey: dottedFieldPath,
46+
hidden: !passes,
47+
omitValue: field.type === 'revealer' || !validator.passesNonRevealerConditions(dottedPrefix),
48+
});
49+
});
50+
51+
return passes;
52+
}
53+
54+
setHiddenFieldState({ dottedKey, hidden, omitValue }) {
55+
const currentValue = this.store.hiddenFields[dottedKey];
56+
57+
// Prevent infinite loops
58+
if (currentValue && currentValue.hidden === hidden && currentValue.omitValue === omitValue) {
59+
return;
60+
}
61+
62+
this.store.setHiddenField({
63+
dottedKey,
64+
hidden,
65+
omitValue,
66+
});
67+
}
68+
69+
shouldForceHiddenField(dottedFieldPath) {
70+
return data_get(this.store.hiddenFields[dottedFieldPath], 'hidden') === 'force';
71+
}
72+
}
Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,11 @@
1-
import Validator from './Validator.js';
2-
import { data_get } from '../../bootstrap/globals.js';
1+
import ShowField from './ShowField.js';
32

43
export default {
5-
inject: ['publishContainer'],
4+
inject: ['store'],
65

76
methods: {
87
showField(field, dottedKey) {
9-
let dottedFieldPath = dottedKey || field.handle;
10-
let dottedPrefix = dottedKey ? dottedKey.replace(new RegExp('\.' + field.handle + '$'), '') : '';
11-
12-
// If we know the field is to permanently hidden, bypass validation.
13-
if (field.visibility === 'hidden' || this.shouldForceHiddenField(dottedFieldPath)) {
14-
this.setHiddenFieldState({
15-
dottedKey: dottedFieldPath,
16-
hidden: 'force',
17-
omitValue: false,
18-
});
19-
20-
return false;
21-
}
22-
23-
// Use validation to determine whether field should be shown.
24-
let validator = new Validator(
25-
field,
26-
{ ...this.values, ...this.extraValues },
27-
dottedFieldPath,
28-
this.publishContainer.store,
29-
);
30-
let passes = validator.passesConditions();
31-
32-
// If the field is configured to always save, never omit value.
33-
if (field.always_save === true) {
34-
this.setHiddenFieldState({
35-
dottedKey: dottedFieldPath,
36-
hidden: !passes,
37-
omitValue: false,
38-
});
39-
40-
return passes;
41-
}
42-
43-
// Ensure DOM is updated to ensure all revealers are properly loaded and tracked before committing to store.
44-
this.$nextTick(() => {
45-
this.setHiddenFieldState({
46-
dottedKey: dottedFieldPath,
47-
hidden: !passes,
48-
omitValue: field.type === 'revealer' || !validator.passesNonRevealerConditions(dottedPrefix),
49-
});
50-
});
51-
52-
return passes;
53-
},
54-
55-
setHiddenFieldState({ dottedKey, hidden, omitValue }) {
56-
const currentValue = this.publishContainer.store.hiddenFields[dottedKey];
57-
58-
// Prevent infinite loops
59-
if (currentValue && currentValue.hidden === hidden && currentValue.omitValue === omitValue) {
60-
return;
61-
}
62-
63-
this.publishContainer.store.setHiddenField({
64-
dottedKey,
65-
hidden,
66-
omitValue,
67-
});
68-
},
69-
70-
shouldForceHiddenField(dottedFieldPath) {
71-
return data_get(this.publishContainer.store.hiddenFields[dottedFieldPath], 'hidden') === 'force';
8+
return new ShowField(this.store, this.values, this.extraValues).showField(field, dottedKey);
729
},
7310
},
7411
};

resources/js/components/fieldtypes/Fieldtype.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ export default {
4848
},
4949
namePrefix: String,
5050
fieldPathPrefix: String,
51+
metaPathPrefix: String,
52+
id: String,
5153
},
5254
5355
methods: {
@@ -95,9 +97,7 @@ export default {
9597
},
9698
9799
fieldId() {
98-
let prefix = this.fieldPathPrefix ? this.fieldPathPrefix + '.' : '';
99-
100-
return prefix + 'field_' + this.config.handle;
100+
return this.id;
101101
},
102102
103103
fieldActionPayload() {

resources/js/components/fieldtypes/GroupFieldtype.vue

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,14 @@
1010
>
1111
</publish-field-fullscreen-header>
1212
<section :class="{ 'mt-14 p-4': fullScreenMode }">
13-
<div :class="{ 'replicator-set rounded-sm border shadow-sm dark:border-dark-900': config.border }">
14-
<div
15-
class="publish-fields @container"
16-
:class="{ 'replicator-set-body': config.border, '-mx-4': !config.border }"
13+
<div :class="{ 'replicator-set dark:border-dark-900 rounded-sm border shadow-sm': config.border }">
14+
<FieldsProvider
15+
:fields="fields"
16+
:field-path-prefix="fieldPathPrefix || handle"
17+
:meta-path-prefix="metaPathPrefix || handle"
1718
>
18-
<set-field
19-
v-for="field in fields"
20-
:key="field.handle"
21-
v-show="showField(field, fieldPath(field.handle))"
22-
:field="field"
23-
:meta="meta[field.handle]"
24-
:value="value[field.handle]"
25-
:parent-name="name"
26-
:set-index="0"
27-
:errors="errors(field.handle)"
28-
:field-path="fieldPath(field.handle)"
29-
:read-only="isReadOnly"
30-
:show-field-previews="config.replicator_preview"
31-
@updated="updated(field.handle, $event)"
32-
@meta-updated="updateMeta(field.handle, $event)"
33-
@focus="$emit('focus')"
34-
@blur="$emit('blur')"
35-
@replicator-preview-updated="previewUpdated(field.handle, $event)"
36-
/>
37-
</div>
19+
<Fields class="p-4" />
20+
</FieldsProvider>
3821
</div>
3922
</section>
4023
</div>
@@ -56,19 +39,19 @@
5639

5740
<script>
5841
import Fieldtype from './Fieldtype.vue';
59-
import SetField from './replicator/Field.vue';
6042
import { ValidatesFieldConditions } from '../field-conditions/FieldConditions.js';
6143
import ManagesPreviewText from './replicator/ManagesPreviewText';
44+
import Fields from '@statamic/components/ui/Publish/Fields.vue';
45+
import FieldsProvider from '@statamic/components/ui/Publish/FieldsProvider.vue';
6246
6347
export default {
6448
mixins: [Fieldtype, ValidatesFieldConditions, ManagesPreviewText],
65-
components: { SetField },
49+
components: { Fields, FieldsProvider },
6650
data() {
6751
return {
6852
containerWidth: null,
6953
focused: false,
7054
fullScreenMode: false,
71-
previews: {},
7255
provide: {
7356
group: this.makeGroupProvide(),
7457
},
@@ -85,6 +68,9 @@ export default {
8568
fields() {
8669
return this.config.fields;
8770
},
71+
previews() {
72+
return data_get(this.store.previews, this.fieldPathPrefix || this.handle) || {};
73+
},
8874
replicatorPreview() {
8975
if (!this.showFieldPreviews || !this.config.replicator_preview) return;
9076
@@ -152,10 +138,6 @@ export default {
152138
this.$emit('meta-updated', { ...this.meta, [handle]: value });
153139
},
154140
155-
previewUpdated(handle, value) {
156-
this.previews = { ...this.previews, [handle]: value };
157-
},
158-
159141
fieldPath(handle) {
160142
return (this.fieldPathPrefix || this.handle) + '.' + handle;
161143
},

resources/js/components/fieldtypes/SlugFieldtype.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
:id="fieldId"
1919
:isReadOnly="isReadOnly"
2020
:name="slug"
21+
:disabled="isReadOnly"
2122
@focus="$emit('focus')"
2223
@blur="$emit('blur')"
2324
>

resources/js/components/fieldtypes/TextFieldtype.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
:autocomplete="config.autocomplete"
88
:autoselect="config.autoselect"
99
:type="config.input_type"
10-
:isReadOnly="isReadOnly"
10+
:disabled="isReadOnly"
1111
:prepend="__(config.prepend)"
1212
:append="__(config.append)"
1313
:limit="config.character_limit"
1414
:placeholder="__(config.placeholder)"
1515
:name="name"
16-
:id="fieldId"
16+
:id="id"
1717
:direction="config.direction"
1818
@update:model-value="inputUpdated"
1919
@focus="$emit('focus')"

0 commit comments

Comments
 (0)