UNPKG

samagra-x-enketo-core

Version:

Extensible Enketo form engine

135 lines (115 loc) 3.82 kB
import Widget from '../../js/widget'; import { isNumber } from '../../js/utils'; import events from '../../js/event'; /** * @augments RangeWidget */ class RatingWidget extends Widget { /** * @type {string} */ static get selector() { return '.or-appearance-rating input[type="number"]'; } _init() { const fragment = document.createRange().createContextualFragment( this._getHtmlStr() ); this.element.after( fragment ); this.element.classList.add( 'hide' ); this.widget = this.question.querySelector( '.widget' ); let ratingStars = '', name = Math.random().toString( 36 ).substring( 2, 15 ); for ( let i = this.props.min; i <= this.props.max; i += this.props.step ) { ratingStars += `<input type=radio name="rating-stars__${name}" class="rating-widget__rating__star ignore" value="${i}"/>`; } this.widget.querySelector( '.rating-widget__rating' ) .append( document.createRange().createContextualFragment( ratingStars ) ); this.rating = this.widget.querySelector( '.rating-widget__rating' ); this.stars = this.rating.querySelectorAll( '.rating-widget__rating__star' ); this.stars.forEach( el => { el.addEventListener( 'change', () => { const selected = this.rating.querySelector( 'input:checked' ); // contains class 'empty' means first load if ( ( this.value != selected.value || this.rating.classList.contains( 'empty' ) ) ) { this.value = selected.value; } } ); } ); // loads the default value if exists this.update(); if ( this.props.readonly ) { this.disable(); } } /** * This is separated so it can be extended (in the analog-scale widget) * * @return {string} HTML string */ _getHtmlStr() { return `<div class="widget rating-widget"> <div class="rating-widget__rating empty"></div> </div>`; } /** * Disables widget */ disable() { this.stars.forEach( el => el.disabled = true ); } /** * Enables widget */ enable() { this.stars.forEach( el => el.disabled = false ); } /** * Updates widget */ update() { const value = this.element.value; if ( isNumber( value ) ) { this.stars.forEach( ( star ) => { if ( star.value === value ) { star.checked = true; star.dispatchEvent( events.Change() ); } } ); } else { this._reset(); } } /** * Resets widget */ _reset() { const selected = this.rating.querySelector( 'input:checked' ); if ( selected ) { this.value = ''; selected.checked = false; } } /** * @type {object} */ get props() { const props = this._props; const min = isNumber( this.element.getAttribute( 'min' ) ) ? this.element.getAttribute( 'min' ) : 0; const max = isNumber( this.element.getAttribute( 'max' ) ) ? this.element.getAttribute( 'max' ) : 10; const step = isNumber( this.element.getAttribute( 'step' ) ) ? this.element.getAttribute( 'step' ) : 1; props.min = Number( min ); props.max = Number( max ); props.step = Number( step ); return props; } /** * @type {string} */ get value() { return this.originalInputValue; } set value( value ) { this.originalInputValue = value; this.rating.classList.toggle( 'empty', value === '' ); } } export default RatingWidget;