Home Reference Source Repository

js/components/form/base-field.js

import log from 'logger';
import $ from 'jquery';
import u from 'utils';
import Vue from 'vue';

/**
 * Base inheritable properties reusable by nested components
 */
export const FieldComponentMixin = {
    props: {
        field: {
            type: Object,
            default: function(){ return {};},
            required: true
        },
        model: Object,
        value: null,  // Means any type
        description: null,
        property: Object,
        required: Boolean,
        placeholder: String
    }
};

/**
 * Common form fields behaviors
 */
export const BaseField = {
    name: 'base-field',
    replace: true,
    data: function() {
        return {
            errors: []
        };
    },
    components: {
        // Only register the common components
        'text-input': require('components/form/text-input.vue'),
        'hidden-input': require('components/form/hidden-input.vue'),
        'select-input': require('components/form/select-input.vue'),
        'markdown-editor': require('components/form/markdown-editor.vue'),
        'date-picker': require('components/form/date-picker.vue'),
        'checkbox': require('components/form/checkbox.vue')
    },
    props: {
        field: {
            type: Object,
            default: function(){ return {};},
            required: true
        },
        model: {
            type: Object,
            default: function(){ return {};},
            required: true
        },
        schema: {
            type: Object,
            default: function(){ return {};},
            required: true
        }
    },
    computed: {
        description: function() {
            let property = this.property;
            return property && property.hasOwnProperty('description')
                ? property.description
                : undefined;
        },
        property: function() {
            if (!this.schema.properties.hasOwnProperty(this.field.id)) {
                log.warn('Field "' + this.field.id + '" not found in schema');
                return {};
            }

            return this.schema.properties[this.field.id];
        },
        required: function() {
            if (!this.field || !this.schema.hasOwnProperty('required')) {
                return false;
            }
            return this.schema.required.indexOf(this.field.id) >= 0;
        },
        is_bool: function() {
            return this.property && this.property.type === 'boolean';
        },
        is_hidden: function() {
            return this.field && this.field.type === 'hidden';
        },
        value: function() {
            let value = '';
            if (this.model && this.field) {
                value = u.getattr(this.model, this.field.id);
                if (!value && this.property && this.property.hasOwnProperty('default')) {
                    value = this.property.default;
                }
            }
            return value || '';
        },
        placeholder: function() {
            return this.field.placeholder || this.field.label || '';
        },
        widget: function() {
            let widget;
            if (this.field.widget) {
                widget = this.field.widget;
            } else if (this.property.type == 'boolean') {
                widget = 'checkbox';
            } else if (this.property.type == 'string') {
                if (this.property.format === 'markdown') {
                    widget = 'markdown-editor';
                } else if (this.property.enum) {
                    widget = 'select-input';
                }
            }
            widget = widget || 'text-input';

            // Lazy load component if needed
            if (!this.$options.components.hasOwnProperty(widget)) {
                this.$options.components[widget] = function(resolve, reject) {
                    require(['./' + widget + '.vue'], resolve);
                };
            }
            return widget;
        }
    },
    ready: function() {
        // Form help messages as popover on info sign
        $(this.$el).find('.form-help').popover({
            placement: 'left',
            trigger: 'hover',
            container: 'body',
            html: true
        });
    }
};

export default BaseField;