forked from rc/aircox
		
	
		
			
				
	
	
		
			193 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
    <div>
 | 
						|
        <input type="hidden" :name="_prefix + 'TOTAL_FORMS'" :value="items.length || 0"/>
 | 
						|
        <template v-for="(value,name) in formData.management" v-bind:key="name">
 | 
						|
            <input type="hidden" :name="_prefix + name.toUpperCase()"
 | 
						|
                :value="value"/>
 | 
						|
        </template>
 | 
						|
 | 
						|
        <a-rows ref="rows" :set="set" :context="this"
 | 
						|
                :columns="visibleFields" :columnsOrderable="columnsOrderable"
 | 
						|
                :orderable="orderable" @move="moveItem" @colmove="onColumnMove"
 | 
						|
                @cell="e => $emit('cell', e)">
 | 
						|
 | 
						|
            <template #header-head>
 | 
						|
                <template v-if="orderable">
 | 
						|
                    <th style="max-width:2em" :title="orderField.label"
 | 
						|
                            :aria-label="orderField.label"
 | 
						|
                            :aria-description="orderField.help || ''">
 | 
						|
                        <span class="icon">
 | 
						|
                            <i class="fa fa-arrow-down-1-9"></i>
 | 
						|
                        </span>
 | 
						|
                    </th>
 | 
						|
                    <slot name="rows-header-head"></slot>
 | 
						|
                </template>
 | 
						|
            </template>
 | 
						|
 | 
						|
            <template #row-head="data">
 | 
						|
                <input v-if="orderable" type="hidden"
 | 
						|
                    :name="_prefix + data.row + '-' + orderBy"
 | 
						|
                    :value="data.row"/>
 | 
						|
                <input type="hidden" :name="_prefix + data.row + '-id'"
 | 
						|
                    :value="data.item ? data.item.id : ''"/>
 | 
						|
 | 
						|
                <template v-for="field of hiddenFields" v-bind:key="field.name">
 | 
						|
                    <input type="hidden"
 | 
						|
                        v-if="!(field.name in ['id', orderBy])"
 | 
						|
                        :name="_prefix + data.row + '-' + field.name"
 | 
						|
                        :value="field.value in [null, undefined] ? data.item.data[name] : field.value"/>
 | 
						|
                </template>
 | 
						|
 | 
						|
                <slot name="row-head" v-bind="data">
 | 
						|
                    <td v-if="orderable">{{ data.row+1 }}</td>
 | 
						|
                </slot>
 | 
						|
            </template>
 | 
						|
 | 
						|
            <template v-for="(field,slot) of fieldSlots" v-bind:key="field.name"
 | 
						|
                    v-slot:[slot]="data">
 | 
						|
                    <slot :name="slot" v-bind="data" :field="field" :input-name="_prefix + data.cell.row + '-' + field.name">
 | 
						|
                    <div class="field">
 | 
						|
                        <div class="control">
 | 
						|
                            <slot :name="'control-' + field.name" v-bind="data" :field="field" :input-name="_prefix + data.cell.row + '-' + field.name"/>
 | 
						|
                        </div>
 | 
						|
                        <p v-for="[error,index] in data.item.error(field.name)" class="help is-danger" v-bind:key="index">
 | 
						|
                            {{ error }}
 | 
						|
                        </p>
 | 
						|
                    </div>
 | 
						|
                </slot>
 | 
						|
            </template>
 | 
						|
 | 
						|
            <template #row-tail="data">
 | 
						|
                <slot v-if="$slots['row-tail']" name="row-tail" v-bind="data"/>
 | 
						|
                <td class="align-right pr-0">
 | 
						|
                    <button type="button" class="button square"
 | 
						|
                            @click.stop="removeItem(data.row, data.item)"
 | 
						|
                            :title="labels.remove_item"
 | 
						|
                            :aria-label="labels.remove_item">
 | 
						|
                        <span class="icon"><i class="fa fa-trash" /></span>
 | 
						|
                    </button>
 | 
						|
                </td>
 | 
						|
            </template>
 | 
						|
        </a-rows>
 | 
						|
        <div class="a-formset-footer flex-row">
 | 
						|
            <div class="flex-grow-1 flex-row">
 | 
						|
                <slot name="footer"/>
 | 
						|
            </div>
 | 
						|
            <div class="flex-grow-1 align-right">
 | 
						|
                <button type="button" class="button square is-warning p-2"
 | 
						|
                        @click="reset()"
 | 
						|
                        :title="labels.discard_changes"
 | 
						|
                        :aria-label="labels.discard_changes"
 | 
						|
                        >
 | 
						|
                    <span class="icon"><i class="fa fa-rotate" /></span>
 | 
						|
                </button>
 | 
						|
                <button type="button" class="button square is-primary p-2"
 | 
						|
                        @click="onActionAdd"
 | 
						|
                        :title="labels.add_item"
 | 
						|
                        :aria-label="labels.add_item"
 | 
						|
                        >
 | 
						|
                    <span class="icon">
 | 
						|
                        <i class="fa fa-plus"/></span>
 | 
						|
                </button>
 | 
						|
            </div>
 | 
						|
        </div>
 | 
						|
    </div>
 | 
						|
