-
- Loading...
-
+ data: () => ({loading: true, text: ''}),
+ template: `
+
+ Loading...
-
{{ text }}
- `,
+
+
{{ text }} `,
async created() {
const cacheKey = `${this.reference}_${this.value}_${this.autocomplete}`;
const cached = JSON.parse(localStorage.getItem(cacheKey) || 'null');
@@ -40,360 +35,417 @@ Vue.component('tt-resolver', {
}
});
-
-Vue.component('tt-positions-manager',
- {
- props: {
- value: {type: [Array, String], required: false},
- config: {type: Object, required: true},
- groupMode: {type: Boolean, default: false},
- submitLoading: {type: Boolean, default: false}
- },
- data() {
- return {
- window: window,
- positions: this.value,
- formData: {},
- groupName: '',
- selectedIndex: null,
- editingGroupName: null,
- tempGroupName: '',
- }
- },
- template: `
-
-
- {{ config["header"] }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ field.label }}
- Aktionen
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ groupName }}
-
-
-
-
-
-
-
-
-
-
-
- {{ position[key] ? 'Ja' : 'Nein' }}
- {{ formatFieldValue(position[key] ?? position[key + '_text'], field) }}
-
-
-
- {{ group }}
-
-
-
-
-
-
-
-
-
-
-
- `,
- methods: {
- updateField(key, value) {
- this.$set(this.formData, key, value);
- },
- defaultValidateForm(formData) {
- for (const field of this.config["validateFormOptions"]) {
- if (!(formData[field.key] || formData[field.key + '_text'])) {
- window.notify('error', field.message);
- return false;
- }
- }
- return true;
- },
- checkEmitDisplayValueAutocomplete() {
- for (const [key, field] of Object.entries(this.config.fields)) {
- if ((typeof field.showCondition === 'function' && field.showCondition(this.formData) === true || !field.showCondition) && field.type === 'autocomplete' && field.emitDisplayValue && (isNaN(this.formData[key]) || !this.formData[key]) && this.$refs['autocomplete-' + key][0]) {
- this.$set(this.formData, key + '_text', this.$refs['autocomplete-' + key][0].displayValue);
- this.$delete(this.formData, key);
- }
-
- if ((typeof field.showCondition === 'function' && field.showCondition(this.formData) === true || !field.showCondition) && field.type === 'input-article' && field.emitDisplayValue && (isNaN(this.formData[key]) || !this.formData[key]) && this.$refs['article-' + key][0]) {
- console.log(this.$refs['article-' + key][0].$refs.autocomplete);
- this.$set(this.formData, key + '_text', this.$refs['article-' + key][0].$refs.autocomplete.displayValue);
- this.$delete(this.formData, key);
- }
-
- if (field.emitDisplayValue && this.formData[key] !== null && this.formData[key] !== undefined) {
- this.$delete(this.formData, key + '_text');
- }
-
- }
- },
- async saveEntry() {
- this.checkEmitDisplayValueAutocomplete();
- if (this.config.hasOwnProperty('validateFormOptions') && !this.defaultValidateForm(this.formData)) return;
- else if (this.config.validateForm && !await this.config.validateForm(this.formData)) return;
-
- if (this.selectedIndex === null) this.positions.push(this.formData);
- else this.$set(this.positions, this.selectedIndex, this.formData);
-
- if (this.config.customOrdering) {
- this.positions.sort((a, b) => a[this.config.customOrdering] - b[this.config.customOrdering]);
- }
-
- this.$emit('input', this.positions);
- this.resetForm();
- },
- addGroup() {
- this.positions.push({_group: this.groupName});
- this.groupName = '';
- },
- startGroupEdit(groupName) {
- this.editingGroupName = groupName;
- this.tempGroupName = groupName;
- },
- saveGroupName(oldGroupName) {
- if (this.tempGroupName.trim() === '') {
- window.notify('error', 'Gruppenname darf nicht leer sein');
- return;
- }
-
- if (this.tempGroupName !== oldGroupName) {
- // Update all positions with the old group name to the new group name
- this.positions.forEach(position => {
- if (position._group === oldGroupName) {
- this.$set(position, '_group', this.tempGroupName);
- }
- });
- this.$emit('input', this.positions);
- }
-
- this.editingGroupName = null;
- this.tempGroupName = '';
- },
- cancelGroupEdit() {
- this.editingGroupName = null;
- this.tempGroupName = '';
- },
- deleteGroup(groupName) {
- if (confirm(`Möchten Sie die Gruppe "${groupName}" wirklich löschen? Alle Einträge werden in "Keine Gruppe" verschoben.`)) {
- // Move all items from this group to "Keine Gruppe" and remove empty group entries
- this.positions = this.positions.filter(position => {
- if (position._group === groupName) {
- // If it's just a group header (only has _group property), remove it
- if (Object.keys(position).length === 1) {
- return false;
- }
- // Otherwise, move to "Keine Gruppe"
- this.$set(position, '_group', 'Keine Gruppe');
- }
- return true;
- });
- this.$emit('input', this.positions);
- }
- },
- getActualIndex(position, groupName, groupIndex) {
- // Find the actual index in the positions array
- if (!this.groupMode) return groupIndex;
-
- let actualIndex = 0;
- let currentGroupIndex = 0;
-
- for (let i = 0; i < this.positions.length; i++) {
- const pos = this.positions[i];
- const posGroup = pos._group ?? 'Keine Gruppe';
-
- if (posGroup === groupName && Object.keys(pos).length > 1) {
- if (currentGroupIndex === groupIndex) {
- return i;
- }
- currentGroupIndex++;
- }
- }
-
- return groupIndex; // Fallback
- },
- async editEntry(index) {
- this.selectedIndex = index;
- for (const [key, field] of Object.entries(this.config.fields)) {
- if (field.type === 'autocomplete' && field.emitDisplayValue) {
- await this.$nextTick();
- if (this.positions[index][key + '_text'] && this.$refs['autocomplete-' + key][0]) {
- console.log('inhere');
- this.$refs['autocomplete-' + key][0].displayValue = this.positions[index][key + '_text'];
- this.$set(this.formData, key, this.positions[index][key]);
- }
- }
- }
- this.formData = {...this.positions[index]};
- },
- deleteEntry(index) {
- this.positions.splice(index, 1);
- this.$emit('input', this.positions);
- },
- resetForm() {
- this.formData = {};
- for (const [key, field] of Object.entries(this.config.fields)) {
- if (
- typeof field.showCondition === 'function' && field.showCondition(this.formData) === true &&
- field.type === 'autocomplete' && field.emitDisplayValue && this.$refs['autocomplete-' + key][0]) {
- this.$refs['autocomplete-' + key][0].displayValue = '';
- }
- if (field.inputType === 'date') {
- this.$set(this.formData, key, moment().format('YYYY-MM-DD'));
- }
- }
- this.selectedIndex = null;
- },
- formatFieldValue(value, field) {
- if (field.formatter) return field.formatter(value);
- if (field.inputType === 'date') return moment(value).format('DD.MM.YYYY');
- return value;
- },
- },
- //TODO: cleanup
- created() {
- if (this.config["customMethods"]) Object.assign(this, this.config.customMethods);
- if (!this.positions) this.positions = [];
- if (typeof this.positions === 'string') {
- try {
- this.positions = JSON.parse(this.positions);
- } catch (e) {
- console.error(e);
- this.positions = [];
- }
- }
- },
- mounted() {
- this.resetForm();
- },
- computed: {
- groupedPositions() {
- const groups = {};
- for (const position of this.positions) {
- const group = position._group ?? 'Keine Gruppe';
- if (!groups[group]) groups[group] = [];
- if (Object.keys(position).length !== 1) groups[group].push(position);
- }
- return groups;
- },
- positionsToRender() {
- return this.groupMode ? this.groupedPositions : {'': this.positions};
- },
- allGroups() {
- return Object.keys(this.groupedPositions);
- }
- },
- watch: {
- value: {
- handler() {
- this.positions = this.value;
- },
- deep: true
+Vue.component('tt-positions-manager', {
+ props: {
+ value: {type: [Array, String], required: false},
+ config: {type: Object, required: true},
+ groupMode: {type: Boolean, default: false},
+ submitLoading: {type: Boolean, default: false}
+ },
+ data() {
+ return {
+ window: window,
+ positions: this.value,
+ formData: {},
+ groupName: '',
+ selectedIndex: null,
+ editingGroupName: null,
+ tempGroupName: '',
+ // New state for instant editing
+ editingCell: {
+ groupName: null, // For grouped positions
+ index: null, // Index within the group or flat array
+ key: null // Field key being edited
}
}
- })
+ },
+ template: `
+
+
+ {{ config["header"] }}
+
+
+
+
+
+
+
+
+
+
+
+ `,
+ methods: {
+ updateField(key, value) {
+ this.$set(this.formData, key, value);
+ },
+ defaultValidateForm(formData) {
+ for (const field of this.config["validateFormOptions"]) {
+ if (!(formData[field.key] || formData[field.key + '_text'])) {
+ window.notify('error', field.message);
+ return false;
+ }
+ }
+ return true;
+ },
+ checkEmitDisplayValueAutocomplete() {
+ for (const [key, field] of Object.entries(this.config.fields)) {
+ if ((typeof field.showCondition === 'function' && field.showCondition(this.formData) === true || !field.showCondition) && field.type === 'autocomplete' && field.emitDisplayValue && (isNaN(this.formData[key]) || !this.formData[key]) && this.$refs['autocomplete-' + key][0]) {
+ this.$set(this.formData, key + '_text', this.$refs['autocomplete-' + key][0].displayValue);
+ this.$delete(this.formData, key);
+ }
+
+ if ((typeof field.showCondition === 'function' && field.showCondition(this.formData) === true || !field.showCondition) && field.type === 'input-article' && field.emitDisplayValue && (isNaN(this.formData[key]) || !this.formData[key]) && this.$refs['article-' + key][0]) {
+ console.log(this.$refs['article-' + key][0].$refs.autocomplete);
+ this.$set(this.formData, key + '_text', this.$refs['article-' + key][0].$refs.autocomplete.displayValue);
+ this.$delete(this.formData, key);
+ }
+
+ if (field.emitDisplayValue && this.formData[key] !== null && this.formData[key] !== undefined) {
+ this.$delete(this.formData, key + '_text');
+ }
+
+ }
+ },
+ async saveEntry() {
+ this.checkEmitDisplayValueAutocomplete();
+ if (this.config.hasOwnProperty('validateFormOptions') && !this.defaultValidateForm(this.formData)) return;
+ else if (this.config.validateForm && !await this.config.validateForm(this.formData)) return;
+
+ if (this.selectedIndex === null) this.positions.push(this.formData);
+ else this.$set(this.positions, this.selectedIndex, this.formData);
+
+ if (this.config.customOrdering) {
+ this.positions.sort((a, b) => a[this.config.customOrdering] - b[this.config.customOrdering]);
+ }
+
+ this.$emit('input', this.positions);
+ this.resetForm();
+ },
+ addGroup() {
+ this.positions.push({_group: this.groupName});
+ this.groupName = '';
+ },
+ startGroupEdit(groupName) {
+ this.editingGroupName = groupName;
+ this.tempGroupName = groupName;
+ },
+ saveGroupName(oldGroupName) {
+ if (this.tempGroupName.trim() === '') {
+ window.notify('error', 'Gruppenname darf nicht leer sein');
+ return;
+ }
+
+ if (this.tempGroupName !== oldGroupName) {
+ // Update all positions with the old group name to the new group name
+ this.positions.forEach(position => {
+ if (position._group === oldGroupName) {
+ this.$set(position, '_group', this.tempGroupName);
+ }
+ });
+ this.$emit('input', this.positions);
+ }
+
+ this.editingGroupName = null;
+ this.tempGroupName = '';
+ },
+ cancelGroupEdit() {
+ this.editingGroupName = null;
+ this.tempGroupName = '';
+ },
+ deleteGroup(groupName) {
+ if (confirm(`Möchten Sie die Gruppe "${groupName}" wirklich löschen? Alle Einträge werden in "Keine Gruppe" verschoben.`)) {
+ // Move all items from this group to "Keine Gruppe" and remove empty group entries
+ this.positions = this.positions.filter(position => {
+ if (position._group === groupName) {
+ // If it's just a group header (only has _group property), remove it
+ if (Object.keys(position).length === 1) {
+ return false;
+ }
+ // Otherwise, move to "Keine Gruppe"
+ this.$set(position, '_group', 'Keine Gruppe');
+ }
+ return true;
+ });
+ this.$emit('input', this.positions);
+ }
+ },
+ getActualIndex(position, groupName, groupIndex) {
+ // Find the actual index in the positions array
+ if (!this.groupMode) return groupIndex;
+
+ let actualIndex = 0;
+ let currentGroupIndex = 0;
+
+ for (let i = 0; i < this.positions.length; i++) {
+ const pos = this.positions[i];
+ const posGroup = pos._group ?? 'Keine Gruppe';
+
+ if (posGroup === groupName && Object.keys(pos).length > 1) {
+ if (currentGroupIndex === groupIndex) {
+ return i;
+ }
+ currentGroupIndex++;
+ }
+ }
+
+ return groupIndex; // Fallback
+ },
+ async editEntry(index) {
+ this.selectedIndex = index;
+ for (const [key, field] of Object.entries(this.config.fields)) {
+ if (field.type === 'autocomplete' && field.emitDisplayValue) {
+ await this.$nextTick();
+ if (this.positions[index][key + '_text'] && this.$refs['autocomplete-' + key][0]) {
+ console.log('inhere');
+ this.$refs['autocomplete-' + key][0].displayValue = this.positions[index][key + '_text'];
+ this.$set(this.formData, key, this.positions[index][key]);
+ }
+ }
+ }
+ this.formData = {...this.positions[index]};
+
+ // Scroll to the form container
+ this.$nextTick(() => {
+ this.$refs.formContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
+ });
+ },
+ deleteEntry(index) {
+ this.positions.splice(index, 1);
+ this.$emit('input', this.positions);
+ },
+ resetForm() {
+ this.formData = {};
+ for (const [key, field] of Object.entries(this.config.fields)) {
+ if (
+ typeof field.showCondition === 'function' && field.showCondition(this.formData) === true &&
+ field.type === 'autocomplete' && field.emitDisplayValue && this.$refs['autocomplete-' + key][0]) {
+ this.$refs['autocomplete-' + key][0].displayValue = '';
+ }
+ if (field.inputType === 'date') {
+ this.$set(this.formData, key, moment().format('YYYY-MM-DD'));
+ }
+ }
+ this.selectedIndex = null;
+ },
+ formatFieldValue(value, field) {
+ if (field.formatter) return field.formatter(value);
+ if (field.inputType === 'date') return moment(value).format('DD.MM.YYYY');
+ return value;
+ },
+ // New methods for instant editing
+ startCellEdit(groupName, index, key, field) {
+ if (!field.editableInTable || !(field.type === 'input' || field.type === 'textarea')) return;
+ this.editingCell = { groupName, index, key };
+ this.$nextTick(() => {
+ const inputElement = this.$el.querySelector(`.editable-cell input[type="${field.type}"], .editable-cell textarea`);
+ if (inputElement) {
+ inputElement.focus();
+ }
+ });
+ },
+ saveCellEdit(position, key, groupName, index) {
+ this.editingCell = { groupName: null, index: null, key: null };
+ // Ensure data is updated in the original positions array
+ const actualIndex = this.getActualIndex(position, groupName, index);
+ this.$set(this.positions, actualIndex, position);
+ this.$emit('input', this.positions);
+ },
+ isCellEditing(groupName, index, key) {
+ return this.editingCell.groupName === groupName &&
+ this.editingCell.index === index &&
+ this.editingCell.key === key;
+ }
+ },
+ //TODO: cleanup
+ created() {
+ if (this.config["customMethods"]) Object.assign(this, this.config.customMethods);
+ if (!this.positions) this.positions = [];
+ if (typeof this.positions === 'string') {
+ try {
+ this.positions = JSON.parse(this.positions);
+ } catch (e) {
+ console.error(e);
+ this.positions = [];
+ }
+ }
+ },
+ mounted() {
+ this.resetForm();
+ },
+ computed: {
+ groupedPositions() {
+ const groups = {};
+ for (const position of this.positions) {
+ const group = position._group ?? 'Keine Gruppe';
+ if (!groups[group]) groups[group] = [];
+ if (Object.keys(position).length !== 1) groups[group].push(position);
+ }
+ return groups;
+ },
+ positionsToRender() {
+ return this.groupMode ? this.groupedPositions : {'': this.positions};
+ },
+ allGroups() {
+ return Object.keys(this.groupedPositions);
+ }
+ },
+ watch: {
+ value: {
+ handler() {
+ this.positions = this.value;
+ },
+ deep: true
+ }
+ }
+});
\ No newline at end of file