UNPKG

samagra-x-enketo-core

Version:

Extensible Enketo form engine

184 lines (155 loc) 5.35 kB
import $ from 'jquery'; import Widget from '../../js/widget'; import support from '../../js/support'; import events from '../../js/event'; import sortable from 'html5sortable/dist/html5sortable.cjs'; import { t } from 'enketo/translator'; /** * @augments Widget */ class RankWidget extends Widget { /** * @type {string} */ static get selector() { return '.question input.rank'; } /** * @type {boolean} */ static get list() { return true; } _init() { const that = this; const loadedValue = this.originalInputValue; const startTextKey = support.touch ? 'rankwidget.tapstart' : 'rankwidget.clickstart'; this.itemSelector = 'label:not(.itemset-template)'; this.list = $( this.element ).next( '.option-wrapper' ).addClass( 'widget rank-widget' )[ 0 ]; $( this.list ) .toggleClass( 'rank-widget--empty', !loadedValue ) .append( this.resetButtonHtml ) .append( `<div class="rank-widget__overlay"><span class="rank-widget__overlay__content" data-i18n="${startTextKey}">${support.touch ? t( 'rankwidget.tapstart' ) : t( 'rankwidget.clickstart' )}</span></div>` ) .on( 'click', function() { if ( !that.element.disabled ) { this.classList.remove( 'rank-widget--empty' ); that.originalInputValue = that.value; that.element.dispatchEvent( events.FakeFocus() ); } } ); this.list.querySelector( '.btn-reset' ).addEventListener( 'click', ( evt ) => { this._reset(); evt.stopPropagation(); } ); this.element.classList.add( 'hide' ); this.value = loadedValue; // Create the sortable drag-and-drop functionality sortable( this.list, { items: this.itemSelector, //hoverClass: 'rank-widget__item--hover', containerSerializer( container ) { return { value: [].slice.call( container.node.querySelectorAll( `${that.itemSelector} input` ) ).map( input => input.value ).join( ' ' ) }; } } )[ 0 ].addEventListener( 'sortupdate', () => { this.originalInputValue = this.value; this.element.dispatchEvent( events.FakeFocus() ); } ); if ( this.props.readonly ) { this.disable(); } } /** * Resets widget */ _reset() { this.originalInputValue = ''; } /** * @type {string} */ get value() { const result = sortable( this.list, 'serialize' ); return result[ 0 ].container.value; } set value( value ) { if ( !value ) { this._reset(); } else { const that = this; const values = value.split( ' ' ); const items = [ ...this.list.querySelectorAll( `${this.itemSelector} input` ) ]; // Basic error check if ( values.length !== items.length ) { throw new Error( 'Could not load rank widget value. Number of items mismatch.' ); } // Don't even attempt to rectify a mismatch between the value and the available items. items.sort( ( a, b ) => { const aIndex = values.indexOf( a.value ); const bIndex = values.indexOf( b.value ); if ( aIndex === -1 || bIndex === -1 ) { throw new Error( 'Could not load rank widget value. Mismatch in item values.' ); } return aIndex - bIndex; } ); items.forEach( item => { $( that.list ).find( '.btn-reset' ).before( $( item.parentNode ).detach() ); } ); } } /** * Disables widget */ disable() { $( this.element ) .prop( 'disabled', true ) .next( '.widget' ) .find( 'input, button' ) .prop( 'disabled', true ); sortable( this.list, 'disable' ); } /** * Enables widget */ enable() { $( this.element ) .prop( 'disabled', false ) .next( '.widget' ) .find( 'input, button' ) .prop( 'disabled', false ); sortable( this.list, 'enable' ); } /** * Updates widget */ update() { const value = this.element.value; // re-initalize sortable because the options may have changed sortable( this.list ); if ( value ) { this.value = value; this.originalInputValue = value; } else { this._reset(); } } // Since we're overriding the setter we also have to overwrite the getter // https://stackoverflow.com/questions/28950760/override-a-setter-and-the-getter-must-also-be-overridden /** * @type {string} */ get originalInputValue() { return super.originalInputValue; } /** * This is the input that Enketo's engine listens on. * * @type {string} */ set originalInputValue( value ) { super.originalInputValue = value; this.list.classList.toggle( 'rank-widget--empty', !value ); } } export default RankWidget;