/**
* @module nyc/Choice
*/
import $ from 'jquery'
import nyc from 'nyc'
import Container from 'nyc/Container'
/**
* @desc Class for creating checkbox and radio input widgets
* @public
* @class
* @extends {module:nyc/Container~Container}
* @fires module:nyc/Choice~Choice#change
*/
class Choice extends Container {
/**
* @desc Create an instance of Choice
* @public
* @constructor
* @param {module:nyc/Choice~Choice.Options} options Choice options
*/
constructor(options) {
super(options.target)
this.getContainer().addClass('chc rad-all')
/**
* @public
* @member {boolean}
*/
this.radio = options.radio
/**
* @private
* @member {Array<JQuery>}
*/
this.inputs = null
/**
* @private
* @member {Array<module:nyc/Choice~Choice.Choice>}
*/
this.choices = options.choices
this.setChoices(this.choices)
}
/**
* @desc Set the available choices
* @protected
* @method
* @returns {JQuery} The container
*/
createContainer() {
return $(Choice.HTML)
}
/**
* @desc Set the available choices
* @public
* @method
* @param {Array<module:nyc/Choice~Choice.Choice>} choices The choices
*/
setChoices(choices) {
this.choices = choices
let type = 'checkbox'
if (this.radio) {
this.getContainer().attr('role', 'radiogroup')
type = 'radio'
} else {
this.getContainer().attr('role', 'group')
}
this.getContainer().empty()
choices.forEach((choice, i) => {
const div = this.createContainer()
const id = nyc.nextId('chc-chc')
const input = div.find('input')
div.addClass(this.radio ? `${choice.name}-${i}` : choice.name)
input.attr({
id: id,
name: choice.name,
type: type,
role: type,
'aria-checked': choice.checked === true
})
.prop('checked', choice.checked === true)
.data('choice', choice)
.change($.proxy(this.change, this))
div.find('label').html(choice.label).attr('for', id)
this.iconHtml(div, choice)
this.append(div)
this.extend(choice)
})
this.inputs = this.find('input')
}
/**
* @private
* @desc Create HTML for icon
* @method
* @param {jQuery} div The label for the choice
* @param {module:nyc/Choice~Choice.Choice} choice The choice
*/
iconHtml(div, choice) {
if (choice.icon) {
const inputCell = div.find('td.input')
const css = choice.values.join('_').replace(/[^A-Za-z0-9\s|^_]/g, '').replace(/\s+/g, '-').toLowerCase()
$(`<td class="ico chc-${css}"><div></div></td>`).insertAfter(inputCell)
}
}
/**
* @desc Get or set the seleced choices
* @public
* @method
* @param {Array<module:nyc/Choice~Choice.Choice>} choices The choices
* @return {Array} Chosen options
*/
val(choices) {
if (choices) {
choices.forEach(choice => {
this.extend(choice)
})
$.each(this.inputs, (_, input) => {
$(input).prop('checked', false)
choices.some(chosen => {
const choice = $(input).data('choice')
if (chosen.eq(choice)) {
$(input).prop('checked', true)
return true
}
})
})
return this.val()
} else {
const chosen = []
$.each(this.inputs, (_, input) => {
if ($(input).prop('checked')) {
chosen.push($(input).data('choice'))
}
})
return chosen
}
}
/**
* @private
* @method
* @param {jQuery.Event} event Event object
*/
change(event) {
$.each(this.inputs, (_, input) => {
$(input).attr('aria-checked', $(input).prop('checked'))
})
this.trigger('change', this)
}
/**
* @private
* @method
* @param {module:nyc/Choice~Choice.Choice} choice Choice
*/
extend(choice) {
$.extend(choice, {
eq(another) {
return this.name === another.name &&
this.label === another.label &&
JSON.stringify(this.value) === JSON.stringify(another.value)
}
})
}
}
/**
* @desc A choice for {@link module:nyc/Choice~Choice}
* @public
* @typedef {Object}
* @property {string} name The name for the choice
* @property {string} label The label for the choice
* @property {Array<Object>} value The value of the choice
* @property {boolean} [checked=false] The value of the checked state of the choice
* @property {boolean} [icon=false] The value of the icon state of the choice
*/
Choice.Choice
/**
* @desc Constructor options for {@link module:nyc/Choice~Choice}
* @public
* @typedef {Object}
* @property {jQuery|Element|string} target The target DOM node for creating the choice control
* @property {Array<module:nyc/Choice~Choice.Choice>} choices The choices
* @property {boolean} [radio=false] Checkbox or radio button
*/
Choice.Options
/**
* @desc The change event
* @event module:nyc/Choice~Choice#change
* @type {module:nyc/Choice~Choice}
*/
/**
* @private
* @const
* @type {string}
*/
Choice.HTML = '<div class="chc-chc"><table><tbody><tr><td class="input"><input></td><td><label></label></td></tr></tbody></table></div>'
export default Choice