</template>
 | 
						|
<script>
 | 
						|
    import {cloneDeep} from 'lodash'
 | 
						|
    import Model, {Set} from '../model'
 | 
						|
 | 
						|
    import ARows from './ARows'
 | 
						|
 | 
						|
    export default {
 | 
						|
        emit: ['cell', 'move', 'colmove', 'load'],
 | 
						|
        components: {ARows},
 | 
						|
 | 
						|
        props: {
 | 
						|
            labels: Object,
 | 
						|
 | 
						|
            //! If provided call this function instead of adding an item to rows on "+" button click.
 | 
						|
            actionAdd: Function,
 | 
						|
            actionRemove: Function,
 | 
						|
 | 
						|
            //! If True, columns can be reordered
 | 
						|
            columnsOrderable: Boolean,
 | 
						|
            //! Field name used for ordering
 | 
						|
            orderBy: String,
 | 
						|
 | 
						|
            //! Formset data as returned by get_formset_data
 | 
						|
            formData: Object,
 | 
						|
            //! Model class used for item's set
 | 
						|
            model: {type: Function, default: Model},
 | 
						|
        },
 | 
						|
 | 
						|
        data() {
 | 
						|
            return {
 | 
						|
                set: new Set(Model),
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        computed: {
 | 
						|
            // ---- fields
 | 
						|
            _prefix() { return this.formData.prefix ? this.formData.prefix + '-' : '' },
 | 
						|
            fields() { return this.formData.fields },
 | 
						|
            orderField() { return this.orderBy && this.fields.find(f => f.name == this.orderBy) },
 | 
						|
            orderable() { return !!this.orderField },
 | 
						|
 | 
						|
            hiddenFields() { return this.fields.filter(f => f.hidden && !(this.orderable && f == this.orderField)) },
 | 
						|
            visibleFields() { return this.fields.filter(f => !f.hidden) },
 | 
						|
 | 
						|
            fieldSlots() { return this.visibleFields.reduce(
 | 
						|
                (slots, f) => ({...slots, ['row-' + f.name]: f}),
 | 
						|
                {}
 | 
						|
            )},
 | 
						|
 | 
						|
            items() { return this.set.items },
 | 
						|
            rows() { return this.$refs.rows },
 | 
						|
        },
 | 
						|
 | 
						|
        methods: {
 | 
						|
            onCellEvent(event) { this.$emit('cell', event) },
 | 
						|
            onColumnMove(event) { this.$emit('colmove', event) },
 | 
						|
            onActionAdd() {
 | 
						|
                if(this.actionAdd)
 | 
						|
                    return this.actionAdd(this)
 | 
						|
                this.set.push()
 | 
						|
            },
 | 
						|
 | 
						|
            moveItem(event) {
 | 
						|
                const {from, to} = event
 | 
						|
                const set_ = event.set || this.set
 | 
						|
                set_.move(from, to);
 | 
						|
                this.$emit('move', {...event, seŧ: set_})
 | 
						|
            },
 | 
						|
 | 
						|
            removeItem(row, item) {
 | 
						|
                if(this.actionRemove) {
 | 
						|
                    this.actionRemove(row, item);
 | 
						|
                    return
 | 
						|
                }
 | 
						|
                this.items.splice(row,1)
 | 
						|
            },
 | 
						|
 | 
						|
            //! Load items into set
 | 
						|
            load(items=[], reset=false) {
 | 
						|
                if(reset)
 | 
						|
                    this.set.items = []
 | 
						|
                for(var item of items)
 | 
						|
                    this.set.push(cloneDeep(item))
 | 
						|
                this.$emit('load', items)
 | 
						|
            },
 | 
						|
 | 
						|
            //! Reset forms to initials
 | 
						|
            reset() {
 | 
						|
                this.load(this.formData?.initials || [], true)
 | 
						|
            },
 | 
						|
        },
 | 
						|
 | 
						|
        mounted() {
 | 
						|
            this.reset()
 | 
						|
        }
 | 
						|
    }
 | 
						|
</script>
 |