constructor(config, preview) {
    this.rawConfig = jQuery.extend({}, config)

    // make a copy of config so we don't change the object reference
    config = jQuery.extend({}, config)
    this.preview = preview
    delete config.isPreview
    if (this.preview) {
      delete config.required
    }

    // process config - extract standard properties
    const properties = ['label', 'description', 'subtype', 'required', 'disabled']
    for (const prop of properties) {
      this[prop] = config[prop]
      delete config[prop]
    }

    // default fields
    if (!config.id) {
      if (config.name) {
        config.id = config.name
      } else {
        config.id = 'control-' + Math.floor(Math.random() * 10000000 + 1)
      }
    }
    this.id = config.id
    this.type = config.type
    if (this.description) {
      config.title = this.description
    }

    // check for global class configuration
    if (!control.controlConfig) {
      control.controlConfig = {}
    }
    const classId = this.subtype ? this.type + '.' + this.subtype : this.type
    this.classConfig = jQuery.extend({}, control.controlConfig[this.type] || {}, control.controlConfig[classId] || {})

    // if subtype, update the config type for injecting into DOM elements
    if (this.subtype) {
      config.type = this.subtype
    }

    if (this.required) {
      config['required'] = 'required'
      config['aria-required'] = 'true'
    }

    // Allow setting disabled flag
    if (this.disabled) {
      config['disabled'] = 'disabled'
    }
    this.config = config
    this.configure()
  }
initialise the control object
@param {Object} config each control class receives a control configuration
object ({name, label, etc})
@param {Boolean} preview isPreview