Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion assets/js/app/editor/Components/Date.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
:form="form"
:name="name"
placeholder="Select date"
:data-errormessage="errormessage"
:data-errormessage="optionalAttribute(errormessage)"
>
</flat-pickr>
<button
Expand Down Expand Up @@ -46,6 +46,7 @@
import $ from 'jquery';
import value from '../mixins/value';
import flatPickr from 'vue-flatpickr-component';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorDate',
Expand Down Expand Up @@ -124,6 +125,7 @@ export default {
},

methods: {
optionalAttribute,
fixRequired() {
if (!this.required) {
return;
Expand Down
9 changes: 7 additions & 2 deletions assets/js/app/editor/Components/Email.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@
type="email"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
:placeholder="placeholder"
/>
</div>
</div>
</template>

<script>
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorEmail',
props: {
Expand All @@ -45,5 +47,8 @@ export default {
},
placeholder: String | Boolean,
},
methods: {
optionalAttribute,
},
};
</script>
6 changes: 4 additions & 2 deletions assets/js/app/editor/Components/Embed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
type="url"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
/>
<span class="input-group-append">
<button
Expand Down Expand Up @@ -112,6 +112,7 @@
import _ from 'lodash';
import baguetteBox from 'baguettebox.js';
import field from '../mixins/value';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorEmbed',
Expand Down Expand Up @@ -172,6 +173,7 @@ export default {
});
},
methods: {
optionalAttribute,
updateEmbed: function () {
this.loading = true;
this.debouncedFetchEmbed();
Expand Down
6 changes: 4 additions & 2 deletions assets/js/app/editor/Components/File.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
:value="filenameData"
data-readonly="readonly"
:required="required"
:data-errormessage="errormessage"
:data-errormessage="optionalAttribute(errormessage)"
/>
</div>
<div class="input-group mb-3">
Expand All @@ -30,7 +30,7 @@
type="text"
:required="required"
:readonly="readonly"
:pattern="pattern"
:pattern="optionalAttribute(pattern)"
:placeholder="getPlaceholder"
/>
</div>
Expand Down Expand Up @@ -149,6 +149,7 @@ import Axios from 'axios';
import { renable } from '../../patience-is-a-virtue';
import { resetModalContent } from '../../modal';
import { Modal } from 'bootstrap';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorFile',
Expand Down Expand Up @@ -202,6 +203,7 @@ export default {
},
},
methods: {
optionalAttribute,
onMoveFileDown() {
this.$emit('move-file-down', this);
},
Expand Down
6 changes: 4 additions & 2 deletions assets/js/app/editor/Components/Image.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
:value="filenameData"
data-readonly="readonly"
:required="required"
:data-errormessage="errormessage"
:data-errormessage="optionalAttribute(errormessage)"
/>
</div>
<div v-if="includeAlt" class="input-group mb-3">
Expand All @@ -45,7 +45,7 @@
:name="name + '[alt]'"
type="text"
:readonly="readonly"
:pattern="pattern"
:pattern="optionalAttribute(pattern)"
:placeholder="getPlaceholder"
/>
</div>
Expand Down Expand Up @@ -198,6 +198,7 @@ import Axios from 'axios';
import { Modal } from 'bootstrap';
import { renable } from '../../patience-is-a-virtue';
import { resetModalContent } from '../../modal';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorImage',
Expand Down Expand Up @@ -276,6 +277,7 @@ export default {
});
},
methods: {
optionalAttribute,
resetImage() {
if (!this.filenameData) {
this.previewImage = null;
Expand Down
8 changes: 6 additions & 2 deletions assets/js/app/editor/Components/Number.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
:max="max"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
:placeholder="placeholder"
/>
</div>
</template>

<script>
import val from '../mixins/value';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorNumber',
Expand All @@ -39,5 +40,8 @@ export default {
pattern: String | Boolean,
placeholder: String | Boolean,
},
methods: {
optionalAttribute,
},
};
</script>
6 changes: 4 additions & 2 deletions assets/js/app/editor/Components/Password.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
:value="value"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
:placeholder="placeholder"
autocomplete="new-password"
@input="measureStrength"
Expand All @@ -28,6 +28,7 @@
<script>
import ProgressBar from './ProgressBar';
import $ from 'jquery';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorPassword',
Expand Down Expand Up @@ -60,6 +61,7 @@ export default {
},

methods: {
optionalAttribute,
togglePassword(event) {
const iconElement = event.target;
const inputElement = $('#' + this.id)[0];
Expand Down
4 changes: 3 additions & 1 deletion assets/js/app/editor/Components/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
:show-labels="false"
:taggable="taggable"
:disabled="readonly"
:data-errormessage="errormessage"
:data-errormessage="optionalAttribute(errormessage)"
label="value"
tag-placeholder="Add this as new tag"
tag-position="bottom"
Expand Down Expand Up @@ -81,6 +81,7 @@
import Multiselect from 'vue-multiselect';
import $ from 'jquery';
import { raw } from '../../../filters/string';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorSelect',
Expand Down Expand Up @@ -182,6 +183,7 @@ export default {
}
},
methods: {
optionalAttribute,
raw,
addTag(newTag) {
const tag = {
Expand Down
6 changes: 4 additions & 2 deletions assets/js/app/editor/Components/Slug.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
:class="fieldClass"
:readonly="readonly || !edit"
:required="required"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
:title="name"
/>
<div class="input-group-append">
Expand Down Expand Up @@ -53,6 +53,7 @@
<script>
import field from '../mixins/value';
import { slugify } from '../../../filters/string';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorSlug',
Expand Down Expand Up @@ -95,6 +96,7 @@ export default {
this.$root.$on('slugify-from-title', () => this.generateSlug());
},
methods: {
optionalAttribute,
shouldGenerateFromTitle(title) {
return this.isNew ? true : title.length <= 0 && this.localize;
},
Expand Down
8 changes: 6 additions & 2 deletions assets/js/app/editor/Components/Text.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
:disabled="disabled"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:pattern="pattern"
:data-errormessage="optionalAttribute(errormessage)"
:pattern="optionalAttribute(pattern)"
:placeholder="placeholder"
:autofocus="autofocus == true"
/>
Expand All @@ -21,6 +21,7 @@

<script>
import field from '../mixins/value';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorText',
Expand Down Expand Up @@ -62,5 +63,8 @@ export default {
mounted() {
this.$root.$on('generate-from-title', data => (this.generate = data));
},
methods: {
optionalAttribute,
},
};
</script>
6 changes: 5 additions & 1 deletion assets/js/app/editor/Components/Textarea.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:rows="rows"
:required="required"
:readonly="readonly"
:data-errormessage="errormessage"
:data-errormessage="optionalAttribute(errormessage)"
:placeholder="placeholder"
:style="{ height: styleHeight }"
:maxlength="maxlength"
Expand All @@ -19,6 +19,7 @@

<script>
import field from '../mixins/value';
import { optionalAttribute } from '../utils/attributes';

export default {
name: 'EditorTextarea',
Expand All @@ -42,5 +43,8 @@ export default {
styleHeight: isNaN(this.height) ? this.height : false,
};
},
methods: {
optionalAttribute,
},
};
</script>
11 changes: 11 additions & 0 deletions assets/js/app/editor/utils/attributes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Twig passes `false` for an unset field option, such as a pattern or an error
* message. Vue 2 drops a non-boolean attribute bound to `false`, but Vue 3
* renders it as "false"; `undefined` drops it in both. Every other value is
* returned as it is.
*
* @see https://v3-migration.vuejs.org/breaking-changes/attribute-coercion.html
*/
export function optionalAttribute<T>(value: T | false): T | undefined {
return value === false ? undefined : value;
}
2 changes: 1 addition & 1 deletion tests/unit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ regression baseline rather than a round of manual clicking.
app/ the non-component scripts (common, ajax-save, modal,
notifications, patience-is-a-virtue, save-on-ctrl-s)
components/ the SFCs, mirroring assets/js/app/
filters/ services/ store/ mixins/
filters/ services/ store/ mixins/ utils/

## Notes for the Vue 3 upgrade

Expand Down
9 changes: 9 additions & 0 deletions tests/unit/components/Date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,13 @@ describe('EditorDate', () => {
// from updated(), so an empty required field can flash the browser's
// "please fill in this field" popup before the user has touched it.
it.todo('does not surface the native validation popup on mount');

it('hands the error message to the picker only when there is one', async () => {
const withMessage = mountDate();
const without = mountDate({ errormessage: false });
await nextTick();

expect(submitted(withMessage).attributes('data-errormessage')).toBe('Pick a date');
expect(submitted(without).attributes('data-errormessage')).toBeUndefined();
});
});
10 changes: 10 additions & 0 deletions tests/unit/components/Email.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,14 @@ describe('EditorEmail', () => {

expect(wrapper.find('input').attributes('readonly')).toBeDefined();
});

it('omits the error message and pattern when they are false', () => {
const wrapper = mount(Email, {
propsData: { value: '', name: 'fields[email]', errormessage: false, pattern: false },
});

const input = wrapper.find('input');
expect(input.attributes('data-errormessage')).toBeUndefined();
expect(input.attributes('pattern')).toBeUndefined();
});
});
7 changes: 7 additions & 0 deletions tests/unit/components/Embed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,11 @@ describe('EditorEmbed', () => {
expect(wrapper.find('input[name="fields[video][width]"]').attributes('readonly')).toBeDefined();
expect(wrapper.find('button.remove').attributes('disabled')).toBeUndefined();
});

it('omits the error message and pattern when they are false', () => {
const wrapper = mountEmbed({ errormessage: false, pattern: false });

expect(urlInput(wrapper).attributes('data-errormessage')).toBeUndefined();
expect(urlInput(wrapper).attributes('pattern')).toBeUndefined();
});
});
Loading
Loading