mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-04-23 04:35:02 +08:00
Add validation to label template code [SCI-7210]
This commit is contained in:
parent
e1ce81280e
commit
17bf490fef
5 changed files with 128 additions and 21 deletions
app
assets/stylesheets/label_templates
javascript/vue/label_template
config/locales
|
@ -29,6 +29,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.label-preview__error {
|
||||
background-color: $brand-danger-light;
|
||||
color: $brand-danger-hover;
|
||||
margin-top: .5em;
|
||||
padding: 1.5em 2em;
|
||||
}
|
||||
|
||||
.label-preview__controls {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -55,6 +55,24 @@
|
|||
|
||||
.label-textarea-container {
|
||||
height: calc(100% - 6em);
|
||||
|
||||
.label-textarea {
|
||||
height: 100%;
|
||||
margin-top: .5em;
|
||||
padding: .5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.error {
|
||||
.label-textarea {
|
||||
border: 1px solid $brand-danger;
|
||||
height: calc(100% - 2em);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: $brand-danger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label-edit-header {
|
||||
|
@ -115,13 +133,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.label-textarea {
|
||||
height: 100%;
|
||||
margin-top: .5em;
|
||||
padding: .5em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.inser-field-dropdown {
|
||||
.open-dropdown-button:not(.collapsed) {
|
||||
.fas {
|
||||
|
|
|
@ -51,6 +51,10 @@
|
|||
<div v-if="base64Image" class="label-preview__image">
|
||||
<img :src="`data:image/png;base64,${base64Image}`" />
|
||||
</div>
|
||||
<div class="label-preview__error" v-html="i18n.t('label_templates.label_preview.error_html')"
|
||||
v-else-if="base64Image != null && base64Image.length === 0">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -113,6 +117,9 @@
|
|||
}
|
||||
|
||||
this.setDefaults();
|
||||
},
|
||||
zpl() {
|
||||
this.refreshPreview();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -123,6 +130,8 @@
|
|||
!this.height && (this.height = this.unit === 'in' ? 1 : 25.4);
|
||||
},
|
||||
refreshPreview() {
|
||||
if (this.zpl.length === 0) return;
|
||||
|
||||
$.ajax({
|
||||
url: this.previewUrl,
|
||||
type: 'GET',
|
||||
|
@ -134,7 +143,17 @@
|
|||
},
|
||||
success: (result) => {
|
||||
this.base64Image = result.base64_preview;
|
||||
if (this.base64Image.length > 0) {
|
||||
this.$emit('preview:valid');
|
||||
} else {
|
||||
this.$emit('preview:invalid');
|
||||
}
|
||||
},
|
||||
error: (result) => {
|
||||
this.base64Image = '';
|
||||
this.$emit('preview:invalid');
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
updateUnit(unit) {
|
||||
|
|
|
@ -55,23 +55,26 @@
|
|||
/>
|
||||
</div>
|
||||
<template v-if="editingContent">
|
||||
<div class="label-textarea-container">
|
||||
<div class="label-textarea-container" :class="{'error': hasError }">
|
||||
<textarea
|
||||
ref="contentInput"
|
||||
v-model="newContent"
|
||||
class="label-textarea"
|
||||
@blur="updateContent"
|
||||
@blur="saveCursorPosition"
|
||||
></textarea>
|
||||
<div class="error-message">
|
||||
{{ codeErrorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="button-container">
|
||||
<div class="btn btn-secondary refresh-preview">
|
||||
<div class="btn btn-secondary refresh-preview" @click="generatePreview(true)">
|
||||
<i class="fas fa-sync"></i>
|
||||
{{ i18n.t('label_templates.show.buttons.refresh') }}
|
||||
</div>
|
||||
<div class="btn btn-secondary" @mousedown="disableContentEdit">
|
||||
{{ i18n.t('general.cancel') }}
|
||||
</div>
|
||||
<div class="btn btn-primary save-template" @click="updateContent">
|
||||
<div class="btn btn-primary save-template" :disabled="hasError && previewValid" @click="generatePreview(false)">
|
||||
<i class="fas fa-save"></i>
|
||||
{{ i18n.t('label_templates.show.buttons.save') }}
|
||||
</div>
|
||||
|
@ -83,7 +86,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="label-preview-container">
|
||||
<LabelPreview :zpl='labelTemplate.attributes.content' :previewUrl="previewUrl" />
|
||||
<LabelPreview :zpl='previewContent' :previewUrl="previewUrl" @preview:valid="updateContent" @preview:invalid="invalidPreview" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -112,14 +115,32 @@
|
|||
editingDescription: false,
|
||||
editingContent: false,
|
||||
newContent: '',
|
||||
previewContent: '',
|
||||
previewValid: false,
|
||||
skipSave: false,
|
||||
codeErrorMessage: '',
|
||||
cursorPos: 0
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
newContent() {
|
||||
this.showErrors();
|
||||
},
|
||||
previewValid() {
|
||||
this.showErrors();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hasError() {
|
||||
return this.codeErrorMessage.length > 0
|
||||
}
|
||||
},
|
||||
components: {InlineEdit, InsertFieldDropdown, LabelPreview},
|
||||
created() {
|
||||
$.get(this.labelTemplateUrl, (result) => {
|
||||
this.labelTemplate = result.data
|
||||
this.newContent = this.labelTemplate.attributes.content
|
||||
this.previewContent = this.labelTemplate.attributes.content
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
|
@ -134,6 +155,7 @@
|
|||
disableContentEdit() {
|
||||
this.editingContent = false;
|
||||
this.newContent = this.labelTemplate.attributes.content;
|
||||
this.previewContent = this.labelTemplate.attributes.content;
|
||||
},
|
||||
updateName(newName) {
|
||||
$.ajax({
|
||||
|
@ -156,23 +178,66 @@
|
|||
});
|
||||
},
|
||||
updateContent() {
|
||||
this.cursorPos = $(this.$refs.contentInput).prop('selectionStart');
|
||||
$.ajax({
|
||||
url: this.labelTemplate.attributes.urls.update,
|
||||
type: 'PATCH',
|
||||
data: {label_template: {content: this.newContent}},
|
||||
success: (result) => {
|
||||
this.labelTemplate.attributes.content = result.data.attributes.content;
|
||||
this.editingContent = false;
|
||||
}
|
||||
this.previewValid = true;
|
||||
|
||||
if (!this.editingContent) return;
|
||||
|
||||
if (this.skipSave) {
|
||||
this.skipSave = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.hasError) return;
|
||||
|
||||
$.ajax({
|
||||
url: this.labelTemplate.attributes.urls.update,
|
||||
type: 'PATCH',
|
||||
data: {label_template: {content: this.newContent}},
|
||||
success: (result) => {
|
||||
this.labelTemplate.attributes.content = result.data.attributes.content;
|
||||
this.editingContent = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
generatePreview(skipSave = false) {
|
||||
this.skipSave = skipSave;
|
||||
if (!skipSave && this.previewContent === this.newContent && this.previewValid) {
|
||||
this.updateContent();
|
||||
} else {
|
||||
this.previewContent = this.newContent;
|
||||
}
|
||||
|
||||
},
|
||||
invalidPreview() {
|
||||
this.previewValid = false;
|
||||
this.skipSave = false;
|
||||
},
|
||||
saveCursorPosition() {
|
||||
this.cursorPos = $(this.$refs.contentInput).prop('selectionStart');
|
||||
},
|
||||
insertField(field) {
|
||||
this.enableContentEdit();
|
||||
let textBefore = this.newContent.substring(0, this.cursorPos);
|
||||
let textAfter = this.newContent.substring(this.cursorPos, this.newContent.length);
|
||||
this.newContent = textBefore + field + textAfter;
|
||||
this.cursorPos = this.cursorPos + field.length;
|
||||
},
|
||||
showErrors() {
|
||||
if (this.editingContent) {
|
||||
if (this.newContent.length === 0) {
|
||||
this.codeErrorMessage = this.i18n.t('label_templates.show.code_errors.empty')
|
||||
} else if (this.newContent.length > 10000) {
|
||||
this.codeErrorMessage = this.i18n.t('label_templates.show.code_errors.too_long')
|
||||
} else if (!this.previewValid) {
|
||||
this.codeErrorMessage = this.i18n.t('label_templates.show.code_errors.invalid')
|
||||
} else {
|
||||
this.codeErrorMessage = ''
|
||||
}
|
||||
} else {
|
||||
this.codeErrorMessage = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -872,6 +872,10 @@ en:
|
|||
content_title: '%{format} template code'
|
||||
preview_title: 'Template preview'
|
||||
view_content_tooltip: 'Click to edit template code'
|
||||
code_errors:
|
||||
empty: 'ZPL template code cannot be empty'
|
||||
too_long: 'ZPL template code has exceeded the maximum of 10.000 characters'
|
||||
invalid: 'ZPL template code invalid'
|
||||
insert_dropdown:
|
||||
button: 'Insert field code'
|
||||
common_fields: 'Common custom fields'
|
||||
|
@ -896,6 +900,7 @@ en:
|
|||
refresh_preview: 'Refresh preview'
|
||||
mm: 'Millimeters (mm) 1 cm = 10 mm'
|
||||
in: 'Inches (in)'
|
||||
error_html: 'Label cannot be previewed:<br>the ZPL code might be invalid, or the preview generator is down. Please double-check your code, save it and reload the page.'
|
||||
promo:
|
||||
head_title: 'Label templates'
|
||||
promo_title: 'This feature is disabled by default in open source SciNote'
|
||||
|
|
Loading…
Add table
Reference in a new issue